feat(Request): allow aborting intercepted requests with custom reasons (#1080)

This patch adds optional parameter to the `request.abort()` method
that specifies abort reason.

References #1020.
This commit is contained in:
Andrey Lushnikov 2017-10-18 00:26:48 -07:00 committed by GitHub
parent 7fbd2cb661
commit 4f64dfd993
3 changed files with 52 additions and 4 deletions

View File

@ -162,7 +162,7 @@
* [elementHandle.type(text[, options])](#elementhandletypetext-options) * [elementHandle.type(text[, options])](#elementhandletypetext-options)
* [elementHandle.uploadFile(...filePaths)](#elementhandleuploadfilefilepaths) * [elementHandle.uploadFile(...filePaths)](#elementhandleuploadfilefilepaths)
- [class: Request](#class-request) - [class: Request](#class-request)
* [request.abort()](#requestabort) * [request.abort([errorCode])](#requestaborterrorcode)
* [request.continue([overrides])](#requestcontinueoverrides) * [request.continue([overrides])](#requestcontinueoverrides)
* [request.failure()](#requestfailure) * [request.failure()](#requestfailure)
* [request.headers](#requestheaders) * [request.headers](#requestheaders)
@ -1831,7 +1831,22 @@ If request fails at some point, then instead of 'requestfinished' event (and pos
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. 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.
#### request.abort() #### request.abort([errorCode])
- `errorCode` <[string]> Optional error code. Defaults to `failed`, could be
one of the following:
- `aborted` - An operation was aborted (due to user action)
- `accessdenied` - Permission to access a resource, other than the network, was denied
- `addressunreachable` - The IP address is unreachable. This usually means
that there is no route to the specified host or network.
- `connectionaborted` - A connection timed out as a result of not receiving an ACK for data sent.
- `connectionclosed` - A connection was closed (corresponding to a TCP FIN).
- `connectionfailed` - A connection attempt failed.
- `connectionrefused` - A connection attempt was refused.
- `connectionreset` - A connection was reset (corresponding to a TCP RST).
- `internetdisconnected` - The Internet connection has been lost.
- `namenotresolved` - The host name could not be resolved.
- `timedout` - An operation timed out.
- `failed` - A generic failure occurred.
- returns: <[Promise]> - returns: <[Promise]>
Aborts request. To use this, request interception should be enabled with `page.setRequestInterceptionEnabled`. Aborts request. To use this, request interception should be enabled with `page.setRequestInterceptionEnabled`.

View File

@ -340,16 +340,21 @@ class Request {
}); });
} }
async abort() { /**
* @param {string=} errorCode
*/
async abort(errorCode = 'failed') {
// DataURL's are not interceptable. In this case, do nothing. // DataURL's are not interceptable. In this case, do nothing.
if (this.url.startsWith('data:')) if (this.url.startsWith('data:'))
return; return;
const errorReason = errorReasons[errorCode];
console.assert(errorReason, 'Unknown error code: ' + errorCode);
console.assert(this._allowInterception, 'Request Interception is not enabled!'); console.assert(this._allowInterception, 'Request Interception is not enabled!');
console.assert(!this._interceptionHandled, 'Request is already handled!'); console.assert(!this._interceptionHandled, 'Request is already handled!');
this._interceptionHandled = true; this._interceptionHandled = true;
await this._client.send('Network.continueInterceptedRequest', { await this._client.send('Network.continueInterceptedRequest', {
interceptionId: this._interceptionId, interceptionId: this._interceptionId,
errorReason: 'Failed' errorReason
}).catch(error => { }).catch(error => {
// In certain cases, protocol will return error if the request was already canceled // In certain cases, protocol will return error if the request was already canceled
// or the page was closed. We should tolerate these errors. // or the page was closed. We should tolerate these errors.
@ -357,6 +362,22 @@ class Request {
}); });
} }
} }
const errorReasons = {
'aborted': 'Aborted',
'accessdenied': 'AccessDenied',
'addressunreachable': 'AddressUnreachable',
'connectionaborted': 'ConnectionAborted',
'connectionclosed': 'ConnectionClosed',
'connectionfailed': 'ConnectionFailed',
'connectionrefused': 'ConnectionRefused',
'connectionreset': 'ConnectionReset',
'internetdisconnected': 'InternetDisconnected',
'namenotresolved': 'NameNotResolved',
'timedout': 'TimedOut',
'failed': 'Failed',
};
helper.tracePublicAPI(Request); helper.tracePublicAPI(Request);
class Response { class Response {

View File

@ -1176,8 +1176,20 @@ describe('Page', function() {
page.on('requestfailed', event => ++failedRequests); page.on('requestfailed', event => ++failedRequests);
const response = await page.goto(PREFIX + '/one-style.html'); const response = await page.goto(PREFIX + '/one-style.html');
expect(response.ok).toBe(true); expect(response.ok).toBe(true);
expect(response.request().failure()).toBe(null);
expect(failedRequests).toBe(1); expect(failedRequests).toBe(1);
})); }));
it('should be abortable with custom error codes', SX(async function() {
await page.setRequestInterceptionEnabled(true);
page.on('request', request => {
request.abort('internetdisconnected');
});
let failedRequest = null;
page.on('requestfailed', request => failedRequest = request);
await page.goto(EMPTY_PAGE).catch(e => {});
expect(failedRequest).toBeTruthy();
expect(failedRequest.failure().errorText).toBe('net::ERR_INTERNET_DISCONNECTED');
}));
it('should amend HTTP headers', SX(async function() { it('should amend HTTP headers', SX(async function() {
await page.setRequestInterceptionEnabled(true); await page.setRequestInterceptionEnabled(true);
page.on('request', request => { page.on('request', request => {