brave-real-playwright-core
Version:
Brave-optimized Playwright Core (v1.55.0) with comprehensive stealth patches and error stack sanitization
318 lines (317 loc) • 12.9 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var bidiNetworkManager_exports = {};
__export(bidiNetworkManager_exports, {
BidiNetworkManager: () => BidiNetworkManager,
bidiBytesValueToString: () => bidiBytesValueToString
});
module.exports = __toCommonJS(bidiNetworkManager_exports);
var import_eventsHelper = require("../utils/eventsHelper");
var import_cookieStore = require("../cookieStore");
var network = __toESM(require("../network"));
var bidi = __toESM(require("./third_party/bidiProtocol"));
class BidiNetworkManager {
constructor(bidiSession, page) {
this._userRequestInterceptionEnabled = false;
this._protocolRequestInterceptionEnabled = false;
this._session = bidiSession;
this._requests = /* @__PURE__ */ new Map();
this._page = page;
this._eventListeners = [
import_eventsHelper.eventsHelper.addEventListener(bidiSession, "network.beforeRequestSent", this._onBeforeRequestSent.bind(this)),
import_eventsHelper.eventsHelper.addEventListener(bidiSession, "network.responseStarted", this._onResponseStarted.bind(this)),
import_eventsHelper.eventsHelper.addEventListener(bidiSession, "network.responseCompleted", this._onResponseCompleted.bind(this)),
import_eventsHelper.eventsHelper.addEventListener(bidiSession, "network.fetchError", this._onFetchError.bind(this)),
import_eventsHelper.eventsHelper.addEventListener(bidiSession, "network.authRequired", this._onAuthRequired.bind(this))
];
}
dispose() {
import_eventsHelper.eventsHelper.removeEventListeners(this._eventListeners);
}
_onBeforeRequestSent(param) {
if (param.request.url.startsWith("data:"))
return;
const redirectedFrom = param.redirectCount ? this._requests.get(param.request.request) || null : null;
const frame = redirectedFrom ? redirectedFrom.request.frame() : param.context ? this._page.frameManager.frame(param.context) : null;
if (!frame)
return;
if (redirectedFrom)
this._requests.delete(redirectedFrom._id);
let route;
if (param.intercepts) {
if (redirectedFrom) {
let params = {};
if (redirectedFrom._originalRequestRoute?._alreadyContinuedHeaders)
params = toBidiRequestHeaders(redirectedFrom._originalRequestRoute._alreadyContinuedHeaders ?? []);
this._session.sendMayFail("network.continueRequest", {
request: param.request.request,
...params
});
} else {
route = new BidiRouteImpl(this._session, param.request.request);
}
}
const request = new BidiRequest(frame, redirectedFrom, param, route);
this._requests.set(request._id, request);
this._page.frameManager.requestStarted(request.request, route);
}
_onResponseStarted(params) {
const request = this._requests.get(params.request.request);
if (!request)
return;
const getResponseBody = async () => {
throw new Error(`Response body is not available for requests in Bidi`);
};
const timings = params.request.timings;
const startTime = timings.requestTime;
function relativeToStart(time) {
if (!time)
return -1;
return time - startTime;
}
const timing = {
startTime,
requestStart: relativeToStart(timings.requestStart),
responseStart: relativeToStart(timings.responseStart),
domainLookupStart: relativeToStart(timings.dnsStart),
domainLookupEnd: relativeToStart(timings.dnsEnd),
connectStart: relativeToStart(timings.connectStart),
secureConnectionStart: relativeToStart(timings.tlsStart),
connectEnd: relativeToStart(timings.connectEnd)
};
const response = new network.Response(request.request, params.response.status, params.response.statusText, fromBidiHeaders(params.response.headers), timing, getResponseBody, false);
response._serverAddrFinished();
response._securityDetailsFinished();
response.setRawResponseHeaders(null);
response.setResponseHeadersSize(params.response.headersSize);
this._page.frameManager.requestReceivedResponse(response);
}
_onResponseCompleted(params) {
const request = this._requests.get(params.request.request);
if (!request)
return;
const response = request.request._existingResponse();
response.setTransferSize(params.response.bodySize);
response.setEncodedBodySize(params.response.bodySize);
const isRedirected = response.status() >= 300 && response.status() <= 399;
const responseEndTime = params.request.timings.responseEnd - response.timing().startTime;
if (isRedirected) {
response._requestFinished(responseEndTime);
} else {
this._requests.delete(request._id);
response._requestFinished(responseEndTime);
}
response._setHttpVersion(params.response.protocol);
this._page.frameManager.reportRequestFinished(request.request, response);
}
_onFetchError(params) {
const request = this._requests.get(params.request.request);
if (!request)
return;
this._requests.delete(request._id);
const response = request.request._existingResponse();
if (response) {
response.setTransferSize(null);
response.setEncodedBodySize(null);
response._requestFinished(-1);
}
request.request._setFailureText(params.errorText);
this._page.frameManager.requestFailed(request.request, params.errorText === "NS_BINDING_ABORTED");
}
_onAuthRequired(params) {
const isBasic = params.response.authChallenges?.some((challenge) => challenge.scheme.startsWith("Basic"));
const credentials = this._page.browserContext._options.httpCredentials;
if (isBasic && credentials) {
this._session.sendMayFail("network.continueWithAuth", {
request: params.request.request,
action: "provideCredentials",
credentials: {
type: "password",
username: credentials.username,
password: credentials.password
}
});
} else {
this._session.sendMayFail("network.continueWithAuth", {
request: params.request.request,
action: "default"
});
}
}
async setRequestInterception(value) {
this._userRequestInterceptionEnabled = value;
await this._updateProtocolRequestInterception();
}
async setCredentials(credentials) {
this._credentials = credentials;
await this._updateProtocolRequestInterception();
}
async _updateProtocolRequestInterception(initial) {
const enabled = this._userRequestInterceptionEnabled || !!this._credentials;
if (enabled === this._protocolRequestInterceptionEnabled)
return;
this._protocolRequestInterceptionEnabled = enabled;
if (initial && !enabled)
return;
const cachePromise = this._session.send("network.setCacheBehavior", { cacheBehavior: enabled ? "bypass" : "default" });
let interceptPromise = Promise.resolve(void 0);
if (enabled) {
interceptPromise = this._session.send("network.addIntercept", {
phases: [bidi.Network.InterceptPhase.AuthRequired, bidi.Network.InterceptPhase.BeforeRequestSent],
urlPatterns: [{ type: "pattern" }]
// urlPatterns: [{ type: 'string', pattern: '*' }],
}).then((r) => {
this._intercepId = r.intercept;
});
} else if (this._intercepId) {
interceptPromise = this._session.send("network.removeIntercept", { intercept: this._intercepId });
this._intercepId = void 0;
}
await Promise.all([cachePromise, interceptPromise]);
}
}
class BidiRequest {
constructor(frame, redirectedFrom, payload, route) {
this._id = payload.request.request;
if (redirectedFrom)
redirectedFrom._redirectedTo = this;
const postDataBuffer = null;
this.request = new network.Request(
frame._page.browserContext,
frame,
null,
redirectedFrom ? redirectedFrom.request : null,
payload.navigation ?? void 0,
payload.request.url,
"other",
payload.request.method,
postDataBuffer,
fromBidiHeaders(payload.request.headers)
);
this.request.setRawRequestHeaders(null);
this.request._setBodySize(payload.request.bodySize || 0);
this._originalRequestRoute = route ?? redirectedFrom?._originalRequestRoute;
route?._setRequest(this.request);
}
_finalRequest() {
let request = this;
while (request._redirectedTo)
request = request._redirectedTo;
return request;
}
}
class BidiRouteImpl {
constructor(session, requestId) {
this._session = session;
this._requestId = requestId;
}
_setRequest(request) {
this._request = request;
}
async continue(overrides) {
let headers = overrides.headers || this._request.headers();
if (overrides.postData && headers) {
headers = headers.map((header) => {
if (header.name.toLowerCase() === "content-length")
return { name: header.name, value: overrides.postData.byteLength.toString() };
return header;
});
}
this._alreadyContinuedHeaders = headers;
await this._session.sendMayFail("network.continueRequest", {
request: this._requestId,
url: overrides.url,
method: overrides.method,
...toBidiRequestHeaders(this._alreadyContinuedHeaders),
body: overrides.postData ? { type: "base64", value: Buffer.from(overrides.postData).toString("base64") } : void 0
});
}
async fulfill(response) {
const base64body = response.isBase64 ? response.body : Buffer.from(response.body).toString("base64");
await this._session.sendMayFail("network.provideResponse", {
request: this._requestId,
statusCode: response.status,
reasonPhrase: network.statusText(response.status),
...toBidiResponseHeaders(response.headers),
body: { type: "base64", value: base64body }
});
}
async abort(errorCode) {
await this._session.sendMayFail("network.failRequest", {
request: this._requestId
});
}
}
function fromBidiHeaders(bidiHeaders) {
const result = [];
for (const { name, value } of bidiHeaders)
result.push({ name, value: bidiBytesValueToString(value) });
return result;
}
function toBidiRequestHeaders(allHeaders) {
const bidiHeaders = toBidiHeaders(allHeaders);
return { headers: bidiHeaders };
}
function toBidiResponseHeaders(headers) {
const setCookieHeaders = headers.filter((h) => h.name.toLowerCase() === "set-cookie");
const otherHeaders = headers.filter((h) => h.name.toLowerCase() !== "set-cookie");
const rawCookies = setCookieHeaders.map((h) => (0, import_cookieStore.parseRawCookie)(h.value));
const cookies = rawCookies.filter(Boolean).map((c) => {
return {
...c,
value: { type: "string", value: c.value },
sameSite: toBidiSameSite(c.sameSite)
};
});
return { cookies, headers: toBidiHeaders(otherHeaders) };
}
function toBidiHeaders(headers) {
return headers.map(({ name, value }) => ({ name, value: { type: "string", value } }));
}
function bidiBytesValueToString(value) {
if (value.type === "string")
return value.value;
if (value.type === "base64")
return Buffer.from(value.type, "base64").toString("binary");
return "unknown value type: " + value.type;
}
function toBidiSameSite(sameSite) {
if (!sameSite)
return void 0;
if (sameSite === "Strict")
return bidi.Network.SameSite.Strict;
if (sameSite === "Lax")
return bidi.Network.SameSite.Lax;
return bidi.Network.SameSite.None;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
BidiNetworkManager,
bidiBytesValueToString
});