diff --git a/browsers.json b/browsers.json index 6836f03ce6..0656365eda 100644 --- a/browsers.json +++ b/browsers.json @@ -8,7 +8,7 @@ }, { "name": "firefox", - "revision": "1206", + "revision": "1208", "download": true }, { diff --git a/docs/api.md b/docs/api.md index 474263dbf0..8c7664014a 100644 --- a/docs/api.md +++ b/docs/api.md @@ -4159,6 +4159,7 @@ Aborts the route's request. #### route.continue([overrides]) - `overrides` <[Object]> Optional request overrides, can override following properties: + - `url` <[string]> If set changes the request URL. New URL must have same protocol as original one. - `method` <[string]> If set changes the request method (e.g. GET or POST) - `postData` <[string]|[Buffer]> If set changes the post data of request - `headers` <[Object]<[string], [string]>> If set changes the request HTTP headers. Header values will be converted to a string. diff --git a/src/client/network.ts b/src/client/network.ts index da9b366577..b4e0a37bf1 100644 --- a/src/client/network.ts +++ b/src/client/network.ts @@ -221,9 +221,10 @@ export class Route extends ChannelOwner { await this._object.continue({ + url: params.url, method: params.method, headers: params.headers, postData: params.postData ? Buffer.from(params.postData, 'base64') : undefined, diff --git a/src/protocol/channels.ts b/src/protocol/channels.ts index 48690803ea..14f8a070bd 100644 --- a/src/protocol/channels.ts +++ b/src/protocol/channels.ts @@ -2139,11 +2139,13 @@ export type RouteAbortOptions = { }; export type RouteAbortResult = void; export type RouteContinueParams = { + url?: string, method?: string, headers?: NameValue[], postData?: Binary, }; export type RouteContinueOptions = { + url?: string, method?: string, headers?: NameValue[], postData?: Binary, diff --git a/src/protocol/protocol.yml b/src/protocol/protocol.yml index 812f77b5ec..e8c2a8204f 100644 --- a/src/protocol/protocol.yml +++ b/src/protocol/protocol.yml @@ -1810,6 +1810,7 @@ Route: continue: parameters: + url: string? method: string? headers: type: array? diff --git a/src/protocol/validator.ts b/src/protocol/validator.ts index a9ced7bbc0..333e4edb38 100644 --- a/src/protocol/validator.ts +++ b/src/protocol/validator.ts @@ -845,6 +845,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { errorCode: tOptional(tString), }); scheme.RouteContinueParams = tObject({ + url: tOptional(tString), method: tOptional(tString), headers: tOptional(tArray(tType('NameValue'))), postData: tOptional(tBinary), diff --git a/src/server/chromium/crNetworkManager.ts b/src/server/chromium/crNetworkManager.ts index 12035b8ae5..7f91b5cfe9 100644 --- a/src/server/chromium/crNetworkManager.ts +++ b/src/server/chromium/crNetworkManager.ts @@ -410,6 +410,7 @@ class InterceptableRequest implements network.RouteDelegate { // or the page was closed. We should tolerate these errors. await this._client._sendMayFail('Fetch.continueRequest', { requestId: this._interceptionId!, + url: overrides.url, headers: overrides.headers, method: overrides.method, postData: overrides.postData ? overrides.postData.toString('base64') : undefined diff --git a/src/server/firefox/ffNetworkManager.ts b/src/server/firefox/ffNetworkManager.ts index 772b38ca28..f2fee87e41 100644 --- a/src/server/firefox/ffNetworkManager.ts +++ b/src/server/firefox/ffNetworkManager.ts @@ -175,6 +175,7 @@ class InterceptableRequest implements network.RouteDelegate { async continue(overrides: types.NormalizedContinueOverrides) { await this._session.sendMayFail('Network.resumeInterceptedRequest', { requestId: this._id, + url: overrides.url, method: overrides.method, headers: overrides.headers, postData: overrides.postData ? Buffer.from(overrides.postData).toString('base64') : undefined diff --git a/src/server/firefox/protocol.ts b/src/server/firefox/protocol.ts index 7c43394320..708a1980f9 100644 --- a/src/server/firefox/protocol.ts +++ b/src/server/firefox/protocol.ts @@ -885,6 +885,7 @@ export module Protocol { export type abortInterceptedRequestReturnValue = void; export type resumeInterceptedRequestParameters = { requestId: string; + url?: string; method?: string; headers?: { name: string; diff --git a/src/server/network.ts b/src/server/network.ts index a9881fb219..5b8ad1c71b 100644 --- a/src/server/network.ts +++ b/src/server/network.ts @@ -224,6 +224,12 @@ export class Route { async continue(overrides: types.NormalizedContinueOverrides = {}) { assert(!this._handled, 'Route is already handled!'); + if (overrides.url) { + const newUrl = new URL(overrides.url); + const oldUrl = new URL(this._request.url()); + if (oldUrl.protocol !== newUrl.protocol) + throw new Error('New URL must have same protocol as overriden URL'); + } await this._delegate.continue(overrides); } } diff --git a/src/server/types.ts b/src/server/types.ts index aa00662eac..5b72ad97d6 100644 --- a/src/server/types.ts +++ b/src/server/types.ts @@ -191,6 +191,7 @@ export type NormalizedFulfillResponse = { }; export type NormalizedContinueOverrides = { + url?: string, method?: string, headers?: HeadersArray, postData?: Buffer, diff --git a/src/server/webkit/wkInterceptableRequest.ts b/src/server/webkit/wkInterceptableRequest.ts index 0c4095dbf8..87fc749754 100644 --- a/src/server/webkit/wkInterceptableRequest.ts +++ b/src/server/webkit/wkInterceptableRequest.ts @@ -100,6 +100,7 @@ export class WKInterceptableRequest implements network.RouteDelegate { // or the page was closed. We should tolerate these errors. await this._session.sendMayFail('Network.interceptWithRequest', { requestId: this._requestId, + url: overrides.url, method: overrides.method, headers: overrides.headers ? headersArrayToObject(overrides.headers, false /* lowerCase */) : undefined, postData: overrides.postData ? Buffer.from(overrides.postData).toString('base64') : undefined diff --git a/test/request-continue.spec.ts b/test/request-continue.spec.ts index 68cd283d74..14baf010fe 100644 --- a/test/request-continue.spec.ts +++ b/test/request-continue.spec.ts @@ -49,6 +49,42 @@ it('should amend method', async ({page, server}) => { expect((await sRequest).method).toBe('POST'); }); +it('should override request url', async ({page, server}) => { + const request = server.waitForRequest('/empty.html'); + await page.route('**/foo', route => { + route.continue({ url: server.EMPTY_PAGE }); + }); + await page.goto(server.PREFIX + '/foo'); + expect((await request).method).toBe('GET'); +}); + +it('should not allow changing protocol when overriding url', async ({page, server}) => { + let error: Error | undefined; + await page.route('**/*', async route => { + try { + await route.continue({ url: 'file:///tmp/foo' }); + } catch (e) { + error = e; + await route.continue(); + } + }); + await page.goto(server.EMPTY_PAGE); + expect(error).toBeTruthy(); + expect(error.message).toContain('New URL must have same protocol as overriden URL'); +}); + +it('should override method along with url', async ({page, server}) => { + const request = server.waitForRequest('/empty.html'); + await page.route('**/foo', route => { + route.continue({ + url: server.EMPTY_PAGE, + method: 'POST' + }); + }); + await page.goto(server.PREFIX + '/foo'); + expect((await request).method).toBe('POST'); +}); + it('should amend method on main request', async ({page, server}) => { const request = server.waitForRequest('/empty.html'); await page.route('**/*', route => route.continue({ method: 'POST' }));