Skip to content

Commit 69be12a

Browse files
authored
api(route): pass Route object instead of Request to route handlers (#1385)
References #1348.
1 parent 2647911 commit 69be12a

14 files changed

+251
-255
lines changed

README.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ const { firefox } = require('playwright');
101101

102102
#### Intercept network requests
103103

104-
This code snippet sets up network interception for a WebKit page to log all network requests.
104+
This code snippet sets up request routing for a WebKit page to log all network requests.
105105

106106
```js
107107
const { webkit } = require('playwright');
@@ -112,9 +112,9 @@ const { webkit } = require('playwright');
112112
const page = await context.newPage();
113113

114114
// Log and continue all network requests
115-
page.route('**', request => {
116-
console.log(request.url());
117-
request.continue();
115+
page.route('**', route => {
116+
console.log(route.request().url());
117+
route.continue();
118118
});
119119

120120
await page.goto('http://todomvc.com');

docs/api.md

+106-95
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
- [class: Request](#class-request)
2121
- [class: Response](#class-response)
2222
- [class: Selectors](#class-selectors)
23+
- [class: Route](#class-route)
2324
- [class: TimeoutError](#class-timeouterror)
2425
- [class: Accessibility](#class-accessibility)
2526
- [class: Worker](#class-worker)
@@ -456,17 +457,17 @@ Creates a new page in the browser context.
456457

457458
#### browserContext.route(url, handler)
458459
- `url` <[string]|[RegExp]|[function]\([string]\):[boolean]> A glob pattern, regex pattern or predicate receiving [URL] to match while routing.
459-
- `handler` <[function]\([Request]\)> handler function to route the request.
460-
- returns: <[Promise]>.
460+
- `handler` <[function]\([Route], [Request]\)> handler function to route the request.
461+
- returns: <[Promise]>
461462

462-
Routing activates the request interception and enables `request.abort`, `request.continue` and `request.fulfill` methods on the request. This provides the capability to modify network requests that are made by any page in the browser context.
463+
Routing provides the capability to modify network requests that are made by any page in the browser context.
464+
Once route is enabled, every request matching the url pattern will stall unless it's continued, fulfilled or aborted.
463465

464-
Once request interception is enabled, every request matching the url pattern will stall unless it's continued, fulfilled or aborted.
465-
An example of a naïve request interceptor that aborts all image requests:
466+
An example of a naïve handler that aborts all image requests:
466467

467468
```js
468469
const context = await browser.newContext();
469-
await context.route('**/*.{png,jpg,jpeg}', request => request.abort());
470+
await context.route('**/*.{png,jpg,jpeg}', route => route.abort());
470471
const page = await context.newPage();
471472
await page.goto('https://example.com');
472473
await browser.close();
@@ -476,15 +477,15 @@ or the same snippet using a regex pattern instead:
476477

477478
```js
478479
const context = await browser.newContext();
479-
await context.route(/(\.png$)|(\.jpg$)/, request => request.abort());
480+
await context.route(/(\.png$)|(\.jpg$)/, route => route.abort());
480481
const page = await context.newPage();
481482
await page.goto('https://example.com');
482483
await browser.close();
483484
```
484485

485486
Page routes (set up with [page.route(url, handler)](#pagerouteurl-handler)) take precedence over browser context routes when request matches both handlers.
486487

487-
> **NOTE** Enabling request interception disables http cache.
488+
> **NOTE** Enabling routing disables http cache.
488489
489490
#### browserContext.setDefaultNavigationTimeout(timeout)
490491
- `timeout` <[number]> Maximum navigation time in milliseconds
@@ -783,7 +784,7 @@ const popup = await event.page();
783784
- <[Request]>
784785

785786
Emitted when a page issues a request. The [request] object is read-only.
786-
In order to intercept and mutate requests, see `page.route()`.
787+
In order to intercept and mutate requests, see !!!`page.route()` or `brows.
787788

788789
#### event: 'requestfailed'
789790
- <[Request]>
@@ -1423,18 +1424,18 @@ If `key` is a single character and no modifier keys besides `Shift` are being he
14231424

14241425
#### page.route(url, handler)
14251426
- `url` <[string]|[RegExp]|[function]\([string]\):[boolean]> A glob pattern, regex pattern or predicate receiving [URL] to match while routing.
1426-
- `handler` <[function]\([Request]\)> handler function to route the request.
1427+
- `handler` <[function]\([Route], [Request]\)> handler function to route the request.
14271428
- returns: <[Promise]>.
14281429

1429-
Routing activates the request interception and enables `request.abort`, `request.continue` and
1430-
`request.fulfill` methods on the request. This provides the capability to modify network requests that are made by a page.
1430+
Routing provides the capability to modify network requests that are made by a page.
1431+
1432+
Once routing is enabled, every request matching the url pattern will stall unless it's continued, fulfilled or aborted.
14311433

1432-
Once request interception is enabled, every request matching the url pattern will stall unless it's continued, fulfilled or aborted.
1433-
An example of a naïve request interceptor that aborts all image requests:
1434+
An example of a naïve handler that aborts all image requests:
14341435

14351436
```js
14361437
const page = await browser.newPage();
1437-
await page.route('**/*.{png,jpg,jpeg}', request => request.abort());
1438+
await page.route('**/*.{png,jpg,jpeg}', route => route.abort());
14381439
await page.goto('https://example.com');
14391440
await browser.close();
14401441
```
@@ -1443,14 +1444,14 @@ or the same snippet using a regex pattern instead:
14431444

14441445
```js
14451446
const page = await browser.newPage();
1446-
await page.route(/(\.png$)|(\.jpg$)/, request => request.abort());
1447+
await page.route(/(\.png$)|(\.jpg$)/, route => route.abort());
14471448
await page.goto('https://example.com');
14481449
await browser.close();
14491450
```
14501451

14511452
Page routes take precedence over browser context routes (set up with [browserContext.route(url, handler)](#browsercontextrouteurl-handler)) when request matches both handlers.
14521453

1453-
> **NOTE** Enabling request interception disables http cache.
1454+
> **NOTE** Enabling rouing disables http cache.
14541455
14551456
#### page.screenshot([options])
14561457
- `options` <[Object]> Options object which might have the following properties:
@@ -3131,11 +3132,8 @@ If request fails at some point, then instead of `'requestfinished'` event (and p
31313132
If request gets a 'redirect' response, the request is successfully finished with the 'requestfinished' event, and a new request is issued to a redirected url.
31323133

31333134
<!-- GEN:toc -->
3134-
- [request.abort([errorCode])](#requestaborterrorcode)
3135-
- [request.continue([overrides])](#requestcontinueoverrides)
31363135
- [request.failure()](#requestfailure)
31373136
- [request.frame()](#requestframe)
3138-
- [request.fulfill(response)](#requestfulfillresponse)
31393137
- [request.headers()](#requestheaders)
31403138
- [request.isNavigationRequest()](#requestisnavigationrequest)
31413139
- [request.method()](#requestmethod)
@@ -3146,50 +3144,6 @@ If request gets a 'redirect' response, the request is successfully finished with
31463144
- [request.url()](#requesturl)
31473145
<!-- GEN:stop -->
31483146

3149-
#### request.abort([errorCode])
3150-
- `errorCode` <[string]> Optional error code. Defaults to `failed`, could be
3151-
one of the following:
3152-
- `aborted` - An operation was aborted (due to user action)
3153-
- `accessdenied` - Permission to access a resource, other than the network, was denied
3154-
- `addressunreachable` - The IP address is unreachable. This usually means
3155-
that there is no route to the specified host or network.
3156-
- `blockedbyclient` - The client chose to block the request.
3157-
- `blockedbyresponse` - The request failed because the response was delivered along with requirements which are not met ('X-Frame-Options' and 'Content-Security-Policy' ancestor checks, for instance).
3158-
- `connectionaborted` - A connection timed out as a result of not receiving an ACK for data sent.
3159-
- `connectionclosed` - A connection was closed (corresponding to a TCP FIN).
3160-
- `connectionfailed` - A connection attempt failed.
3161-
- `connectionrefused` - A connection attempt was refused.
3162-
- `connectionreset` - A connection was reset (corresponding to a TCP RST).
3163-
- `internetdisconnected` - The Internet connection has been lost.
3164-
- `namenotresolved` - The host name could not be resolved.
3165-
- `timedout` - An operation timed out.
3166-
- `failed` - A generic failure occurred.
3167-
- returns: <[Promise]>
3168-
3169-
Aborts request. To use this, request interception should be enabled with `page.route`.
3170-
Exception is immediately thrown if the request interception is not enabled.
3171-
3172-
#### request.continue([overrides])
3173-
- `overrides` <[Object]> Optional request overrides, which can be one of the following:
3174-
- `method` <[string]> If set changes the request method (e.g. GET or POST)
3175-
- `postData` <[string]> If set changes the post data of request
3176-
- `headers` <[Object]> If set changes the request HTTP headers. Header values will be converted to a string.
3177-
- returns: <[Promise]>
3178-
3179-
Continues request with optional request overrides. To use this, request interception should be enabled with `page.route`.
3180-
Exception is immediately thrown if the request interception is not enabled.
3181-
3182-
```js
3183-
await page.route('**/*', request => {
3184-
// Override headers
3185-
const headers = Object.assign({}, request.headers(), {
3186-
foo: 'bar', // set "foo" header
3187-
origin: undefined, // remove "origin" header
3188-
});
3189-
request.continue({headers});
3190-
});
3191-
```
3192-
31933147
#### request.failure()
31943148
- returns: <?[Object]> Object describing request failure, if any
31953149
- `errorText` <[string]> Human-readable error message, e.g. `'net::ERR_FAILED'`.
@@ -3208,37 +3162,6 @@ page.on('requestfailed', request => {
32083162
#### request.frame()
32093163
- returns: <[Frame]> A [Frame] that initiated this request.
32103164

3211-
#### request.fulfill(response)
3212-
- `response` <[Object]> Response that will fulfill this request
3213-
- `status` <[number]> Response status code, defaults to `200`.
3214-
- `headers` <[Object]> Optional response headers. Header values will be converted to a string.
3215-
- `contentType` <[string]> If set, equals to setting `Content-Type` response header.
3216-
- `body` <[string]|[Buffer]> Optional response body.
3217-
- `path` <[string]> Optional file path to respond with. The content type will be inferred from file extension. If `path` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd).
3218-
- returns: <[Promise]>
3219-
3220-
Fulfills request with given response. To use this, request interception should
3221-
be enabled with `page.route`. Exception is thrown if
3222-
request interception is not enabled.
3223-
3224-
An example of fulfilling all requests with 404 responses:
3225-
3226-
```js
3227-
await page.route('**/*', request => {
3228-
request.fulfill({
3229-
status: 404,
3230-
contentType: 'text/plain',
3231-
body: 'Not Found!'
3232-
});
3233-
});
3234-
```
3235-
3236-
An example of serving static file:
3237-
3238-
```js
3239-
await page.route('**/xhr_endpoint', request => request.fulfill({ path: 'mock_data.json' }));
3240-
```
3241-
32423165
#### request.headers()
32433166
- returns: <[Object]> An object with HTTP headers associated with the request. All header names are lower-case.
32443167

@@ -3410,6 +3333,93 @@ const { selectors, firefox } = require('playwright'); // Or 'chromium' or 'webk
34103333
})();
34113334
```
34123335

3336+
3337+
### class: Route
3338+
3339+
Whenever a network route is set up with [page.route(url, handler)](#pagerouteurl-handler) or [browserContext.route(url, handler)](#browsercontextrouteurl-handler), the `Route` object allows to handle the route.
3340+
3341+
<!-- GEN:toc -->
3342+
- [route.abort([errorCode])](#routeaborterrorcode)
3343+
- [route.continue([overrides])](#routecontinueoverrides)
3344+
- [route.fulfill(response)](#routefulfillresponse)
3345+
- [route.request()](#routerequest)
3346+
<!-- GEN:stop -->
3347+
3348+
#### route.abort([errorCode])
3349+
- `errorCode` <[string]> Optional error code. Defaults to `failed`, could be
3350+
one of the following:
3351+
- `aborted` - An operation was aborted (due to user action)
3352+
- `accessdenied` - Permission to access a resource, other than the network, was denied
3353+
- `addressunreachable` - The IP address is unreachable. This usually means
3354+
that there is no route to the specified host or network.
3355+
- `blockedbyclient` - The client chose to block the request.
3356+
- `blockedbyresponse` - The request failed because the response was delivered along with requirements which are not met ('X-Frame-Options' and 'Content-Security-Policy' ancestor checks, for instance).
3357+
- `connectionaborted` - A connection timed out as a result of not receiving an ACK for data sent.
3358+
- `connectionclosed` - A connection was closed (corresponding to a TCP FIN).
3359+
- `connectionfailed` - A connection attempt failed.
3360+
- `connectionrefused` - A connection attempt was refused.
3361+
- `connectionreset` - A connection was reset (corresponding to a TCP RST).
3362+
- `internetdisconnected` - The Internet connection has been lost.
3363+
- `namenotresolved` - The host name could not be resolved.
3364+
- `timedout` - An operation timed out.
3365+
- `failed` - A generic failure occurred.
3366+
- returns: <[Promise]>
3367+
3368+
Aborts the route's request.
3369+
3370+
#### route.continue([overrides])
3371+
- `overrides` <[Object]> Optional request overrides, which can be one of the following:
3372+
- `method` <[string]> If set changes the request method (e.g. GET or POST)
3373+
- `postData` <[string]> If set changes the post data of request
3374+
- `headers` <[Object]> If set changes the request HTTP headers. Header values will be converted to a string.
3375+
- returns: <[Promise]>
3376+
3377+
Continues route's request with optional overrides.
3378+
3379+
```js
3380+
await page.route('**/*', (route, request) => {
3381+
// Override headers
3382+
const headers = Object.assign({}, request.headers(), {
3383+
foo: 'bar', // set "foo" header
3384+
origin: undefined, // remove "origin" header
3385+
});
3386+
route.continue({headers});
3387+
});
3388+
```
3389+
3390+
#### route.fulfill(response)
3391+
- `response` <[Object]> Response that will fulfill this route's request.
3392+
- `status` <[number]> Response status code, defaults to `200`.
3393+
- `headers` <[Object]> Optional response headers. Header values will be converted to a string.
3394+
- `contentType` <[string]> If set, equals to setting `Content-Type` response header.
3395+
- `body` <[string]|[Buffer]> Optional response body.
3396+
- `path` <[string]> Optional file path to respond with. The content type will be inferred from file extension. If `path` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd).
3397+
- returns: <[Promise]>
3398+
3399+
Fulfills route's request with given response.
3400+
3401+
An example of fulfilling all requests with 404 responses:
3402+
3403+
```js
3404+
await page.route('**/*', route => {
3405+
route.fulfill({
3406+
status: 404,
3407+
contentType: 'text/plain',
3408+
body: 'Not Found!'
3409+
});
3410+
});
3411+
```
3412+
3413+
An example of serving static file:
3414+
3415+
```js
3416+
await page.route('**/xhr_endpoint', route => route.fulfill({ path: 'mock_data.json' }));
3417+
```
3418+
3419+
#### route.request()
3420+
- returns: <[Request]> A request to be routed.
3421+
3422+
34133423
### class: TimeoutError
34143424

34153425
* extends: [Error]
@@ -4052,6 +4062,7 @@ const { chromium } = require('playwright');
40524062
[RegExp]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp
40534063
[Request]: #class-request "Request"
40544064
[Response]: #class-response "Response"
4065+
[Route]: #class-route "Route"
40554066
[Selectors]: #class-selectors "Selectors"
40564067
[Serializable]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#Description "Serializable"
40574068
[TimeoutError]: #class-timeouterror "TimeoutError"

src/api.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export { TimeoutError } from './errors';
2424
export { Frame } from './frames';
2525
export { Keyboard, Mouse } from './input';
2626
export { JSHandle } from './javascript';
27-
export { Request, Response } from './network';
27+
export { Request, Response, Route } from './network';
2828
export { FileChooser, Page, PageEvent, Worker } from './page';
2929
export { Selectors } from './selectors';
3030

src/browserContext.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export abstract class BrowserContextBase extends platform.EventEmitter implement
6363
readonly _timeoutSettings = new TimeoutSettings();
6464
readonly _pageBindings = new Map<string, PageBinding>();
6565
readonly _options: BrowserContextOptions;
66-
readonly _routes: { url: types.URLMatch, handler: (request: network.Request) => any }[] = [];
66+
readonly _routes: { url: types.URLMatch, handler: network.RouteHandler }[] = [];
6767
_closed = false;
6868
private readonly _closePromise: Promise<Error>;
6969
private _closePromiseFulfill: ((error: Error) => void) | undefined;

src/chromium/crNetworkManager.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ export class CRNetworkManager {
241241
}
242242
}
243243

244-
class InterceptableRequest implements network.RequestDelegate {
244+
class InterceptableRequest implements network.RouteDelegate {
245245
readonly request: network.Request;
246246
_requestId: string;
247247
_interceptionId: string | null;

src/firefox/ffNetworkManager.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ const causeToResourceType: {[key: string]: string} = {
141141
TYPE_WEB_MANIFEST: 'manifest',
142142
};
143143

144-
class InterceptableRequest implements network.RequestDelegate {
144+
class InterceptableRequest implements network.RouteDelegate {
145145
readonly request: network.Request;
146146
_id: string;
147147
private _session: FFSession;

0 commit comments

Comments
 (0)