refactor: migrate onto Fetch domain (#4265)

Request interception in Network domain is deprecated.
Move on onto Fetch domain - the new bright future.
This commit is contained in:
Andrey Lushnikov 2019-04-11 15:02:06 -04:00 committed by GitHub
parent a79b775430
commit 2265974ce5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -45,8 +45,9 @@ class NetworkManager extends EventEmitter {
/** @type {!Map<string, string>} */ /** @type {!Map<string, string>} */
this._requestIdToInterceptionId = new Map(); this._requestIdToInterceptionId = new Map();
this._client.on('Fetch.requestPaused', this._onRequestPaused.bind(this));
this._client.on('Fetch.authRequired', this._onAuthRequired.bind(this));
this._client.on('Network.requestWillBeSent', this._onRequestWillBeSent.bind(this)); this._client.on('Network.requestWillBeSent', this._onRequestWillBeSent.bind(this));
this._client.on('Network.requestIntercepted', this._onRequestIntercepted.bind(this));
this._client.on('Network.requestServedFromCache', this._onRequestServedFromCache.bind(this)); this._client.on('Network.requestServedFromCache', this._onRequestServedFromCache.bind(this));
this._client.on('Network.responseReceived', this._onResponseReceived.bind(this)); this._client.on('Network.responseReceived', this._onResponseReceived.bind(this));
this._client.on('Network.loadingFinished', this._onLoadingFinished.bind(this)); this._client.on('Network.loadingFinished', this._onLoadingFinished.bind(this));
@ -138,11 +139,20 @@ class NetworkManager extends EventEmitter {
if (enabled === this._protocolRequestInterceptionEnabled) if (enabled === this._protocolRequestInterceptionEnabled)
return; return;
this._protocolRequestInterceptionEnabled = enabled; this._protocolRequestInterceptionEnabled = enabled;
const patterns = enabled ? [{urlPattern: '*'}] : []; if (enabled) {
await Promise.all([ await Promise.all([
this._updateProtocolCacheDisabled(), this._updateProtocolCacheDisabled(),
this._client.send('Network.setRequestInterception', {patterns}) this._client.send('Fetch.enable', {
handleAuthRequests: true,
patterns: [{urlPattern: '*'}],
}),
]); ]);
} else {
await Promise.all([
this._updateProtocolCacheDisabled(),
this._client.send('Fetch.disable')
]);
}
} }
async _updateProtocolCacheDisabled() { async _updateProtocolCacheDisabled() {
@ -171,38 +181,42 @@ class NetworkManager extends EventEmitter {
} }
/** /**
* @param {!Protocol.Network.requestInterceptedPayload} event * @param {!Protocol.Fetch.authRequiredPayload} event
*/ */
_onRequestIntercepted(event) { _onAuthRequired(event) {
if (event.authChallenge) {
/** @type {"Default"|"CancelAuth"|"ProvideCredentials"} */ /** @type {"Default"|"CancelAuth"|"ProvideCredentials"} */
let response = 'Default'; let response = 'Default';
if (this._attemptedAuthentications.has(event.interceptionId)) { if (this._attemptedAuthentications.has(event.requestId)) {
response = 'CancelAuth'; response = 'CancelAuth';
} else if (this._credentials) { } else if (this._credentials) {
response = 'ProvideCredentials'; response = 'ProvideCredentials';
this._attemptedAuthentications.add(event.interceptionId); this._attemptedAuthentications.add(event.requestId);
} }
const {username, password} = this._credentials || {username: undefined, password: undefined}; const {username, password} = this._credentials || {username: undefined, password: undefined};
this._client.send('Network.continueInterceptedRequest', { this._client.send('Fetch.continueWithAuth', {
interceptionId: event.interceptionId, requestId: event.requestId,
authChallengeResponse: { response, username, password } authChallengeResponse: { response, username, password },
}).catch(debugError);
return;
}
if (!this._userRequestInterceptionEnabled && this._protocolRequestInterceptionEnabled) {
this._client.send('Network.continueInterceptedRequest', {
interceptionId: event.interceptionId
}).catch(debugError); }).catch(debugError);
} }
const requestId = event.requestId; /**
* @param {!Protocol.Fetch.requestPausedPayload} event
*/
_onRequestPaused(event) {
if (!this._userRequestInterceptionEnabled && this._protocolRequestInterceptionEnabled) {
this._client.send('Fetch.continueRequest', {
requestId: event.requestId
}).catch(debugError);
}
const requestId = event.networkId;
const interceptionId = event.requestId;
if (requestId && this._requestIdToRequestWillBeSentEvent.has(requestId)) { if (requestId && this._requestIdToRequestWillBeSentEvent.has(requestId)) {
const requestWillBeSentEvent = this._requestIdToRequestWillBeSentEvent.get(requestId); const requestWillBeSentEvent = this._requestIdToRequestWillBeSentEvent.get(requestId);
this._onRequest(requestWillBeSentEvent, event.interceptionId); this._onRequest(requestWillBeSentEvent, interceptionId);
this._requestIdToRequestWillBeSentEvent.delete(requestId); this._requestIdToRequestWillBeSentEvent.delete(requestId);
} else { } else {
this._requestIdToInterceptionId.set(requestId, event.interceptionId); this._requestIdToInterceptionId.set(requestId, interceptionId);
} }
} }
@ -424,12 +438,12 @@ class Request {
headers headers
} = overrides; } = overrides;
this._interceptionHandled = true; this._interceptionHandled = true;
await this._client.send('Network.continueInterceptedRequest', { await this._client.send('Fetch.continueRequest', {
interceptionId: this._interceptionId, requestId: this._interceptionId,
url, url,
method, method,
postData, postData,
headers, headers: headers ? headersArray(headers) : undefined,
}).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.
@ -450,6 +464,7 @@ class Request {
const responseBody = response.body && helper.isString(response.body) ? Buffer.from(/** @type {string} */(response.body)) : /** @type {?Buffer} */(response.body || null); const responseBody = response.body && helper.isString(response.body) ? Buffer.from(/** @type {string} */(response.body)) : /** @type {?Buffer} */(response.body || null);
/** @type {!Object<string, string>} */
const responseHeaders = {}; const responseHeaders = {};
if (response.headers) { if (response.headers) {
for (const header of Object.keys(response.headers)) for (const header of Object.keys(response.headers))
@ -458,24 +473,13 @@ class Request {
if (response.contentType) if (response.contentType)
responseHeaders['content-type'] = response.contentType; responseHeaders['content-type'] = response.contentType;
if (responseBody && !('content-length' in responseHeaders)) if (responseBody && !('content-length' in responseHeaders))
responseHeaders['content-length'] = Buffer.byteLength(responseBody); responseHeaders['content-length'] = String(Buffer.byteLength(responseBody));
const statusCode = response.status || 200; await this._client.send('Fetch.fulfillRequest', {
const statusText = statusTexts[statusCode] || ''; requestId: this._interceptionId,
const statusLine = `HTTP/1.1 ${statusCode} ${statusText}`; responseCode: response.status || 200,
responseHeaders: headersArray(responseHeaders),
const CRLF = '\r\n'; body: responseBody ? responseBody.toString('base64') : undefined,
let text = statusLine + CRLF;
for (const header of Object.keys(responseHeaders))
text += header + ': ' + responseHeaders[header] + CRLF;
text += CRLF;
let responseBuffer = Buffer.from(text, 'utf8');
if (responseBody)
responseBuffer = Buffer.concat([responseBuffer, responseBody]);
await this._client.send('Network.continueInterceptedRequest', {
interceptionId: this._interceptionId,
rawResponse: responseBuffer.toString('base64')
}).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.
@ -495,8 +499,8 @@ class Request {
assert(this._allowInterception, 'Request Interception is not enabled!'); assert(this._allowInterception, 'Request Interception is not enabled!');
assert(!this._interceptionHandled, 'Request is already handled!'); assert(!this._interceptionHandled, 'Request is already handled!');
this._interceptionHandled = true; this._interceptionHandled = true;
await this._client.send('Network.continueInterceptedRequest', { await this._client.send('Fetch.failRequest', {
interceptionId: this._interceptionId, requestId: this._interceptionId,
errorReason 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
@ -712,67 +716,15 @@ class SecurityDetails {
} }
} }
const statusTexts = { /**
'100': 'Continue', * @param {Object<string, string>} headers
'101': 'Switching Protocols', * @return {!Array<{name: string, value: string}>}
'102': 'Processing', */
'200': 'OK', function headersArray(headers) {
'201': 'Created', const result = [];
'202': 'Accepted', for (const name in headers)
'203': 'Non-Authoritative Information', result.push({name, value: headers[name]});
'204': 'No Content', return result;
'206': 'Partial Content', }
'207': 'Multi-Status',
'208': 'Already Reported',
'209': 'IM Used',
'300': 'Multiple Choices',
'301': 'Moved Permanently',
'302': 'Found',
'303': 'See Other',
'304': 'Not Modified',
'305': 'Use Proxy',
'306': 'Switch Proxy',
'307': 'Temporary Redirect',
'308': 'Permanent Redirect',
'400': 'Bad Request',
'401': 'Unauthorized',
'402': 'Payment Required',
'403': 'Forbidden',
'404': 'Not Found',
'405': 'Method Not Allowed',
'406': 'Not Acceptable',
'407': 'Proxy Authentication Required',
'408': 'Request Timeout',
'409': 'Conflict',
'410': 'Gone',
'411': 'Length Required',
'412': 'Precondition Failed',
'413': 'Payload Too Large',
'414': 'URI Too Long',
'415': 'Unsupported Media Type',
'416': 'Range Not Satisfiable',
'417': 'Expectation Failed',
'418': 'I\'m a teapot',
'421': 'Misdirected Request',
'422': 'Unprocessable Entity',
'423': 'Locked',
'424': 'Failed Dependency',
'426': 'Upgrade Required',
'428': 'Precondition Required',
'429': 'Too Many Requests',
'431': 'Request Header Fields Too Large',
'451': 'Unavailable For Legal Reasons',
'500': 'Internal Server Error',
'501': 'Not Implemented',
'502': 'Bad Gateway',
'503': 'Service Unavailable',
'504': 'Gateway Timeout',
'505': 'HTTP Version Not Supported',
'506': 'Variant Also Negotiates',
'507': 'Insufficient Storage',
'508': 'Loop Detected',
'510': 'Not Extended',
'511': 'Network Authentication Required',
};
module.exports = {Request, Response, NetworkManager, SecurityDetails}; module.exports = {Request, Response, NetworkManager, SecurityDetails};