2020-01-21 14:58:12 -08:00
|
|
|
/**
|
|
|
|
* Copyright 2017 Google Inc. All rights reserved.
|
|
|
|
* Modifications copyright (c) Microsoft Corporation.
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
import * as frames from '../frames';
|
2020-04-20 07:52:26 -07:00
|
|
|
import { assert, helper } from '../helper';
|
2020-01-21 14:58:12 -08:00
|
|
|
import * as network from '../network';
|
2020-06-25 08:30:56 -07:00
|
|
|
import * as types from '../types';
|
2020-01-21 14:58:12 -08:00
|
|
|
import { Protocol } from './protocol';
|
|
|
|
import { WKSession } from './wkConnection';
|
|
|
|
|
2020-06-17 08:34:42 -07:00
|
|
|
const errorReasons: { [reason: string]: Protocol.Network.ResourceErrorType } = {
|
2020-01-21 14:58:12 -08:00
|
|
|
'aborted': 'Cancellation',
|
|
|
|
'accessdenied': 'AccessControl',
|
|
|
|
'addressunreachable': 'General',
|
|
|
|
'blockedbyclient': 'Cancellation',
|
|
|
|
'blockedbyresponse': 'General',
|
|
|
|
'connectionaborted': 'General',
|
|
|
|
'connectionclosed': 'General',
|
|
|
|
'connectionfailed': 'General',
|
|
|
|
'connectionrefused': 'General',
|
|
|
|
'connectionreset': 'General',
|
|
|
|
'internetdisconnected': 'General',
|
|
|
|
'namenotresolved': 'General',
|
|
|
|
'timedout': 'Timeout',
|
|
|
|
'failed': 'General',
|
|
|
|
};
|
|
|
|
|
2020-03-13 14:30:40 -07:00
|
|
|
export class WKInterceptableRequest implements network.RouteDelegate {
|
2020-01-21 14:58:12 -08:00
|
|
|
private readonly _session: WKSession;
|
|
|
|
readonly request: network.Request;
|
|
|
|
readonly _requestId: string;
|
|
|
|
_interceptedCallback: () => void = () => {};
|
|
|
|
private _interceptedPromise: Promise<unknown>;
|
2020-06-18 17:15:47 -07:00
|
|
|
readonly _allowInterception: boolean;
|
2020-01-21 14:58:12 -08:00
|
|
|
|
2020-03-16 13:31:06 -07:00
|
|
|
constructor(session: WKSession, allowInterception: boolean, frame: frames.Frame, event: Protocol.Network.requestWillBeSentPayload, redirectedFrom: network.Request | null, documentId: string | undefined) {
|
2020-01-21 14:58:12 -08:00
|
|
|
this._session = session;
|
|
|
|
this._requestId = event.requestId;
|
2020-06-18 17:15:47 -07:00
|
|
|
this._allowInterception = allowInterception;
|
2020-05-28 14:38:47 -07:00
|
|
|
const resourceType = event.type ? event.type.toLowerCase() : (redirectedFrom ? redirectedFrom.resourceType() : 'other');
|
2020-03-16 13:31:06 -07:00
|
|
|
this.request = new network.Request(allowInterception ? this : null, frame, redirectedFrom, documentId, event.request.url,
|
|
|
|
resourceType, event.request.method, event.request.postData || null, headersObject(event.request.headers));
|
2020-01-21 14:58:12 -08:00
|
|
|
this._interceptedPromise = new Promise(f => this._interceptedCallback = f);
|
|
|
|
}
|
|
|
|
|
|
|
|
async abort(errorCode: string) {
|
2020-06-17 08:34:42 -07:00
|
|
|
const errorType = errorReasons[errorCode];
|
|
|
|
assert(errorType, 'Unknown error code: ' + errorCode);
|
2020-01-21 14:58:12 -08:00
|
|
|
await this._interceptedPromise;
|
2020-06-05 07:50:26 -07:00
|
|
|
// In certain cases, protocol will return error if the request was already canceled
|
|
|
|
// or the page was closed. We should tolerate these errors.
|
2020-06-17 08:34:42 -07:00
|
|
|
await this._session.sendMayFail('Network.interceptRequestWithError', { requestId: this._requestId, errorType });
|
2020-01-21 14:58:12 -08:00
|
|
|
}
|
|
|
|
|
2020-06-29 16:37:38 -07:00
|
|
|
async fulfill(response: types.NormalizedFulfillResponse) {
|
2020-01-21 14:58:12 -08:00
|
|
|
await this._interceptedPromise;
|
|
|
|
|
|
|
|
const base64Encoded = !!response.body && !helper.isString(response.body);
|
2020-04-16 12:36:00 -07:00
|
|
|
const responseBody = response.body ? (base64Encoded ? response.body.toString('base64') : response.body as string) : '';
|
2020-01-21 14:58:12 -08:00
|
|
|
|
|
|
|
const responseHeaders: { [s: string]: string; } = {};
|
2020-06-29 16:37:38 -07:00
|
|
|
for (const header of Object.keys(response.headers))
|
|
|
|
responseHeaders[header.toLowerCase()] = String(response.headers[header]);
|
2020-05-04 21:49:54 -07:00
|
|
|
let mimeType = base64Encoded ? 'application/octet-stream' : 'text/plain';
|
|
|
|
if (response.contentType) {
|
2020-01-21 14:58:12 -08:00
|
|
|
responseHeaders['content-type'] = response.contentType;
|
2020-05-04 21:49:54 -07:00
|
|
|
const index = response.contentType.indexOf(';');
|
|
|
|
if (index !== -1)
|
|
|
|
mimeType = response.contentType.substring(0, index).trimEnd();
|
|
|
|
else
|
|
|
|
mimeType = response.contentType.trim();
|
|
|
|
}
|
2020-01-21 14:58:12 -08:00
|
|
|
if (responseBody && !('content-length' in responseHeaders))
|
2020-04-01 14:42:47 -07:00
|
|
|
responseHeaders['content-length'] = String(Buffer.byteLength(responseBody));
|
2020-01-21 14:58:12 -08:00
|
|
|
|
2020-06-05 07:50:26 -07:00
|
|
|
// In certain cases, protocol will return error if the request was already canceled
|
|
|
|
// or the page was closed. We should tolerate these errors.
|
2020-06-17 08:34:42 -07:00
|
|
|
await this._session.sendMayFail('Network.interceptRequestWithResponse', {
|
2020-01-21 14:58:12 -08:00
|
|
|
requestId: this._requestId,
|
2020-06-29 16:37:38 -07:00
|
|
|
status: response.status,
|
|
|
|
statusText: network.STATUS_TEXTS[String(response.status)],
|
2020-05-04 21:49:54 -07:00
|
|
|
mimeType,
|
2020-01-21 14:58:12 -08:00
|
|
|
headers: responseHeaders,
|
|
|
|
base64Encoded,
|
|
|
|
content: responseBody
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-06-25 08:30:56 -07:00
|
|
|
async continue(overrides: { method?: string; headers?: types.Headers; postData?: string }) {
|
2020-01-21 14:58:12 -08:00
|
|
|
await this._interceptedPromise;
|
2020-06-05 07:50:26 -07:00
|
|
|
// In certain cases, protocol will return error if the request was already canceled
|
|
|
|
// or the page was closed. We should tolerate these errors.
|
2020-06-17 08:34:42 -07:00
|
|
|
await this._session.sendMayFail('Network.interceptWithRequest', {
|
2020-01-21 14:58:12 -08:00
|
|
|
requestId: this._requestId,
|
2020-01-28 14:29:46 -08:00
|
|
|
method: overrides.method,
|
|
|
|
headers: overrides.headers,
|
|
|
|
postData: overrides.postData ? Buffer.from(overrides.postData).toString('base64') : undefined
|
2020-01-21 14:58:12 -08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
createResponse(responsePayload: Protocol.Network.Response): network.Response {
|
|
|
|
const getResponseBody = async () => {
|
|
|
|
const response = await this._session.send('Network.getResponseBody', { requestId: this._requestId });
|
2020-04-01 14:42:47 -07:00
|
|
|
return Buffer.from(response.body, response.base64Encoded ? 'base64' : 'utf8');
|
2020-01-21 14:58:12 -08:00
|
|
|
};
|
2020-01-23 12:13:58 -08:00
|
|
|
return new network.Response(this.request, responsePayload.status, responsePayload.statusText, headersObject(responsePayload.headers), getResponseBody);
|
2020-01-21 14:58:12 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-25 08:30:56 -07:00
|
|
|
function headersObject(headers: Protocol.Network.Headers): types.Headers {
|
|
|
|
const result: types.Headers = {};
|
2020-01-21 14:58:12 -08:00
|
|
|
for (const key of Object.keys(headers))
|
|
|
|
result[key.toLowerCase()] = headers[key];
|
|
|
|
return result;
|
|
|
|
}
|