Skip to content

Commit

Permalink
feat(chromium): roll to Chromium 97.0.4692.0 (r938248)
Browse files Browse the repository at this point in the history
Issues: #7458
  • Loading branch information
OrKoN committed Nov 11, 2021
1 parent 51e6169 commit 4979b44
Show file tree
Hide file tree
Showing 9 changed files with 248 additions and 27 deletions.
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -59,7 +59,7 @@
"license": "Apache-2.0",
"dependencies": {
"debug": "4.3.2",
"devtools-protocol": "0.0.901419",
"devtools-protocol": "0.0.937139",
"extract-zip": "2.0.1",
"https-proxy-agent": "5.0.0",
"node-fetch": "2.6.5",
Expand Down
2 changes: 1 addition & 1 deletion src/common/FrameManager.ts
Expand Up @@ -449,7 +449,7 @@ export class FrameManager extends EventEmitter {
}
}
const context = new ExecutionContext(
frame._client || this._client,
frame?._client || this._client,
contextPayload,
world
);
Expand Down
13 changes: 9 additions & 4 deletions src/common/HTTPResponse.ts
Expand Up @@ -55,7 +55,8 @@ export class HTTPResponse {
constructor(
client: CDPSession,
request: HTTPRequest,
responsePayload: Protocol.Network.Response
responsePayload: Protocol.Network.Response,
extraInfo: Protocol.Network.ResponseReceivedExtraInfoEvent | null
) {
this._client = client;
this._request = request;
Expand All @@ -68,13 +69,17 @@ export class HTTPResponse {
ip: responsePayload.remoteIPAddress,
port: responsePayload.remotePort,
};
this._status = responsePayload.status;
// TODO extract statusText from extraInfo.headersText instead if present
this._statusText = responsePayload.statusText;
this._url = request.url();
this._fromDiskCache = !!responsePayload.fromDiskCache;
this._fromServiceWorker = !!responsePayload.fromServiceWorker;
for (const key of Object.keys(responsePayload.headers))
this._headers[key.toLowerCase()] = responsePayload.headers[key];

this._status = extraInfo ? extraInfo.statusCode : responsePayload.status;
const headers = extraInfo ? extraInfo.headers : responsePayload.headers;
for (const key of Object.keys(headers))
this._headers[key.toLowerCase()] = headers[key];

this._securityDetails = responsePayload.securityDetails
? new SecurityDetails(responsePayload.securityDetails)
: null;
Expand Down
167 changes: 148 additions & 19 deletions src/common/NetworkManager.ts
Expand Up @@ -110,6 +110,31 @@ export class NetworkManager extends EventEmitter {
>();
_requestIdToRequest = new Map<string, HTTPRequest>();

/*
* The below maps are used to reconcile Network.responseReceivedExtraInfo
* events with their corresponding request. Each response and redirect
* response gets an ExtraInfo event, and we don't know which will come first.
* This means that we have to store a Response or an ExtraInfo for each
* response, and emit the event when we get both of them. In addition, to
* handle redirects, we have to make them Arrays to represent the chain of
* events.
*/
_requestIdToResponseReceivedExtraInfo = new Map<
string,
Protocol.Network.ResponseReceivedExtraInfoEvent[]
>();
_requestIdToResponseReceived = new Map<
string,
Protocol.Network.ResponseReceivedEvent
>();
_requestIdToRedirectInfoMap = new Map<
string,
Array<{
request: HTTPRequest;
response: Protocol.Network.Response;
}>
>();

_extraHTTPHeaders: Record<string, string> = {};
_credentials?: Credentials = null;
_attemptedAuthentications = new Set<string>();
Expand Down Expand Up @@ -152,6 +177,10 @@ export class NetworkManager extends EventEmitter {
this._onLoadingFinished.bind(this)
);
this._client.on('Network.loadingFailed', this._onLoadingFailed.bind(this));
this._client.on(
'Network.responseReceivedExtraInfo',
this._onResponseReceivedExtraInfo.bind(this)
);
}

async initialize(): Promise<void> {
Expand Down Expand Up @@ -361,18 +390,82 @@ export class NetworkManager extends EventEmitter {
}
}

_requestIdToRedirectInfo(requestId: string): Array<{
request: HTTPRequest;
response: Protocol.Network.Response;
}> {
if (!this._requestIdToRedirectInfoMap.has(requestId)) {
this._requestIdToRedirectInfoMap.set(requestId, []);
}
return this._requestIdToRedirectInfoMap.get(requestId);
}

_requestIdToResponseExtraInfo(
requestId: string
): Protocol.Network.ResponseReceivedExtraInfoEvent[] {
if (!this._requestIdToResponseReceivedExtraInfo.has(requestId)) {
this._requestIdToResponseReceivedExtraInfo.set(requestId, []);
}
return this._requestIdToResponseReceivedExtraInfo.get(requestId);
}

_emitRedirectResponse(
request: HTTPRequest,
responsePayload: Protocol.Network.Response,
extraInfo: Protocol.Network.ResponseReceivedExtraInfoEvent
): void {
const response = new HTTPResponse(
this._client,
request,
responsePayload,
extraInfo
);
request._response = response;
request._redirectChain.push(request);
response._resolveBody(
new Error('Response body is unavailable for redirect responses')
);
this._forgetRequest(request, false);
this.emit(NetworkManagerEmittedEvents.Response, response);
this.emit(NetworkManagerEmittedEvents.RequestFinished, request);
}

_handleRequestWithRedirect(
event: Protocol.Network.RequestWillBeSentEvent
): void {
const lastRequest = this._requestIdToRequest.get(event.requestId);
// If we connect late to the target, we could have missed the
// requestWillBeSent event.
if (!lastRequest) return;

let extraInfo = null;
if (event.redirectHasExtraInfo) {
extraInfo = this._requestIdToResponseExtraInfo(event.requestId).shift();
if (!extraInfo) {
// Wait for the corresponding ExtraInfo event before emitting the response.
this._requestIdToRedirectInfo(event.requestId).push({
request: lastRequest,
response: event.redirectResponse,
});
return;
}
}

this._emitRedirectResponse(lastRequest, event.redirectResponse, null);
}

_onRequest(
event: Protocol.Network.RequestWillBeSentEvent,
interceptionId?: string
): void {
let redirectChain = [];
if (event.redirectResponse) {
const request = this._requestIdToRequest.get(event.requestId);
const lastRequest = this._requestIdToRequest.get(event.requestId);
// If we connect late to the target, we could have missed the
// requestWillBeSent event.
if (request) {
this._handleRequestRedirect(request, event.redirectResponse);
redirectChain = request._redirectChain;
if (lastRequest) {
this._handleRequestWithRedirect(event);
redirectChain = lastRequest._redirectChain;
}
}
const frame = event.frameId
Expand All @@ -399,28 +492,61 @@ export class NetworkManager extends EventEmitter {
this.emit(NetworkManagerEmittedEvents.RequestServedFromCache, request);
}

_handleRequestRedirect(
request: HTTPRequest,
responsePayload: Protocol.Network.Response
_emitResponseEvent(
responseReceived: Protocol.Network.ResponseReceivedEvent,
extraInfo: Protocol.Network.ResponseReceivedExtraInfoEvent
): void {
const response = new HTTPResponse(this._client, request, responsePayload);
request._response = response;
request._redirectChain.push(request);
response._resolveBody(
new Error('Response body is unavailable for redirect responses')
const request = this._requestIdToRequest.get(responseReceived.requestId);
// FileUpload sends a response without a matching request.
if (!request) return;

const response = new HTTPResponse(
this._client,
request,
responseReceived.response,
extraInfo
);
this._forgetRequest(request, false);
request._response = response;
this.emit(NetworkManagerEmittedEvents.Response, response);
this.emit(NetworkManagerEmittedEvents.RequestFinished, request);
}

_onResponseReceived(event: Protocol.Network.ResponseReceivedEvent): void {
const request = this._requestIdToRequest.get(event.requestId);
// FileUpload sends a response without a matching request.
if (!request) return;
const response = new HTTPResponse(this._client, request, event.response);
request._response = response;
this.emit(NetworkManagerEmittedEvents.Response, response);
let extraInfo = null;
if (request && !request._fromMemoryCache && event.hasExtraInfo) {
extraInfo = this._requestIdToResponseExtraInfo(event.requestId).shift();
if (!extraInfo) {
// Wait until we get the corresponding ExtraInfo event.
this._requestIdToResponseReceived.set(event.requestId, event);
return;
}
}
this._emitResponseEvent(event, extraInfo);
}

_onResponseReceivedExtraInfo(
event: Protocol.Network.ResponseReceivedExtraInfoEvent
): void {
const redirectInfo = this._requestIdToRedirectInfo(event.requestId).shift();
if (redirectInfo) {
this._emitRedirectResponse(
redirectInfo.request,
redirectInfo.response,
event
);
return;
}

const responseReceived = this._requestIdToResponseReceived.get(
event.requestId
);
if (responseReceived) {
this._emitResponseEvent(responseReceived, event);
return;
}

// Wait until we get a corresponding response event.
this._requestIdToResponseExtraInfo(event.requestId).push(event);
}

_forgetRequest(request: HTTPRequest, events: boolean): void {
Expand All @@ -433,6 +559,9 @@ export class NetworkManager extends EventEmitter {
if (events) {
this._requestIdToRequestWillBeSentEvent.delete(requestId);
this._requestIdToRequestPausedEvent.delete(requestId);
this._requestIdToResponseReceived.delete(requestId);
this._requestIdToResponseReceivedExtraInfo.delete(requestId);
this._requestIdToRedirectInfoMap.delete(requestId);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/revisions.ts
Expand Up @@ -20,6 +20,6 @@ type Revisions = Readonly<{
}>;

export const PUPPETEER_REVISIONS: Revisions = {
chromium: '901912',
chromium: '938248',
firefox: 'latest',
};
3 changes: 2 additions & 1 deletion test/accessibility.spec.ts
Expand Up @@ -168,7 +168,8 @@ describeFailsFirefox('Accessibility', function () {
'<div tabIndex=-1 aria-roledescription="foo">Hi</div>'
);
const snapshot = await page.accessibility.snapshot();
expect(snapshot.children[0].roledescription).toEqual('foo');
// See https://chromium-review.googlesource.com/c/chromium/src/+/3088862
expect(snapshot.children[0].roledescription).toEqual(undefined);
});
it('orientation', async () => {
const { page } = getTestState();
Expand Down
6 changes: 6 additions & 0 deletions test/jshandle.spec.ts
Expand Up @@ -390,6 +390,12 @@ describe('JSHandle', function () {
y: 15,
},
});
for (let i = 0; i < 3; i++) {
if (clicks.length >= 2) {
break;
}
await new Promise((resolve) => setTimeout(resolve, 100));
}
expect(clicks).toEqual([
[45 + 60, 45 + 30], // margin + middle point offset
[30 + 10, 30 + 15], // margin + offset
Expand Down
79 changes: 79 additions & 0 deletions test/network.spec.ts
Expand Up @@ -529,6 +529,12 @@ describe('network', function () {
server.setRedirect('/foo.html', '/empty.html');
const FOO_URL = server.PREFIX + '/foo.html';
const response = await page.goto(FOO_URL);
for (let i = 0; i < 3; i++) {
if (events.length >= 6) {
break;
}
await new Promise((resolve) => setTimeout(resolve, 100));
}
expect(events).toEqual([
`GET ${FOO_URL}`,
`302 ${FOO_URL}`,
Expand Down Expand Up @@ -686,4 +692,77 @@ describe('network', function () {
expect(responses.get('one-style.html').fromCache()).toBe(false);
});
});

describeFailsFirefox('raw network headers', async () => {
it('Same-origin set-cookie navigation', async () => {
const { page, server } = getTestState();

const setCookieString = 'foo=bar';
server.setRoute('/empty.html', (req, res) => {
res.setHeader('set-cookie', setCookieString);
res.end('hello world');
});
const response = await page.goto(server.EMPTY_PAGE);
expect(response.headers()['set-cookie']).toBe(setCookieString);
});

it('Same-origin set-cookie subresource', async () => {
const { page, server } = getTestState();
await page.goto(server.EMPTY_PAGE);

const setCookieString = 'foo=bar';
server.setRoute('/foo', (req, res) => {
res.setHeader('set-cookie', setCookieString);
res.end('hello world');
});

const responsePromise = new Promise<HTTPResponse>((resolve) =>
page.on('response', (response) => resolve(response))
);
page.evaluate(() => {
const xhr = new XMLHttpRequest();
xhr.open('GET', '/foo');
xhr.send();
});
const subresourceResponse = await responsePromise;
expect(subresourceResponse.headers()['set-cookie']).toBe(setCookieString);
});

it('Cross-origin set-cookie', async () => {
const { httpsServer, puppeteer, defaultBrowserOptions } = getTestState();

const browser = await puppeteer.launch({
...defaultBrowserOptions,
ignoreHTTPSErrors: true,
});

const page = await browser.newPage();

try {
await page.goto(httpsServer.PREFIX + '/empty.html');

const setCookieString = 'hello=world';
httpsServer.setRoute('/setcookie.html', (req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('set-cookie', setCookieString);
res.end();
});
await page.goto(httpsServer.PREFIX + '/setcookie.html');

const response = await new Promise<HTTPResponse>((resolve) => {
page.on('response', resolve);
const url = httpsServer.CROSS_PROCESS_PREFIX + '/setcookie.html';
page.evaluate<(src: string) => void>((src) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', src);
xhr.send();
}, url);
});
expect(response.headers()['set-cookie']).toBe(setCookieString);
} finally {
await page.close();
await browser.close();
}
});
});
});
1 change: 1 addition & 0 deletions versions.js
Expand Up @@ -17,6 +17,7 @@
const versionsPerRelease = new Map([
// This is a mapping from Chromium version => Puppeteer version.
// In Chromium roll patches, use 'NEXT' for the Puppeteer version.
['97.0.4692.0', 'NEXT'],
['93.0.4577.0', 'v10.2.0'],
['92.0.4512.0', 'v10.0.0'],
['91.0.4469.0', 'v9.0.0'],
Expand Down

0 comments on commit 4979b44

Please sign in to comment.