fix(chromium): make interception work with dedicated workers (#4658)

This commit is contained in:
Dmitry Gozman 2020-12-10 15:04:57 -08:00 committed by GitHub
parent b9c959768c
commit 495085cbb2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 53 additions and 31 deletions

View file

@ -200,6 +200,11 @@ export class CRNetworkManager {
} }
} }
let frame = requestWillBeSentEvent.frameId ? this._page._frameManager.frame(requestWillBeSentEvent.frameId) : workerFrame; let frame = requestWillBeSentEvent.frameId ? this._page._frameManager.frame(requestWillBeSentEvent.frameId) : workerFrame;
// Requests from workers lack frameId, because we receive Network.requestWillBeSent
// on the worker target. However, we receive Fetch.requestPaused on the page target,
// and lack workerFrame there. Luckily, Fetch.requestPaused provides a frameId.
if (!frame && requestPausedEvent && requestPausedEvent.frameId)
frame = this._page._frameManager.frame(requestPausedEvent.frameId);
// Check if it's main resource request interception (targetId === main frame id). // Check if it's main resource request interception (targetId === main frame id).
if (!frame && requestPausedEvent && requestWillBeSentEvent.frameId === (this._page._delegate as CRPage)._targetId) { if (!frame && requestPausedEvent && requestWillBeSentEvent.frameId === (this._page._delegate as CRPage)._targetId) {
@ -209,11 +214,12 @@ export class CRNetworkManager {
frame = this._page._frameManager.frameAttached(requestWillBeSentEvent.frameId, null); frame = this._page._frameManager.frameAttached(requestWillBeSentEvent.frameId, null);
} }
if (!frame) { // CORS options request is generated by the network stack. If interception is enabled,
if (requestPausedEvent) { // we accept all CORS options, assuming that this was intended when setting route.
// CORS options request is generated by the network stack, it is not associated with the frame id. //
// If URL matches interception pattern, accept it, assuming that this was intended when setting route. // Note: it would be better to match the URL against interception patterns, but
if (requestPausedEvent.request.method === 'OPTIONS' && this._page._needsRequestInterception()) { // that information is only available to the client. Perhaps we can just route to the client?
if (requestPausedEvent && requestPausedEvent.request.method === 'OPTIONS' && this._page._needsRequestInterception()) {
const requestHeaders = requestPausedEvent.request.headers; const requestHeaders = requestPausedEvent.request.headers;
const responseHeaders: Protocol.Fetch.HeaderEntry[] = [ const responseHeaders: Protocol.Fetch.HeaderEntry[] = [
{ name: 'Access-Control-Allow-Origin', value: requestHeaders['Origin'] || '*' }, { name: 'Access-Control-Allow-Origin', value: requestHeaders['Origin'] || '*' },
@ -229,12 +235,15 @@ export class CRNetworkManager {
responseHeaders, responseHeaders,
body: '', body: '',
}); });
} else {
this._client._sendMayFail('Fetch.continueRequest', { requestId: requestPausedEvent.requestId });
}
}
return; return;
} }
if (!frame) {
if (requestPausedEvent)
this._client._sendMayFail('Fetch.continueRequest', { requestId: requestPausedEvent.requestId });
return;
}
let allowInterception = this._userRequestInterceptionEnabled; let allowInterception = this._userRequestInterceptionEnabled;
if (redirectedFrom) { if (redirectedFrom) {
allowInterception = false; allowInterception = false;

View file

@ -88,18 +88,15 @@ it('should work with glob', async () => {
expect(globToRegex('**/*.{png,jpg,jpeg}').test('https://localhost:8080/c.css')).toBeFalsy(); expect(globToRegex('**/*.{png,jpg,jpeg}').test('https://localhost:8080/c.css')).toBeFalsy();
}); });
it('should intercept network activity from worker', (test, {browserName}) => { it('should intercept network activity from worker', async function({page, server}) {
// @see https://github.com/microsoft/playwright/issues/4487
test.fixme(browserName === 'chromium');
}, async function({page, server}) {
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
server.setRoute('/data_for_worker', (req, res) => res.end('failed to intercept')); server.setRoute('/data_for_worker', (req, res) => res.end('failed to intercept'));
const url = server.PREFIX + '/data_for_worker'; const url = server.PREFIX + '/data_for_worker';
page.route(url, async route => { await page.route(url, route => {
await route.fulfill({ route.fulfill({
status: 200, status: 200,
body: 'intercepted', body: 'intercepted',
}); }).catch(e => null);
}); });
const [msg] = await Promise.all([ const [msg] = await Promise.all([
page.waitForEvent('console'), page.waitForEvent('console'),
@ -110,6 +107,22 @@ it('should intercept network activity from worker', (test, {browserName}) => {
expect(msg.text()).toBe('intercepted'); expect(msg.text()).toBe('intercepted');
}); });
it('should intercept network activity from worker', async function({page, server}) {
const url = server.PREFIX + '/worker/worker.js';
await page.route(url, route => {
route.fulfill({
status: 200,
body: 'console.log("intercepted");',
contentType: 'application/javascript',
}).catch(e => null);
});
const [msg] = await Promise.all([
page.waitForEvent('console'),
page.goto(server.PREFIX + '/worker/worker.html'),
]);
expect(msg.text()).toBe('intercepted');
});
it('should work with regular expression passed from a different context', async ({page, server}) => { it('should work with regular expression passed from a different context', async ({page, server}) => {
const ctx = vm.createContext(); const ctx = vm.createContext();
const regexp = vm.runInContext('new RegExp("empty\\.html")', ctx); const regexp = vm.runInContext('new RegExp("empty\\.html")', ctx);