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.
|
|
|
|
*/
|
|
|
|
|
2025-02-07 13:54:01 -08:00
|
|
|
import { assert, headersArrayToObject, headersObjectToArray } from '../../utils';
|
2020-08-24 06:51:51 -07:00
|
|
|
import * as network from '../network';
|
2025-02-07 13:54:01 -08:00
|
|
|
|
|
|
|
import type * as frames from '../frames';
|
2022-04-06 13:57:14 -08:00
|
|
|
import type * as types from '../types';
|
|
|
|
import type { Protocol } from './protocol';
|
|
|
|
import type { WKSession } from './wkConnection';
|
2025-02-07 13:54:01 -08:00
|
|
|
|
2020-01-21 14:58:12 -08:00
|
|
|
|
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',
|
|
|
|
};
|
|
|
|
|
2021-08-05 08:49:02 -07:00
|
|
|
export class WKInterceptableRequest {
|
2024-07-23 15:02:47 -07:00
|
|
|
private _session: WKSession;
|
|
|
|
private _requestId: string;
|
2020-01-21 14:58:12 -08:00
|
|
|
readonly request: network.Request;
|
2020-10-21 23:25:57 -07:00
|
|
|
_timestamp: number;
|
|
|
|
_wallTime: number;
|
2020-01-21 14:58:12 -08:00
|
|
|
|
2023-12-04 13:02:00 -08:00
|
|
|
constructor(session: WKSession, frame: frames.Frame, event: Protocol.Network.requestWillBeSentPayload, redirectedFrom: WKInterceptableRequest | null, documentId: string | undefined) {
|
2020-01-21 14:58:12 -08:00
|
|
|
this._session = session;
|
|
|
|
this._requestId = event.requestId;
|
2021-08-05 08:49:02 -07:00
|
|
|
const resourceType = event.type ? event.type.toLowerCase() : (redirectedFrom ? redirectedFrom.request.resourceType() : 'other');
|
2020-07-22 15:59:37 -07:00
|
|
|
let postDataBuffer = null;
|
2020-10-21 23:25:57 -07:00
|
|
|
this._timestamp = event.timestamp;
|
|
|
|
this._wallTime = event.walltime * 1000;
|
2020-07-22 15:59:37 -07:00
|
|
|
if (event.request.postData)
|
2020-12-17 18:09:06 -08:00
|
|
|
postDataBuffer = Buffer.from(event.request.postData, 'base64');
|
2025-04-30 18:57:59 -07:00
|
|
|
this.request = new network.Request(frame._page.browserContext, frame, null, redirectedFrom?.request || null, documentId, event.request.url,
|
2020-08-18 15:38:29 -07:00
|
|
|
resourceType, event.request.method, postDataBuffer, headersObjectToArray(event.request.headers));
|
2021-08-05 08:49:02 -07:00
|
|
|
}
|
|
|
|
|
2024-07-23 15:02:47 -07:00
|
|
|
adoptRequestFromNewProcess(newSession: WKSession, requestId: string) {
|
|
|
|
this._session = newSession;
|
|
|
|
this._requestId = requestId;
|
|
|
|
}
|
|
|
|
|
2021-08-05 08:49:02 -07:00
|
|
|
createResponse(responsePayload: Protocol.Network.Response): network.Response {
|
|
|
|
const getResponseBody = async () => {
|
|
|
|
const response = await this._session.send('Network.getResponseBody', { requestId: this._requestId });
|
|
|
|
return Buffer.from(response.body, response.base64Encoded ? 'base64' : 'utf8');
|
|
|
|
};
|
|
|
|
const timingPayload = responsePayload.timing;
|
|
|
|
const timing: network.ResourceTiming = {
|
|
|
|
startTime: this._wallTime,
|
|
|
|
domainLookupStart: timingPayload ? wkMillisToRoundishMillis(timingPayload.domainLookupStart) : -1,
|
|
|
|
domainLookupEnd: timingPayload ? wkMillisToRoundishMillis(timingPayload.domainLookupEnd) : -1,
|
|
|
|
connectStart: timingPayload ? wkMillisToRoundishMillis(timingPayload.connectStart) : -1,
|
|
|
|
secureConnectionStart: timingPayload ? wkMillisToRoundishMillis(timingPayload.secureConnectionStart) : -1,
|
|
|
|
connectEnd: timingPayload ? wkMillisToRoundishMillis(timingPayload.connectEnd) : -1,
|
|
|
|
requestStart: timingPayload ? wkMillisToRoundishMillis(timingPayload.requestStart) : -1,
|
|
|
|
responseStart: timingPayload ? wkMillisToRoundishMillis(timingPayload.responseStart) : -1,
|
|
|
|
};
|
2024-05-14 02:33:00 -07:00
|
|
|
const setCookieSeparator = process.platform === 'darwin' ? ',' : 'playwright-set-cookie-separator';
|
2022-06-24 13:51:09 -07:00
|
|
|
const response = new network.Response(this.request, responsePayload.status, responsePayload.statusText, headersObjectToArray(responsePayload.headers, ',', setCookieSeparator), timing, getResponseBody, responsePayload.source === 'service-worker');
|
2022-06-29 18:11:22 -07:00
|
|
|
|
2022-06-24 13:51:09 -07:00
|
|
|
// No raw response headers in WebKit, use "provisional" ones.
|
|
|
|
response.setRawResponseHeaders(null);
|
2022-06-29 18:11:22 -07:00
|
|
|
// Transfer size is not available in WebKit.
|
|
|
|
response.setTransferSize(null);
|
|
|
|
|
|
|
|
if (responsePayload.requestHeaders && Object.keys(responsePayload.requestHeaders).length) {
|
|
|
|
const headers = { ...responsePayload.requestHeaders };
|
|
|
|
if (!headers['host'])
|
|
|
|
headers['Host'] = new URL(this.request.url()).host;
|
|
|
|
this.request.setRawRequestHeaders(headersObjectToArray(headers));
|
|
|
|
} else {
|
2023-10-04 22:56:42 -04:00
|
|
|
// No raw headers available, use provisional ones.
|
2022-06-29 18:11:22 -07:00
|
|
|
this.request.setRawRequestHeaders(null);
|
|
|
|
}
|
2022-06-24 13:51:09 -07:00
|
|
|
return response;
|
2021-08-05 08:49:02 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export class WKRouteImpl implements network.RouteDelegate {
|
|
|
|
private readonly _session: WKSession;
|
|
|
|
private readonly _requestId: string;
|
|
|
|
|
2021-11-02 17:48:38 -07:00
|
|
|
constructor(session: WKSession, requestId: string) {
|
2021-08-05 08:49:02 -07:00
|
|
|
this._session = session;
|
|
|
|
this._requestId = requestId;
|
2020-01-21 14:58:12 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
async abort(errorCode: string) {
|
2020-06-17 08:34:42 -07:00
|
|
|
const errorType = errorReasons[errorCode];
|
|
|
|
assert(errorType, 'Unknown error code: ' + errorCode);
|
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.
|
2021-11-02 17:48:38 -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-11-17 16:56:04 -08:00
|
|
|
if (300 <= response.status && response.status < 400)
|
|
|
|
throw new Error('Cannot fulfill with redirect status: ' + response.status);
|
|
|
|
|
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-07-03 18:04:08 -07:00
|
|
|
let mimeType = response.isBase64 ? 'application/octet-stream' : 'text/plain';
|
2021-10-01 13:04:03 -07:00
|
|
|
const headers = headersArrayToObject(response.headers, true /* lowerCase */);
|
2020-07-15 13:21:21 -07:00
|
|
|
const contentType = headers['content-type'];
|
2020-07-03 18:04:08 -07:00
|
|
|
if (contentType)
|
|
|
|
mimeType = contentType.split(';')[0].trim();
|
2021-06-18 11:04:48 -07:00
|
|
|
|
2021-11-02 17:48:38 -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,
|
2024-05-17 09:32:40 -07:00
|
|
|
statusText: network.statusText(response.status),
|
2020-05-04 21:49:54 -07:00
|
|
|
mimeType,
|
2020-07-15 13:21:21 -07:00
|
|
|
headers,
|
2020-07-03 18:04:08 -07:00
|
|
|
base64Encoded: response.isBase64,
|
|
|
|
content: response.body
|
2020-01-21 14:58:12 -08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-08-28 08:24:44 -07:00
|
|
|
async continue(overrides: types.NormalizedContinueOverrides) {
|
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-11-16 09:59:00 -08:00
|
|
|
url: overrides.url,
|
2020-01-28 14:29:46 -08:00
|
|
|
method: overrides.method,
|
2020-08-18 15:38:29 -07:00
|
|
|
headers: overrides.headers ? headersArrayToObject(overrides.headers, false /* lowerCase */) : undefined,
|
2020-01-28 14:29:46 -08:00
|
|
|
postData: overrides.postData ? Buffer.from(overrides.postData).toString('base64') : undefined
|
2020-01-21 14:58:12 -08:00
|
|
|
});
|
2020-10-21 23:25:57 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function wkMillisToRoundishMillis(value: number): number {
|
|
|
|
// WebKit uses -1000 for unavailable.
|
|
|
|
if (value === -1000)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
// WebKit has a bug, instead of -1 it sends -1000 to be in ms.
|
2020-11-13 14:10:32 -08:00
|
|
|
if (value <= 0) {
|
2020-10-21 23:25:57 -07:00
|
|
|
// DNS can start before request start on Mac Network Stack
|
2020-11-13 14:10:32 -08:00
|
|
|
return -1;
|
2020-01-21 14:58:12 -08:00
|
|
|
}
|
2020-10-21 23:25:57 -07:00
|
|
|
|
|
|
|
return ((value * 1000) | 0) / 1000;
|
2020-01-21 14:58:12 -08:00
|
|
|
}
|