Skip to content

Commit

Permalink
Address comments
Browse files Browse the repository at this point in the history
  • Loading branch information
yury-s committed Dec 4, 2023
1 parent 56ebe9c commit a8ee3ea
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ export class WKInterceptableRequest {
readonly _requestId: string;
_timestamp: number;
_wallTime: number;
_willBeIntercepted = false;

constructor(session: WKSession, frame: frames.Frame, event: Protocol.Network.requestWillBeSentPayload, redirectedFrom: WKInterceptableRequest | null, documentId: string | undefined) {
this._session = session;
Expand Down
79 changes: 45 additions & 34 deletions packages/playwright-core/src/server/webkit/wkPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export class WKPage implements PageDelegate {
private readonly _pageProxySession: WKSession;
readonly _opener: WKPage | null;
private readonly _requestIdToRequest = new Map<string, WKInterceptableRequest>();
private readonly _requestIdToRequestWillBeSentEvent = new Map<string, Protocol.Network.requestWillBeSentPayload>();
private readonly _workers: WKWorkers;
private readonly _contextIdToContext: Map<number, dom.FrameExecutionContext>;
private _sessionListeners: RegisteredListener[] = [];
Expand Down Expand Up @@ -388,9 +389,9 @@ export class WKPage implements PageDelegate {
eventsHelper.addEventListener(this._session, 'Page.fileChooserOpened', event => this._onFileChooserOpened(event)),
eventsHelper.addEventListener(this._session, 'Network.requestWillBeSent', e => this._onRequestWillBeSent(this._session, e)),
eventsHelper.addEventListener(this._session, 'Network.requestIntercepted', e => this._onRequestIntercepted(this._session, e)),
eventsHelper.addEventListener(this._session, 'Network.responseReceived', e => this._onResponseReceived(e)),
eventsHelper.addEventListener(this._session, 'Network.responseReceived', e => this._onResponseReceived(this._session, e)),
eventsHelper.addEventListener(this._session, 'Network.loadingFinished', e => this._onLoadingFinished(e)),
eventsHelper.addEventListener(this._session, 'Network.loadingFailed', e => this._onLoadingFailed(e)),
eventsHelper.addEventListener(this._session, 'Network.loadingFailed', e => this._onLoadingFailed(this._session, e)),
eventsHelper.addEventListener(this._session, 'Network.webSocketCreated', e => this._page._frameManager.onWebSocketCreated(e.requestId, e.url)),
eventsHelper.addEventListener(this._session, 'Network.webSocketWillSendHandshakeRequest', e => this._page._frameManager.onWebSocketRequest(e.requestId)),
eventsHelper.addEventListener(this._session, 'Network.webSocketHandshakeResponseReceived', e => this._page._frameManager.onWebSocketResponse(e.requestId, e.response.status, e.response.statusText)),
Expand Down Expand Up @@ -1011,6 +1012,15 @@ export class WKPage implements PageDelegate {
_onRequestWillBeSent(session: WKSession, event: Protocol.Network.requestWillBeSentPayload) {
if (event.request.url.startsWith('data:'))
return;

// We do not support intercepting redirects.
if (this._page.needsRequestInterception() && !event.redirectResponse)
this._requestIdToRequestWillBeSentEvent.set(event.requestId, event);
else
this._onRequest(session, event, false);
}

private _onRequest(session: WKSession, event: Protocol.Network.requestWillBeSentPayload, interceted: boolean) {
let redirectedFrom: WKInterceptableRequest | null = null;
if (event.redirectResponse) {
const request = this._requestIdToRequest.get(event.requestId);
Expand All @@ -1030,12 +1040,15 @@ export class WKPage implements PageDelegate {
const isNavigationRequest = event.type === 'Document';
const documentId = isNavigationRequest ? event.loaderId : undefined;
const request = new WKInterceptableRequest(session, frame, event, redirectedFrom, documentId);
// We do not support intercepting redirects.
if (this._page.needsRequestInterception() && !redirectedFrom)
request._willBeIntercepted = true;
let route;
if (interceted) {
route = new WKRouteImpl(session, request._requestId);
// There is no point in waiting for the raw headers in Network.responseReceived when intercepting.
// Use provisional headers as raw headers, so that client can call allHeaders() from the route handler.
request.request.setRawRequestHeaders(null);
}
this._requestIdToRequest.set(event.requestId, request);
if (!request._willBeIntercepted)
this._page._frameManager.requestStarted(request.request, undefined);
this._page._frameManager.requestStarted(request.request, route);
}

private _handleRequestRedirect(request: WKInterceptableRequest, responsePayload: Protocol.Network.Response, timestamp: number) {
Expand All @@ -1051,42 +1064,36 @@ export class WKPage implements PageDelegate {
}

_onRequestIntercepted(session: WKSession, event: Protocol.Network.requestInterceptedPayload) {
const request = this._requestIdToRequest.get(event.requestId);
if (!request) {
session.sendMayFail('Network.interceptRequestWithError', { errorType: 'Cancellation', requestId: event.requestId });
return;
}
// There is no point in waiting for the raw headers in Network.responseReceived when intercepting.
// Use provisional headers as raw headers, so that client can call allHeaders() from the route handler.
request.request.setRawRequestHeaders(null);
if (!request._willBeIntercepted) {
const requestWillBeSentEvent = this._requestIdToRequestWillBeSentEvent.get(event.requestId);
if (!requestWillBeSentEvent) {
// Intercepted, although we do not intend to allow interception.
// Just continue.
session.sendMayFail('Network.interceptWithRequest', { requestId: request._requestId });
} else {
const route = new WKRouteImpl(session, request._requestId);
request._willBeIntercepted = false;
this._page._frameManager.requestStarted(request.request, route);
session.sendMayFail('Network.interceptWithRequest', { requestId: event.requestId });
return;
}
this._requestIdToRequestWillBeSentEvent.delete(event.requestId);
this._onRequest(session, requestWillBeSentEvent, true);
}

_onResponseReceived(event: Protocol.Network.responseReceivedPayload) {
_onResponseReceived(session: WKSession, event: Protocol.Network.responseReceivedPayload) {
const requestWillBeSentEvent = this._requestIdToRequestWillBeSentEvent.get(event.requestId);
if (requestWillBeSentEvent) {
this._requestIdToRequestWillBeSentEvent.delete(event.requestId);
// We received a response, so the request won't be intercepted (e.g. it was handled by a
// service worker and we don't intercept service workers).
this._onRequest(session, requestWillBeSentEvent, false);
}
const request = this._requestIdToRequest.get(event.requestId);
// FileUpload sends a response without a matching request.
if (!request)
return;
if (request._willBeIntercepted) {
// We received a response, so the request won't be intercepted (e.g. it was handled by service
// worker and we don't intercept service workers).
request._willBeIntercepted = false;
this._page._frameManager.requestStarted(request.request, undefined);
}

this._requestIdToResponseReceivedPayloadEvent.set(request._requestId, event);
const response = request.createResponse(event.response);
this._page._frameManager.requestReceivedResponse(response);

if (response.status() === 204) {
this._onLoadingFailed({
this._onLoadingFailed(session, {
requestId: event.requestId,
errorText: 'Aborted: 204 No Content',
timestamp: event.timestamp
Expand Down Expand Up @@ -1129,17 +1136,21 @@ export class WKPage implements PageDelegate {
this._page._frameManager.reportRequestFinished(request.request, response);
}

_onLoadingFailed(event: Protocol.Network.loadingFailedPayload) {
_onLoadingFailed(session: WKSession, event: Protocol.Network.loadingFailedPayload) {
const requestWillBeSentEvent = this._requestIdToRequestWillBeSentEvent.get(event.requestId);
if (requestWillBeSentEvent) {
this._requestIdToRequestWillBeSentEvent.delete(event.requestId);
// We received a response, so the request won't be intercepted (e.g. it was handled by a
// service worker and we don't intercept service workers).
this._onRequest(session, requestWillBeSentEvent, false);
}

const request = this._requestIdToRequest.get(event.requestId);
// For certain requestIds we never receive requestWillBeSent event.
// @see https://crbug.com/750469
if (!request)
return;

if (request._willBeIntercepted) {
request._willBeIntercepted = false;
this._page._frameManager.requestStarted(request.request, undefined);
}
const response = request.request._existingResponse();
if (response) {
response._serverAddrFinished();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ export class WKProvisionalPage {
this._sessionListeners = [
eventsHelper.addEventListener(session, 'Network.requestWillBeSent', overrideFrameId(e => wkPage._onRequestWillBeSent(session, e))),
eventsHelper.addEventListener(session, 'Network.requestIntercepted', overrideFrameId(e => wkPage._onRequestIntercepted(session, e))),
eventsHelper.addEventListener(session, 'Network.responseReceived', overrideFrameId(e => wkPage._onResponseReceived(e))),
eventsHelper.addEventListener(session, 'Network.responseReceived', overrideFrameId(e => wkPage._onResponseReceived(session, e))),
eventsHelper.addEventListener(session, 'Network.loadingFinished', overrideFrameId(e => wkPage._onLoadingFinished(e))),
eventsHelper.addEventListener(session, 'Network.loadingFailed', overrideFrameId(e => wkPage._onLoadingFailed(e))),
eventsHelper.addEventListener(session, 'Network.loadingFailed', overrideFrameId(e => wkPage._onLoadingFailed(session, e))),
];

this.initializationPromise = this._wkPage._initializeSession(session, true, ({ frameTree }) => this._handleFrameTree(frameTree));
Expand Down
35 changes: 6 additions & 29 deletions tests/page/page-event-request.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,16 @@ it('should report requests and responses handled by service worker', async ({ pa
expect(await failedRequest.response()).toBe(null);
});

it('should report requests and responses handled by service worker with routing', async ({ page, server, isAndroid, isElectron, mode, platform }) => {
it('should report requests and responses handled by service worker with routing', async ({ page, server, isAndroid, isElectron, mode, browserName, platform }) => {
it.fixme(isAndroid);
it.fixme(isElectron);
it.fixme(mode.startsWith('service') && platform === 'linux', 'Times out for no clear reason');

await page.route('**/*', route => route.continue());
const interceptedUrls = [];
await page.route('**/*', route => {
interceptedUrls.push(route.request().url());
void route.continue();
});
await page.goto(server.PREFIX + '/serviceworkers/fetchdummy/sw.html');
await page.evaluate(() => window['activationPromise']);
const [swResponse, request] = await Promise.all([
Expand All @@ -96,34 +100,7 @@ it('should report requests and responses handled by service worker with routing'
expect(failedRequest.failure()).not.toBe(null);
expect(failedRequest.serviceWorker()).toBe(null);
expect(await failedRequest.response()).toBe(null);
});

it('should not intercept requests handled by service worker with routing', async ({ page, server, isAndroid, isElectron, mode, platform, browserName }) => {
it.fixme(isAndroid);
it.fixme(isElectron);
it.fixme(mode.startsWith('service') && platform === 'linux', 'Times out for no clear reason');

const interceptedUrls = [];
await page.route('**/*', async route => {
interceptedUrls.push(route.request().url());
await route.continue();
});
await page.goto(server.PREFIX + '/serviceworkers/fetchdummy/sw.html');
await page.evaluate(() => window['activationPromise']);
const [swResponse, request] = await Promise.all([
page.evaluate(() => window['fetchDummy']('foo')),
page.waitForEvent('request'),
]);
expect(swResponse).toBe('responseFromServiceWorker:foo');
const response = await request.response();
expect(response.url()).toBe(server.PREFIX + '/serviceworkers/fetchdummy/foo');

const [failedRequest] = await Promise.all([
page.waitForEvent('requestfailed'),
page.evaluate(() => window['fetchDummy']('error')).catch(e => e),
]);
expect(failedRequest.url()).toBe(server.PREFIX + '/serviceworkers/fetchdummy/error');
expect(failedRequest.failure()).not.toBe(null);
const expectedUrls = [server.PREFIX + '/serviceworkers/fetchdummy/sw.html'];
if (browserName === 'webkit')
expectedUrls.push(server.PREFIX + '/serviceworkers/fetchdummy/sw.js');
Expand Down

0 comments on commit a8ee3ea

Please sign in to comment.