UNPKG

brave-real-playwright-core

Version:

Brave-optimized Playwright Core (v1.55.0) with comprehensive stealth patches and error stack sanitization

219 lines (218 loc) 8.13 kB
"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 httpServer_exports = {}; __export(httpServer_exports, { HttpServer: () => HttpServer }); module.exports = __toCommonJS(httpServer_exports); var import_fs = __toESM(require("fs")); var import_path = __toESM(require("path")); var import_utilsBundle = require("../../utilsBundle"); var import_crypto = require("./crypto"); var import_assert = require("../../utils/isomorphic/assert"); var import_manualPromise = require("../../utils/isomorphic/manualPromise"); var import_network = require("./network"); class HttpServer { constructor() { this._urlPrefixPrecise = ""; this._urlPrefixHumanReadable = ""; this._port = 0; this._started = false; this._routes = []; this._server = (0, import_network.createHttpServer)(this._onRequest.bind(this)); } server() { return this._server; } routePrefix(prefix, handler) { this._routes.push({ prefix, handler }); } routePath(path2, handler) { this._routes.push({ exact: path2, handler }); } port() { return this._port; } async _tryStart(port, host) { const errorPromise = new import_manualPromise.ManualPromise(); const errorListener = (error) => errorPromise.reject(error); this._server.on("error", errorListener); try { this._server.listen(port, host); await Promise.race([ new Promise((cb) => this._server.once("listening", cb)), errorPromise ]); } finally { this._server.removeListener("error", errorListener); } } createWebSocket(transport, guid) { (0, import_assert.assert)(!this._wsGuid, "can only create one main websocket transport per server"); this._wsGuid = guid || (0, import_crypto.createGuid)(); const wss = new import_utilsBundle.wsServer({ server: this._server, path: "/" + this._wsGuid }); wss.on("connection", (ws) => { transport.onconnect(); transport.sendEvent = (method, params) => ws.send(JSON.stringify({ method, params })); transport.close = () => ws.close(); ws.on("message", async (message) => { const { id, method, params } = JSON.parse(String(message)); try { const result = await transport.dispatch(method, params); ws.send(JSON.stringify({ id, result })); } catch (e) { ws.send(JSON.stringify({ id, error: String(e) })); } }); ws.on("close", () => transport.onclose()); ws.on("error", () => transport.onclose()); }); } wsGuid() { return this._wsGuid; } async start(options = {}) { (0, import_assert.assert)(!this._started, "server already started"); this._started = true; const host = options.host || "localhost"; if (options.preferredPort) { try { await this._tryStart(options.preferredPort, host); } catch (e) { if (!e || !e.message || !e.message.includes("EADDRINUSE")) throw e; await this._tryStart(void 0, host); } } else { await this._tryStart(options.port, host); } const address = this._server.address(); (0, import_assert.assert)(address, "Could not bind server socket"); if (typeof address === "string") { this._urlPrefixPrecise = address; this._urlPrefixHumanReadable = address; } else { this._port = address.port; const resolvedHost = address.family === "IPv4" ? address.address : `[${address.address}]`; this._urlPrefixPrecise = `http://${resolvedHost}:${address.port}`; this._urlPrefixHumanReadable = `http://${host}:${address.port}`; } } async stop() { await new Promise((cb) => this._server.close(cb)); } urlPrefix(purpose) { return purpose === "human-readable" ? this._urlPrefixHumanReadable : this._urlPrefixPrecise; } serveFile(request, response, absoluteFilePath, headers) { try { for (const [name, value] of Object.entries(headers || {})) response.setHeader(name, value); if (request.headers.range) this._serveRangeFile(request, response, absoluteFilePath); else this._serveFile(response, absoluteFilePath); return true; } catch (e) { return false; } } _serveFile(response, absoluteFilePath) { const content = import_fs.default.readFileSync(absoluteFilePath); response.statusCode = 200; const contentType = import_utilsBundle.mime.getType(import_path.default.extname(absoluteFilePath)) || "application/octet-stream"; response.setHeader("Content-Type", contentType); response.setHeader("Content-Length", content.byteLength); response.end(content); } _serveRangeFile(request, response, absoluteFilePath) { const range = request.headers.range; if (!range || !range.startsWith("bytes=") || range.includes(", ") || [...range].filter((char) => char === "-").length !== 1) { response.statusCode = 400; return response.end("Bad request"); } const [startStr, endStr] = range.replace(/bytes=/, "").split("-"); let start; let end; const size = import_fs.default.statSync(absoluteFilePath).size; if (startStr !== "" && endStr === "") { start = +startStr; end = size - 1; } else if (startStr === "" && endStr !== "") { start = size - +endStr; end = size - 1; } else { start = +startStr; end = +endStr; } if (Number.isNaN(start) || Number.isNaN(end) || start >= size || end >= size || start > end) { response.writeHead(416, { "Content-Range": `bytes */${size}` }); return response.end(); } response.writeHead(206, { "Content-Range": `bytes ${start}-${end}/${size}`, "Accept-Ranges": "bytes", "Content-Length": end - start + 1, "Content-Type": import_utilsBundle.mime.getType(import_path.default.extname(absoluteFilePath)) }); const readable = import_fs.default.createReadStream(absoluteFilePath, { start, end }); readable.pipe(response); } _onRequest(request, response) { if (request.method === "OPTIONS") { response.writeHead(200); response.end(); return; } request.on("error", () => response.end()); try { if (!request.url) { response.end(); return; } const url = new URL("http://localhost" + request.url); for (const route of this._routes) { if (route.exact && url.pathname === route.exact && route.handler(request, response)) return; if (route.prefix && url.pathname.startsWith(route.prefix) && route.handler(request, response)) return; } response.statusCode = 404; response.end(); } catch (e) { response.end(); } } } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { HttpServer });