diff --git a/dist/anonymize_proxy.d.ts b/dist/anonymize_proxy.d.ts
new file mode 100644
index 00000000..32af82d0
--- /dev/null
+++ b/dist/anonymize_proxy.d.ts
@@ -0,0 +1,40 @@
+///
+///
+///
+///
+import type { Buffer } from "node:buffer";
+import type http from "node:http";
+import type net from "node:net";
+export interface AnonymizeProxyOptions {
+ url: string;
+ port: number;
+ ignoreProxyCertificate?: boolean;
+}
+/**
+ * Parses and validates a HTTP proxy URL. If the proxy requires authentication,
+ * or if it is an HTTPS proxy and `ignoreProxyCertificate` is `true`, then the function
+ * starts an open local proxy server that forwards to the upstream proxy.
+ */
+export declare const anonymizeProxy: (options: string | AnonymizeProxyOptions, callback?: ((error: Error | null) => void) | undefined) => Promise;
+/**
+ * Closes anonymous proxy previously started by `anonymizeProxy()`.
+ * If proxy was not found or was already closed, the function has no effect
+ * and its result if `false`. Otherwise the result is `true`.
+ * @param closeConnections If true, pending proxy connections are forcibly closed.
+ */
+export declare const closeAnonymizedProxy: (anonymizedProxyUrl: string, closeConnections: boolean, callback?: ((error: Error | null, result?: boolean) => void) | undefined) => Promise;
+type Callback = ({ response, socket, head, }: {
+ response: http.IncomingMessage;
+ socket: net.Socket;
+ head: Buffer;
+}) => void;
+/**
+ * Add a callback on 'tunnelConnectResponded' Event in order to get headers from CONNECT tunnel to proxy
+ * Useful for some proxies that are using headers to send information like ProxyMesh
+ * @returns `true` if the callback is successfully configured, otherwise `false` (e.g. when an
+ * invalid proxy URL is given).
+ */
+export declare const listenConnectAnonymizedProxy: (anonymizedProxyUrl: string, tunnelConnectRespondedCallback: Callback) => boolean;
+export declare const statisticsAnonymizedProxy: (anonymizedProxyUrl: string) => number;
+export {};
+//# sourceMappingURL=anonymize_proxy.d.ts.map
\ No newline at end of file
diff --git a/dist/anonymize_proxy.d.ts.map b/dist/anonymize_proxy.d.ts.map
new file mode 100644
index 00000000..63924a5d
--- /dev/null
+++ b/dist/anonymize_proxy.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"anonymize_proxy.d.ts","sourceRoot":"","sources":["../src/anonymize_proxy.ts"],"names":[],"mappings":";;;;AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAShC,MAAM,WAAW,qBAAqB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,sBAAsB,CAAC,EAAE,OAAO,CAAC;CACpC;AAED;;;;GAIG;AACH,eAAO,MAAM,cAAc,YACd,MAAM,GAAG,qBAAqB,sBACpB,KAAK,GAAG,IAAI,KAAK,IAAI,kBACzC,QAAQ,MAAM,CAwEhB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,uBACT,MAAM,oBACR,OAAO,sBACN,KAAK,GAAG,IAAI,WAAW,OAAO,KAAK,IAAI,kBAC3D,QAAQ,OAAO,CAgBjB,CAAC;AAEF,KAAK,QAAQ,GAAG,CAAC,EACb,QAAQ,EACR,MAAM,EACN,IAAI,GACP,EAAE;IACC,QAAQ,EAAE,IAAI,CAAC,eAAe,CAAC;IAC/B,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CAChB,KAAK,IAAI,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,uBACjB,MAAM,kCACM,QAAQ,KACzC,OASF,CAAC;AAEF,eAAO,MAAM,yBAAyB,uBACd,MAAM,KAC3B,MAOF,CAAC"}
\ No newline at end of file
diff --git a/dist/anonymize_proxy.js b/dist/anonymize_proxy.js
new file mode 100644
index 00000000..01e4f0d2
--- /dev/null
+++ b/dist/anonymize_proxy.js
@@ -0,0 +1,113 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.statisticsAnonymizedProxy = exports.listenConnectAnonymizedProxy = exports.closeAnonymizedProxy = exports.anonymizeProxy = void 0;
+const node_url_1 = require("node:url");
+const server_1 = require("./server");
+const nodeify_1 = require("./utils/nodeify");
+// Dictionary, key is value returned from anonymizeProxy(), value is Server instance.
+const anonymizedProxyUrlToServer = {};
+/**
+ * Parses and validates a HTTP proxy URL. If the proxy requires authentication,
+ * or if it is an HTTPS proxy and `ignoreProxyCertificate` is `true`, then the function
+ * starts an open local proxy server that forwards to the upstream proxy.
+ */
+const anonymizeProxy = async (options, callback) => {
+ let proxyUrl;
+ let port = 0;
+ let ignoreProxyCertificate = false;
+ if (typeof options === "string") {
+ proxyUrl = options;
+ }
+ else {
+ proxyUrl = options.url;
+ port = options.port;
+ if (port < 0 || port > 65535) {
+ throw new Error('Invalid "port" option: only values equals or between 0-65535 are valid');
+ }
+ if (options.ignoreProxyCertificate !== undefined) {
+ ignoreProxyCertificate = options.ignoreProxyCertificate;
+ }
+ }
+ const parsedProxyUrl = new node_url_1.URL(proxyUrl);
+ if (!["http:", "https:", ...server_1.SOCKS_PROTOCOLS].includes(parsedProxyUrl.protocol)) {
+ throw new Error(`Invalid "proxyUrl" provided: URL must have one of the following protocols: "http", "https", ${server_1.SOCKS_PROTOCOLS.map((p) => `"${p.replace(":", "")}"`).join(", ")} (was "${parsedProxyUrl}")`);
+ }
+ // If upstream proxy requires no password or if there is no need to ignore HTTPS proxy cert errors, return it directly
+ if (!parsedProxyUrl.username &&
+ !parsedProxyUrl.password &&
+ (!ignoreProxyCertificate || parsedProxyUrl.protocol !== "https:")) {
+ return (0, nodeify_1.nodeify)(Promise.resolve(proxyUrl), callback);
+ }
+ let server;
+ const startServer = async () => {
+ return Promise.resolve().then(async () => {
+ server = new server_1.Server({
+ // verbose: true,
+ port,
+ host: "127.0.0.1",
+ prepareRequestFunction: () => {
+ return {
+ requestAuthentication: false,
+ upstreamProxyUrl: proxyUrl,
+ ignoreUpstreamProxyCertificate: ignoreProxyCertificate,
+ };
+ },
+ });
+ return server.listen();
+ });
+ };
+ const promise = startServer().then(() => {
+ const url = `http://127.0.0.1:${server.port}`;
+ anonymizedProxyUrlToServer[url] = server;
+ return url;
+ });
+ return (0, nodeify_1.nodeify)(promise, callback);
+};
+exports.anonymizeProxy = anonymizeProxy;
+/**
+ * Closes anonymous proxy previously started by `anonymizeProxy()`.
+ * If proxy was not found or was already closed, the function has no effect
+ * and its result if `false`. Otherwise the result is `true`.
+ * @param closeConnections If true, pending proxy connections are forcibly closed.
+ */
+const closeAnonymizedProxy = async (anonymizedProxyUrl, closeConnections, callback) => {
+ if (typeof anonymizedProxyUrl !== "string") {
+ throw new Error('The "anonymizedProxyUrl" parameter must be a string');
+ }
+ const server = anonymizedProxyUrlToServer[anonymizedProxyUrl];
+ if (!server) {
+ return (0, nodeify_1.nodeify)(Promise.resolve(false), callback);
+ }
+ delete anonymizedProxyUrlToServer[anonymizedProxyUrl];
+ const promise = server.close(closeConnections).then(() => {
+ return true;
+ });
+ return (0, nodeify_1.nodeify)(promise, callback);
+};
+exports.closeAnonymizedProxy = closeAnonymizedProxy;
+/**
+ * Add a callback on 'tunnelConnectResponded' Event in order to get headers from CONNECT tunnel to proxy
+ * Useful for some proxies that are using headers to send information like ProxyMesh
+ * @returns `true` if the callback is successfully configured, otherwise `false` (e.g. when an
+ * invalid proxy URL is given).
+ */
+const listenConnectAnonymizedProxy = (anonymizedProxyUrl, tunnelConnectRespondedCallback) => {
+ const server = anonymizedProxyUrlToServer[anonymizedProxyUrl];
+ if (!server) {
+ return false;
+ }
+ server.on("tunnelConnectResponded", ({ response, socket, head }) => {
+ tunnelConnectRespondedCallback({ response, socket, head });
+ });
+ return true;
+};
+exports.listenConnectAnonymizedProxy = listenConnectAnonymizedProxy;
+const statisticsAnonymizedProxy = (anonymizedProxyUrl) => {
+ const server = anonymizedProxyUrlToServer[anonymizedProxyUrl];
+ if (!server) {
+ return 0;
+ }
+ return server.stats.trafficUsedInBytes;
+};
+exports.statisticsAnonymizedProxy = statisticsAnonymizedProxy;
+//# sourceMappingURL=anonymize_proxy.js.map
\ No newline at end of file
diff --git a/dist/anonymize_proxy.js.map b/dist/anonymize_proxy.js.map
new file mode 100644
index 00000000..757a516c
--- /dev/null
+++ b/dist/anonymize_proxy.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"anonymize_proxy.js","sourceRoot":"","sources":["../src/anonymize_proxy.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/dist/chain.d.ts b/dist/chain.d.ts
new file mode 100644
index 00000000..8dbeda7b
--- /dev/null
+++ b/dist/chain.d.ts
@@ -0,0 +1,38 @@
+///
+///
+///
+///
+///
+import type { Buffer } from 'node:buffer';
+import type dns from 'node:dns';
+import type { EventEmitter } from 'node:events';
+import type { URL } from 'node:url';
+import type { Socket } from './socket';
+export interface HandlerOpts {
+ upstreamProxyUrlParsed: URL;
+ ignoreUpstreamProxyCertificate: boolean;
+ localAddress?: string;
+ ipFamily?: number;
+ dnsLookup?: typeof dns['lookup'];
+ customTag?: unknown;
+}
+interface ChainOpts {
+ request: {
+ url?: string;
+ };
+ sourceSocket: Socket;
+ head?: Buffer;
+ handlerOpts: HandlerOpts;
+ server: EventEmitter & {
+ log: (connectionId: unknown, str: string) => void;
+ };
+ isPlain: boolean;
+}
+/**
+ * Passes the traffic to upstream HTTP proxy server.
+ * Client -> Apify -> Upstream -> Web
+ * Client <- Apify <- Upstream <- Web
+ */
+export declare const chain: ({ request, sourceSocket, head, handlerOpts, server, isPlain, }: ChainOpts) => void;
+export {};
+//# sourceMappingURL=chain.d.ts.map
\ No newline at end of file
diff --git a/dist/chain.d.ts.map b/dist/chain.d.ts.map
new file mode 100644
index 00000000..7e2a1c26
--- /dev/null
+++ b/dist/chain.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":";;;;;AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAEpC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAevC,MAAM,WAAW,WAAW;IACxB,sBAAsB,EAAE,GAAG,CAAC;IAC5B,8BAA8B,EAAE,OAAO,CAAC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,GAAG,CAAC,QAAQ,CAAC,CAAC;IACjC,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,UAAU,SAAS;IACf,OAAO,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,WAAW,CAAC;IACzB,MAAM,EAAE,YAAY,GAAG;QAAE,GAAG,EAAE,CAAC,YAAY,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;IAC7E,OAAO,EAAE,OAAO,CAAC;CACpB;AAED;;;;GAIG;AACH,eAAO,MAAM,KAAK,mEAQX,SAAS,KACb,IA4JF,CAAC"}
\ No newline at end of file
diff --git a/dist/chain.js b/dist/chain.js
new file mode 100644
index 00000000..fdb4c231
--- /dev/null
+++ b/dist/chain.js
@@ -0,0 +1,146 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.chain = void 0;
+const tslib_1 = require("tslib");
+const node_http_1 = tslib_1.__importDefault(require("node:http"));
+const node_https_1 = tslib_1.__importDefault(require("node:https"));
+const statuses_1 = require("./statuses");
+const count_target_bytes_1 = require("./utils/count_target_bytes");
+const get_basic_1 = require("./utils/get_basic");
+/**
+ * Passes the traffic to upstream HTTP proxy server.
+ * Client -> Apify -> Upstream -> Web
+ * Client <- Apify <- Upstream <- Web
+ */
+const chain = ({ request, sourceSocket, head, handlerOpts, server, isPlain, }) => {
+ if (head && head.length > 0) {
+ // HTTP/1.1 has no defined semantics when sending payload along with CONNECT and servers can reject the request.
+ // HTTP/2 only says that subsequent DATA frames must be transferred after HEADERS has been sent.
+ // HTTP/3 says that all DATA frames should be transferred (implies pre-HEADERS data).
+ //
+ // Let's go with the HTTP/3 behavior.
+ // There are also clients that send payload along with CONNECT to save milliseconds apparently.
+ // Beware of upstream proxy servers that send out valid CONNECT responses with diagnostic data such as IPs!
+ sourceSocket.unshift(head);
+ }
+ const { proxyChainId } = sourceSocket;
+ const { upstreamProxyUrlParsed: proxy, customTag } = handlerOpts;
+ const options = {
+ method: 'CONNECT',
+ path: request.url,
+ headers: {
+ host: request.url,
+ },
+ localAddress: handlerOpts.localAddress,
+ family: handlerOpts.ipFamily,
+ lookup: handlerOpts.dnsLookup,
+ };
+ if (proxy.username || proxy.password) {
+ options.headers['proxy-authorization'] = (0, get_basic_1.getBasicAuthorizationHeader)(proxy);
+ }
+ const client = proxy.protocol === 'https:'
+ ? node_https_1.default.request(proxy.origin, {
+ ...options,
+ rejectUnauthorized: !handlerOpts.ignoreUpstreamProxyCertificate,
+ })
+ : node_http_1.default.request(proxy.origin, options);
+ client.once('socket', (targetSocket) => {
+ // Socket can be re-used by multiple requests.
+ // That's why we need to track the previous stats.
+ targetSocket.previousBytesRead = targetSocket.bytesRead;
+ targetSocket.previousBytesWritten = targetSocket.bytesWritten;
+ (0, count_target_bytes_1.countTargetBytes)(sourceSocket, targetSocket);
+ });
+ client.on('connect', (response, targetSocket, clientHead) => {
+ if (sourceSocket.readyState !== 'open') {
+ // Sanity check, should never reach.
+ targetSocket.destroy();
+ return;
+ }
+ targetSocket.on('error', (error) => {
+ server.log(proxyChainId, `Chain Destination Socket Error: ${error.stack}`);
+ sourceSocket.destroy();
+ });
+ sourceSocket.on('error', (error) => {
+ server.log(proxyChainId, `Chain Source Socket Error: ${error.stack}`);
+ targetSocket.destroy();
+ });
+ if (response.statusCode !== 200) {
+ server.log(proxyChainId, `Failed to authenticate upstream proxy: ${response.statusCode}`);
+ if (isPlain) {
+ sourceSocket.end();
+ }
+ else {
+ const { statusCode } = response;
+ const status = statusCode === 401 || statusCode === 407
+ ? statuses_1.badGatewayStatusCodes.AUTH_FAILED
+ : statuses_1.badGatewayStatusCodes.NON_200;
+ sourceSocket.end((0, statuses_1.createCustomStatusHttpResponse)(status, `UPSTREAM${statusCode}`));
+ }
+ targetSocket.end();
+ server.emit('tunnelConnectFailed', {
+ proxyChainId,
+ response,
+ customTag,
+ socket: targetSocket,
+ head: clientHead,
+ });
+ return;
+ }
+ if (clientHead.length > 0) {
+ // See comment above
+ targetSocket.unshift(clientHead);
+ }
+ server.emit('tunnelConnectResponded', {
+ proxyChainId,
+ response,
+ customTag,
+ socket: targetSocket,
+ head: clientHead,
+ });
+ sourceSocket.write(isPlain ? '' : `HTTP/1.1 200 Connection Established\r\n\r\n`);
+ sourceSocket.pipe(targetSocket);
+ targetSocket.pipe(sourceSocket);
+ // Once target socket closes forcibly, the source socket gets paused.
+ // We need to enable flowing, otherwise the socket would remain open indefinitely.
+ // Nothing would consume the data, we just want to close the socket.
+ targetSocket.on('close', () => {
+ sourceSocket.resume();
+ if (sourceSocket.writable) {
+ sourceSocket.end();
+ }
+ });
+ // Same here.
+ sourceSocket.on('close', () => {
+ targetSocket.resume();
+ if (targetSocket.writable) {
+ targetSocket.end();
+ }
+ });
+ });
+ client.on('error', (error) => {
+ var _a, _b;
+ server.log(proxyChainId, `Failed to connect to upstream proxy: ${error.stack}`);
+ // The end socket may get connected after the client to proxy one gets disconnected.
+ if (sourceSocket.readyState === 'open') {
+ if (isPlain) {
+ sourceSocket.end();
+ }
+ else {
+ const statusCode = (_a = statuses_1.errorCodeToStatusCode[error.code]) !== null && _a !== void 0 ? _a : statuses_1.badGatewayStatusCodes.GENERIC_ERROR;
+ const response = (0, statuses_1.createCustomStatusHttpResponse)(statusCode, (_b = error.code) !== null && _b !== void 0 ? _b : 'Upstream Closed Early');
+ sourceSocket.end(response);
+ }
+ }
+ });
+ sourceSocket.on('error', () => {
+ client.destroy();
+ });
+ // In case the client ends the socket too early
+ sourceSocket.on('close', () => {
+ client.destroy();
+ });
+ client.end();
+};
+exports.chain = chain;
+//# sourceMappingURL=chain.js.map
\ No newline at end of file
diff --git a/dist/chain.js.map b/dist/chain.js.map
new file mode 100644
index 00000000..8b9a749d
--- /dev/null
+++ b/dist/chain.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"chain.js","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/dist/chain_socks.d.ts b/dist/chain_socks.d.ts
new file mode 100644
index 00000000..ed9179f8
--- /dev/null
+++ b/dist/chain_socks.d.ts
@@ -0,0 +1,30 @@
+///
+///
+///
+///
+///
+import type { Buffer } from 'node:buffer';
+import type { EventEmitter } from 'node:events';
+import type http from 'node:http';
+import { URL } from 'node:url';
+import type { Socket } from './socket';
+export interface HandlerOpts {
+ upstreamProxyUrlParsed: URL;
+ customTag?: unknown;
+}
+interface ChainSocksOpts {
+ request: http.IncomingMessage;
+ sourceSocket: Socket;
+ head: Buffer;
+ server: EventEmitter & {
+ log: (connectionId: unknown, str: string) => void;
+ };
+ handlerOpts: HandlerOpts;
+}
+/**
+ * Client -> Apify (CONNECT) -> Upstream (SOCKS) -> Web
+ * Client <- Apify (CONNECT) <- Upstream (SOCKS) <- Web
+ */
+export declare const chainSocks: ({ request, sourceSocket, head, server, handlerOpts, }: ChainSocksOpts) => Promise;
+export {};
+//# sourceMappingURL=chain_socks.d.ts.map
\ No newline at end of file
diff --git a/dist/chain_socks.d.ts.map b/dist/chain_socks.d.ts.map
new file mode 100644
index 00000000..47890f3b
--- /dev/null
+++ b/dist/chain_socks.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"chain_socks.d.ts","sourceRoot":"","sources":["../src/chain_socks.ts"],"names":[],"mappings":";;;;;AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAI/B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAIvC,MAAM,WAAW,WAAW;IACxB,sBAAsB,EAAE,GAAG,CAAC;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,UAAU,cAAc;IACpB,OAAO,EAAE,IAAI,CAAC,eAAe,CAAC;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,YAAY,GAAG;QAAE,GAAG,EAAE,CAAC,YAAY,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;IAC7E,WAAW,EAAE,WAAW,CAAC;CAC5B;AAYD;;;GAGG;AACH,eAAO,MAAM,UAAU,0DAMpB,cAAc,KAAG,QAAQ,IAAI,CAoF/B,CAAC"}
\ No newline at end of file
diff --git a/dist/chain_socks.js b/dist/chain_socks.js
new file mode 100644
index 00000000..f5707a53
--- /dev/null
+++ b/dist/chain_socks.js
@@ -0,0 +1,91 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.chainSocks = void 0;
+const node_url_1 = require("node:url");
+const socks_1 = require("socks");
+const statuses_1 = require("./statuses");
+const count_target_bytes_1 = require("./utils/count_target_bytes");
+const socksProtocolToVersionNumber = (protocol) => {
+ switch (protocol) {
+ case 'socks4:':
+ case 'socks4a:':
+ return 4;
+ default:
+ return 5;
+ }
+};
+/**
+ * Client -> Apify (CONNECT) -> Upstream (SOCKS) -> Web
+ * Client <- Apify (CONNECT) <- Upstream (SOCKS) <- Web
+ */
+const chainSocks = async ({ request, sourceSocket, head, server, handlerOpts, }) => {
+ const { proxyChainId } = sourceSocket;
+ const { hostname, port, username, password } = handlerOpts.upstreamProxyUrlParsed;
+ const proxy = {
+ host: hostname,
+ port: Number(port),
+ type: socksProtocolToVersionNumber(handlerOpts.upstreamProxyUrlParsed.protocol),
+ userId: decodeURIComponent(username),
+ password: decodeURIComponent(password),
+ };
+ if (head && head.length > 0) {
+ // HTTP/1.1 has no defined semantics when sending payload along with CONNECT and servers can reject the request.
+ // HTTP/2 only says that subsequent DATA frames must be transferred after HEADERS has been sent.
+ // HTTP/3 says that all DATA frames should be transferred (implies pre-HEADERS data).
+ //
+ // Let's go with the HTTP/3 behavior.
+ // There are also clients that send payload along with CONNECT to save milliseconds apparently.
+ // Beware of upstream proxy servers that send out valid CONNECT responses with diagnostic data such as IPs!
+ sourceSocket.unshift(head);
+ }
+ const url = new node_url_1.URL(`connect://${request.url}`);
+ const destination = {
+ port: Number(url.port),
+ host: url.hostname,
+ };
+ let targetSocket;
+ try {
+ const client = await socks_1.SocksClient.createConnection({
+ proxy,
+ command: 'connect',
+ destination,
+ });
+ targetSocket = client.socket;
+ sourceSocket.write(`HTTP/1.1 200 Connection Established\r\n\r\n`);
+ }
+ catch (error) {
+ const socksError = error;
+ server.log(proxyChainId, `Failed to connect to upstream SOCKS proxy ${socksError.stack}`);
+ sourceSocket.end((0, statuses_1.createCustomStatusHttpResponse)((0, statuses_1.socksErrorMessageToStatusCode)(socksError.message), socksError.message));
+ return;
+ }
+ (0, count_target_bytes_1.countTargetBytes)(sourceSocket, targetSocket);
+ sourceSocket.pipe(targetSocket);
+ targetSocket.pipe(sourceSocket);
+ // Once target socket closes forcibly, the source socket gets paused.
+ // We need to enable flowing, otherwise the socket would remain open indefinitely.
+ // Nothing would consume the data, we just want to close the socket.
+ targetSocket.on('close', () => {
+ sourceSocket.resume();
+ if (sourceSocket.writable) {
+ sourceSocket.end();
+ }
+ });
+ // Same here.
+ sourceSocket.on('close', () => {
+ targetSocket.resume();
+ if (targetSocket.writable) {
+ targetSocket.end();
+ }
+ });
+ targetSocket.on('error', (error) => {
+ server.log(proxyChainId, `Chain SOCKS Destination Socket Error: ${error.stack}`);
+ sourceSocket.destroy();
+ });
+ sourceSocket.on('error', (error) => {
+ server.log(proxyChainId, `Chain SOCKS Source Socket Error: ${error.stack}`);
+ targetSocket.destroy();
+ });
+};
+exports.chainSocks = chainSocks;
+//# sourceMappingURL=chain_socks.js.map
\ No newline at end of file
diff --git a/dist/chain_socks.js.map b/dist/chain_socks.js.map
new file mode 100644
index 00000000..c877f60b
--- /dev/null
+++ b/dist/chain_socks.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"chain_socks.js","sourceRoot":"","sources":["../src/chain_socks.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/dist/custom_connect.d.ts b/dist/custom_connect.d.ts
new file mode 100644
index 00000000..6ddfaaf0
--- /dev/null
+++ b/dist/custom_connect.d.ts
@@ -0,0 +1,4 @@
+import type http from 'node:http';
+import type net from 'node:net';
+export declare const customConnect: (socket: net.Socket, server: http.Server) => Promise;
+//# sourceMappingURL=custom_connect.d.ts.map
\ No newline at end of file
diff --git a/dist/custom_connect.d.ts.map b/dist/custom_connect.d.ts.map
new file mode 100644
index 00000000..eabb7431
--- /dev/null
+++ b/dist/custom_connect.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"custom_connect.d.ts","sourceRoot":"","sources":["../src/custom_connect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAGhC,eAAO,MAAM,aAAa,WAAkB,IAAI,MAAM,UAAU,KAAK,MAAM,KAAG,QAAQ,IAAI,CAqBzF,CAAC"}
\ No newline at end of file
diff --git a/dist/custom_connect.js b/dist/custom_connect.js
new file mode 100644
index 00000000..0f71d3d4
--- /dev/null
+++ b/dist/custom_connect.js
@@ -0,0 +1,25 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.customConnect = void 0;
+const node_util_1 = require("node:util");
+const customConnect = async (socket, server) => {
+ // `countTargetBytes(socket, socket)` is incorrect here since `socket` is not a target.
+ // We would have to create a new stream and pipe traffic through that,
+ // however this would also increase CPU usage.
+ // Also, counting bytes here is not correct since we don't know how the response is generated
+ // (whether any additional sockets are used).
+ const asyncWrite = (0, node_util_1.promisify)(socket.write).bind(socket);
+ await asyncWrite('HTTP/1.1 200 Connection Established\r\n\r\n');
+ server.emit('connection', socket);
+ return new Promise((resolve) => {
+ if (socket.destroyed) {
+ resolve();
+ return;
+ }
+ socket.once('close', () => {
+ resolve();
+ });
+ });
+};
+exports.customConnect = customConnect;
+//# sourceMappingURL=custom_connect.js.map
\ No newline at end of file
diff --git a/dist/custom_connect.js.map b/dist/custom_connect.js.map
new file mode 100644
index 00000000..6300472a
--- /dev/null
+++ b/dist/custom_connect.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"custom_connect.js","sourceRoot":"","sources":["../src/custom_connect.ts"],"names":[],"mappings":";;;AAEA,yCAAsC;AAE/B,MAAM,aAAa,GAAG,KAAK,EAAE,MAAkB,EAAE,MAAmB,EAAiB,EAAE;IAC1F,uFAAuF;IACvF,sEAAsE;IACtE,8CAA8C;IAC9C,6FAA6F;IAC7F,6CAA6C;IAE7C,MAAM,UAAU,GAAG,IAAA,qBAAS,EAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACxD,MAAM,UAAU,CAAC,6CAA6C,CAAC,CAAC;IAChE,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAElC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC3B,IAAI,MAAM,CAAC,SAAS,EAAE;YAClB,OAAO,EAAE,CAAC;YACV,OAAO;SACV;QAED,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE;YACtB,OAAO,EAAE,CAAC;QACd,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC,CAAC;AArBW,QAAA,aAAa,iBAqBxB"}
\ No newline at end of file
diff --git a/dist/custom_response.d.ts b/dist/custom_response.d.ts
new file mode 100644
index 00000000..0574e261
--- /dev/null
+++ b/dist/custom_response.d.ts
@@ -0,0 +1,15 @@
+///
+///
+import type { Buffer } from 'node:buffer';
+import type http from 'node:http';
+export interface CustomResponse {
+ statusCode?: number;
+ headers?: Record;
+ body?: string | Buffer;
+ encoding?: BufferEncoding;
+}
+export interface HandlerOpts {
+ customResponseFunction: () => CustomResponse | Promise;
+}
+export declare const handleCustomResponse: (_request: http.IncomingMessage, response: http.ServerResponse, handlerOpts: HandlerOpts) => Promise;
+//# sourceMappingURL=custom_response.d.ts.map
\ No newline at end of file
diff --git a/dist/custom_response.d.ts.map b/dist/custom_response.d.ts.map
new file mode 100644
index 00000000..6ac920af
--- /dev/null
+++ b/dist/custom_response.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"custom_response.d.ts","sourceRoot":"","sources":["../src/custom_response.ts"],"names":[],"mappings":";;AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,MAAM,WAAW,cAAc;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC7B;AAED,MAAM,WAAW,WAAW;IACxB,sBAAsB,EAAE,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAC1E;AAED,eAAO,MAAM,oBAAoB,aACnB,KAAK,eAAe,YACpB,KAAK,cAAc,eAChB,WAAW,KACzB,QAAQ,IAAI,CAqBd,CAAC"}
\ No newline at end of file
diff --git a/dist/custom_response.js b/dist/custom_response.js
new file mode 100644
index 00000000..17a6d823
--- /dev/null
+++ b/dist/custom_response.js
@@ -0,0 +1,22 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.handleCustomResponse = void 0;
+const handleCustomResponse = async (_request, response, handlerOpts) => {
+ const { customResponseFunction } = handlerOpts;
+ if (!customResponseFunction) {
+ throw new Error('The "customResponseFunction" option is required');
+ }
+ const customResponse = await customResponseFunction();
+ if (typeof customResponse !== 'object' || customResponse === null) {
+ throw new Error('The user-provided "customResponseFunction" must return an object.');
+ }
+ response.statusCode = customResponse.statusCode || 200;
+ if (customResponse.headers) {
+ for (const [key, value] of Object.entries(customResponse.headers)) {
+ response.setHeader(key, value);
+ }
+ }
+ response.end(customResponse.body, customResponse.encoding);
+};
+exports.handleCustomResponse = handleCustomResponse;
+//# sourceMappingURL=custom_response.js.map
\ No newline at end of file
diff --git a/dist/custom_response.js.map b/dist/custom_response.js.map
new file mode 100644
index 00000000..e59c4ace
--- /dev/null
+++ b/dist/custom_response.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"custom_response.js","sourceRoot":"","sources":["../src/custom_response.ts"],"names":[],"mappings":";;;AAcO,MAAM,oBAAoB,GAAG,KAAK,EACrC,QAA8B,EAC9B,QAA6B,EAC7B,WAAwB,EACX,EAAE;IACf,MAAM,EAAE,sBAAsB,EAAE,GAAG,WAAW,CAAC;IAC/C,IAAI,CAAC,sBAAsB,EAAE;QACzB,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;KACtE;IAED,MAAM,cAAc,GAAG,MAAM,sBAAsB,EAAE,CAAC;IAEtD,IAAI,OAAO,cAAc,KAAK,QAAQ,IAAI,cAAc,KAAK,IAAI,EAAE;QAC/D,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;KACxF;IAED,QAAQ,CAAC,UAAU,GAAG,cAAc,CAAC,UAAU,IAAI,GAAG,CAAC;IAEvD,IAAI,cAAc,CAAC,OAAO,EAAE;QACxB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE;YAC/D,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE,KAAe,CAAC,CAAC;SAC5C;KACJ;IAED,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,cAAc,CAAC,QAAS,CAAC,CAAC;AAChE,CAAC,CAAC;AAzBW,QAAA,oBAAoB,wBAyB/B"}
\ No newline at end of file
diff --git a/dist/direct.d.ts b/dist/direct.d.ts
new file mode 100644
index 00000000..4eea4bfc
--- /dev/null
+++ b/dist/direct.d.ts
@@ -0,0 +1,32 @@
+///
+///
+///
+///
+import type { Buffer } from 'node:buffer';
+import type dns from 'node:dns';
+import type { EventEmitter } from 'node:events';
+import type { Socket } from './socket';
+export interface HandlerOpts {
+ localAddress?: string;
+ ipFamily?: number;
+ dnsLookup?: typeof dns['lookup'];
+}
+interface DirectOpts {
+ request: {
+ url?: string;
+ };
+ sourceSocket: Socket;
+ head: Buffer;
+ server: EventEmitter & {
+ log: (connectionId: unknown, str: string) => void;
+ };
+ handlerOpts: HandlerOpts;
+}
+/**
+ * Directly connects to the target.
+ * Client -> Apify (CONNECT) -> Web
+ * Client <- Apify (CONNECT) <- Web
+ */
+export declare const direct: ({ request, sourceSocket, head, server, handlerOpts, }: DirectOpts) => void;
+export {};
+//# sourceMappingURL=direct.d.ts.map
\ No newline at end of file
diff --git a/dist/direct.d.ts.map b/dist/direct.d.ts.map
new file mode 100644
index 00000000..b6aa71d2
--- /dev/null
+++ b/dist/direct.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"direct.d.ts","sourceRoot":"","sources":["../src/direct.ts"],"names":[],"mappings":";;;;AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIhD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGvC,MAAM,WAAW,WAAW;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,GAAG,CAAC,QAAQ,CAAC,CAAC;CACpC;AAED,UAAU,UAAU;IAChB,OAAO,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,YAAY,GAAG;QAAE,GAAG,EAAE,CAAC,YAAY,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;IAC7E,WAAW,EAAE,WAAW,CAAC;CAC5B;AAED;;;;GAIG;AACH,eAAO,MAAM,MAAM,0DAOZ,UAAU,KACd,IA0EF,CAAC"}
\ No newline at end of file
diff --git a/dist/direct.js b/dist/direct.js
new file mode 100644
index 00000000..83441ce8
--- /dev/null
+++ b/dist/direct.js
@@ -0,0 +1,73 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.direct = void 0;
+const tslib_1 = require("tslib");
+const node_net_1 = tslib_1.__importDefault(require("node:net"));
+const node_url_1 = require("node:url");
+const count_target_bytes_1 = require("./utils/count_target_bytes");
+/**
+ * Directly connects to the target.
+ * Client -> Apify (CONNECT) -> Web
+ * Client <- Apify (CONNECT) <- Web
+ */
+const direct = ({ request, sourceSocket, head, server, handlerOpts, }) => {
+ const url = new node_url_1.URL(`connect://${request.url}`);
+ if (!url.hostname) {
+ throw new Error('Missing CONNECT hostname');
+ }
+ if (!url.port) {
+ throw new Error('Missing CONNECT port');
+ }
+ if (head.length > 0) {
+ // See comment in chain.ts
+ sourceSocket.unshift(head);
+ }
+ const options = {
+ port: Number(url.port),
+ host: url.hostname,
+ localAddress: handlerOpts.localAddress,
+ family: handlerOpts.ipFamily,
+ lookup: handlerOpts.dnsLookup,
+ };
+ if (options.host[0] === '[') {
+ options.host = options.host.slice(1, -1);
+ }
+ const targetSocket = node_net_1.default.createConnection(options, () => {
+ try {
+ sourceSocket.write(`HTTP/1.1 200 Connection Established\r\n\r\n`);
+ }
+ catch (error) {
+ sourceSocket.destroy(error);
+ }
+ });
+ (0, count_target_bytes_1.countTargetBytes)(sourceSocket, targetSocket);
+ sourceSocket.pipe(targetSocket);
+ targetSocket.pipe(sourceSocket);
+ // Once target socket closes forcibly, the source socket gets paused.
+ // We need to enable flowing, otherwise the socket would remain open indefinitely.
+ // Nothing would consume the data, we just want to close the socket.
+ targetSocket.on('close', () => {
+ sourceSocket.resume();
+ if (sourceSocket.writable) {
+ sourceSocket.end();
+ }
+ });
+ // Same here.
+ sourceSocket.on('close', () => {
+ targetSocket.resume();
+ if (targetSocket.writable) {
+ targetSocket.end();
+ }
+ });
+ const { proxyChainId } = sourceSocket;
+ targetSocket.on('error', (error) => {
+ server.log(proxyChainId, `Direct Destination Socket Error: ${error.stack}`);
+ sourceSocket.destroy();
+ });
+ sourceSocket.on('error', (error) => {
+ server.log(proxyChainId, `Direct Source Socket Error: ${error.stack}`);
+ targetSocket.destroy();
+ });
+};
+exports.direct = direct;
+//# sourceMappingURL=direct.js.map
\ No newline at end of file
diff --git a/dist/direct.js.map b/dist/direct.js.map
new file mode 100644
index 00000000..60973329
--- /dev/null
+++ b/dist/direct.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"direct.js","sourceRoot":"","sources":["../src/direct.ts"],"names":[],"mappings":";;;;AAGA,gEAA2B;AAC3B,uCAA+B;AAG/B,mEAA8D;AAgB9D;;;;GAIG;AACI,MAAM,MAAM,GAAG,CAClB,EACI,OAAO,EACP,YAAY,EACZ,IAAI,EACJ,MAAM,EACN,WAAW,GACF,EACT,EAAE;IACN,MAAM,GAAG,GAAG,IAAI,cAAG,CAAC,aAAa,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAEhD,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE;QACf,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;KAC/C;IAED,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE;QACX,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;KAC3C;IAED,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;QACjB,0BAA0B;QAC1B,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;KAC9B;IAED,MAAM,OAAO,GAAG;QACZ,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;QACtB,IAAI,EAAE,GAAG,CAAC,QAAQ;QAClB,YAAY,EAAE,WAAW,CAAC,YAAY;QACtC,MAAM,EAAE,WAAW,CAAC,QAAQ;QAC5B,MAAM,EAAE,WAAW,CAAC,SAAS;KAChC,CAAC;IAEF,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE;QACzB,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;KAC5C;IAED,MAAM,YAAY,GAAG,kBAAG,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;QACpD,IAAI;YACA,YAAY,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;SACrE;QAAC,OAAO,KAAK,EAAE;YACZ,YAAY,CAAC,OAAO,CAAC,KAAc,CAAC,CAAC;SACxC;IACL,CAAC,CAAC,CAAC;IAEH,IAAA,qCAAgB,EAAC,YAAY,EAAE,YAAY,CAAC,CAAC;IAE7C,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAChC,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAEhC,qEAAqE;IACrE,kFAAkF;IAClF,oEAAoE;IACpE,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QAC1B,YAAY,CAAC,MAAM,EAAE,CAAC;QAEtB,IAAI,YAAY,CAAC,QAAQ,EAAE;YACvB,YAAY,CAAC,GAAG,EAAE,CAAC;SACtB;IACL,CAAC,CAAC,CAAC;IAEH,aAAa;IACb,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QAC1B,YAAY,CAAC,MAAM,EAAE,CAAC;QAEtB,IAAI,YAAY,CAAC,QAAQ,EAAE;YACvB,YAAY,CAAC,GAAG,EAAE,CAAC;SACtB;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,EAAE,YAAY,EAAE,GAAG,YAAY,CAAC;IAEtC,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;QAC/B,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,oCAAoC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;QAE5E,YAAY,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;QAC/B,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,+BAA+B,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;QAEvE,YAAY,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;AACP,CAAC,CAAC;AAlFW,QAAA,MAAM,UAkFjB"}
\ No newline at end of file
diff --git a/dist/forward.d.ts b/dist/forward.d.ts
new file mode 100644
index 00000000..01eeab3f
--- /dev/null
+++ b/dist/forward.d.ts
@@ -0,0 +1,31 @@
+///
+///
+import type dns from 'node:dns';
+import http from 'node:http';
+import type { URL } from 'node:url';
+export interface HandlerOpts {
+ upstreamProxyUrlParsed: URL;
+ ignoreUpstreamProxyCertificate: boolean;
+ localAddress?: string;
+ ipFamily?: number;
+ dnsLookup?: typeof dns['lookup'];
+}
+/**
+ * The request is read from the client and is resent.
+ * This is similar to Direct / Chain, however it uses the CONNECT protocol instead.
+ * Forward uses standard HTTP methods.
+ *
+ * ```
+ * Client -> Apify (HTTP) -> Web
+ * Client <- Apify (HTTP) <- Web
+ * ```
+ *
+ * or
+ *
+ * ```
+ * Client -> Apify (HTTP) -> Upstream (HTTP) -> Web
+ * Client <- Apify (HTTP) <- Upstream (HTTP) <- Web
+ * ```
+ */
+export declare const forward: (request: http.IncomingMessage, response: http.ServerResponse, handlerOpts: HandlerOpts) => Promise;
+//# sourceMappingURL=forward.d.ts.map
\ No newline at end of file
diff --git a/dist/forward.d.ts.map b/dist/forward.d.ts.map
new file mode 100644
index 00000000..460f90fc
--- /dev/null
+++ b/dist/forward.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"forward.d.ts","sourceRoot":"","sources":["../src/forward.ts"],"names":[],"mappings":";;AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAqBpC,MAAM,WAAW,WAAW;IACxB,sBAAsB,EAAE,GAAG,CAAC;IAC5B,8BAA8B,EAAE,OAAO,CAAC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,GAAG,CAAC,QAAQ,CAAC,CAAC;CACpC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,OAAO,YACP,KAAK,eAAe,YACnB,KAAK,cAAc,eAChB,WAAW,KAEzB,QAAQ,IAAI,CA4Fb,CAAC"}
\ No newline at end of file
diff --git a/dist/forward.js b/dist/forward.js
new file mode 100644
index 00000000..1a8b96ef
--- /dev/null
+++ b/dist/forward.js
@@ -0,0 +1,106 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.forward = void 0;
+const tslib_1 = require("tslib");
+const node_http_1 = tslib_1.__importDefault(require("node:http"));
+const node_https_1 = tslib_1.__importDefault(require("node:https"));
+const node_stream_1 = tslib_1.__importDefault(require("node:stream"));
+const node_util_1 = tslib_1.__importDefault(require("node:util"));
+const statuses_1 = require("./statuses");
+const count_target_bytes_1 = require("./utils/count_target_bytes");
+const get_basic_1 = require("./utils/get_basic");
+const valid_headers_only_1 = require("./utils/valid_headers_only");
+const pipeline = node_util_1.default.promisify(node_stream_1.default.pipeline);
+/**
+ * The request is read from the client and is resent.
+ * This is similar to Direct / Chain, however it uses the CONNECT protocol instead.
+ * Forward uses standard HTTP methods.
+ *
+ * ```
+ * Client -> Apify (HTTP) -> Web
+ * Client <- Apify (HTTP) <- Web
+ * ```
+ *
+ * or
+ *
+ * ```
+ * Client -> Apify (HTTP) -> Upstream (HTTP) -> Web
+ * Client <- Apify (HTTP) <- Upstream (HTTP) <- Web
+ * ```
+ */
+const forward = async (request, response, handlerOpts) => new Promise(async (resolve, reject) => {
+ const proxy = handlerOpts.upstreamProxyUrlParsed;
+ const origin = proxy ? proxy.origin : request.url;
+ const options = {
+ method: request.method,
+ headers: (0, valid_headers_only_1.validHeadersOnly)(request.rawHeaders),
+ insecureHTTPParser: true,
+ localAddress: handlerOpts.localAddress,
+ family: handlerOpts.ipFamily,
+ lookup: handlerOpts.dnsLookup,
+ };
+ // In case of proxy the path needs to be an absolute URL
+ if (proxy) {
+ options.path = request.url;
+ try {
+ if (proxy.username || proxy.password) {
+ options.headers.push('proxy-authorization', (0, get_basic_1.getBasicAuthorizationHeader)(proxy));
+ }
+ }
+ catch (error) {
+ reject(error);
+ return;
+ }
+ }
+ const requestCallback = async (clientResponse) => {
+ try {
+ // This is necessary to prevent Node.js throwing an error
+ let statusCode = clientResponse.statusCode;
+ if (statusCode < 100 || statusCode > 999) {
+ statusCode = statuses_1.badGatewayStatusCodes.STATUS_CODE_OUT_OF_RANGE;
+ }
+ // 407 is handled separately
+ if (clientResponse.statusCode === 407) {
+ reject(new Error('407 Proxy Authentication Required'));
+ return;
+ }
+ response.writeHead(statusCode, clientResponse.statusMessage, (0, valid_headers_only_1.validHeadersOnly)(clientResponse.rawHeaders));
+ // `pipeline` automatically handles all the events and data
+ await pipeline(clientResponse, response);
+ resolve();
+ }
+ catch {
+ // Client error, pipeline already destroys the streams, ignore.
+ resolve();
+ }
+ };
+ // We have to force cast `options` because @types/node doesn't support an array.
+ const client = origin.startsWith('https:')
+ ? node_https_1.default.request(origin, {
+ ...options,
+ rejectUnauthorized: handlerOpts.upstreamProxyUrlParsed ? !handlerOpts.ignoreUpstreamProxyCertificate : undefined,
+ }, requestCallback)
+ : node_http_1.default.request(origin, options, requestCallback);
+ client.once('socket', (socket) => {
+ // Socket can be re-used by multiple requests.
+ // That's why we need to track the previous stats.
+ socket.previousBytesRead = socket.bytesRead;
+ socket.previousBytesWritten = socket.bytesWritten;
+ (0, count_target_bytes_1.countTargetBytes)(request.socket, socket, (handler) => response.once('close', handler));
+ });
+ // Can't use pipeline here as it automatically destroys the streams
+ request.pipe(client);
+ client.on('error', (error) => {
+ var _a;
+ if (response.headersSent) {
+ return;
+ }
+ const statusCode = (_a = statuses_1.errorCodeToStatusCode[error.code]) !== null && _a !== void 0 ? _a : statuses_1.badGatewayStatusCodes.GENERIC_ERROR;
+ response.statusCode = !proxy && error.code === 'ENOTFOUND' ? 404 : statusCode;
+ response.setHeader('content-type', 'text/plain; charset=utf-8');
+ response.end(node_http_1.default.STATUS_CODES[response.statusCode]);
+ resolve();
+ });
+});
+exports.forward = forward;
+//# sourceMappingURL=forward.js.map
\ No newline at end of file
diff --git a/dist/forward.js.map b/dist/forward.js.map
new file mode 100644
index 00000000..2d88377a
--- /dev/null
+++ b/dist/forward.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"forward.js","sourceRoot":"","sources":["../src/forward.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/dist/forward_socks.d.ts b/dist/forward_socks.d.ts
new file mode 100644
index 00000000..dde64637
--- /dev/null
+++ b/dist/forward_socks.d.ts
@@ -0,0 +1,15 @@
+///
+import http from 'node:http';
+import type { URL } from 'node:url';
+export interface HandlerOpts {
+ upstreamProxyUrlParsed: URL;
+ localAddress?: string;
+}
+/**
+ * ```
+ * Client -> Apify (HTTP) -> Upstream (SOCKS) -> Web
+ * Client <- Apify (HTTP) <- Upstream (SOCKS) <- Web
+ * ```
+ */
+export declare const forwardSocks: (request: http.IncomingMessage, response: http.ServerResponse, handlerOpts: HandlerOpts) => Promise;
+//# sourceMappingURL=forward_socks.d.ts.map
\ No newline at end of file
diff --git a/dist/forward_socks.d.ts.map b/dist/forward_socks.d.ts.map
new file mode 100644
index 00000000..7fbfca04
--- /dev/null
+++ b/dist/forward_socks.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"forward_socks.d.ts","sourceRoot":"","sources":["../src/forward_socks.ts"],"names":[],"mappings":";AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAoBpC,MAAM,WAAW,WAAW;IACxB,sBAAsB,EAAE,GAAG,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,eAAO,MAAM,YAAY,YACZ,KAAK,eAAe,YACnB,KAAK,cAAc,eAChB,WAAW,KAEzB,QAAQ,IAAI,CAiEb,CAAC"}
\ No newline at end of file
diff --git a/dist/forward_socks.js b/dist/forward_socks.js
new file mode 100644
index 00000000..ed26164d
--- /dev/null
+++ b/dist/forward_socks.js
@@ -0,0 +1,70 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.forwardSocks = void 0;
+const tslib_1 = require("tslib");
+const node_http_1 = tslib_1.__importDefault(require("node:http"));
+const node_stream_1 = tslib_1.__importDefault(require("node:stream"));
+const node_util_1 = tslib_1.__importDefault(require("node:util"));
+const socks_proxy_agent_1 = require("socks-proxy-agent");
+const statuses_1 = require("./statuses");
+const count_target_bytes_1 = require("./utils/count_target_bytes");
+const valid_headers_only_1 = require("./utils/valid_headers_only");
+const pipeline = node_util_1.default.promisify(node_stream_1.default.pipeline);
+/**
+ * ```
+ * Client -> Apify (HTTP) -> Upstream (SOCKS) -> Web
+ * Client <- Apify (HTTP) <- Upstream (SOCKS) <- Web
+ * ```
+ */
+const forwardSocks = async (request, response, handlerOpts) => new Promise(async (resolve, reject) => {
+ const agent = new socks_proxy_agent_1.SocksProxyAgent(handlerOpts.upstreamProxyUrlParsed);
+ const options = {
+ method: request.method,
+ headers: (0, valid_headers_only_1.validHeadersOnly)(request.rawHeaders),
+ insecureHTTPParser: true,
+ localAddress: handlerOpts.localAddress,
+ agent,
+ };
+ // Only handling "http" here - since everything else is handeled by tunnelSocks.
+ // We have to force cast `options` because @types/node doesn't support an array.
+ const client = node_http_1.default.request(request.url, options, async (clientResponse) => {
+ try {
+ // This is necessary to prevent Node.js throwing an error
+ let statusCode = clientResponse.statusCode;
+ if (statusCode < 100 || statusCode > 999) {
+ statusCode = statuses_1.badGatewayStatusCodes.STATUS_CODE_OUT_OF_RANGE;
+ }
+ // 407 is handled separately
+ if (clientResponse.statusCode === 407) {
+ reject(new Error('407 Proxy Authentication Required'));
+ return;
+ }
+ response.writeHead(statusCode, clientResponse.statusMessage, (0, valid_headers_only_1.validHeadersOnly)(clientResponse.rawHeaders));
+ // `pipeline` automatically handles all the events and data
+ await pipeline(clientResponse, response);
+ resolve();
+ }
+ catch {
+ // Client error, pipeline already destroys the streams, ignore.
+ resolve();
+ }
+ });
+ client.once('socket', (socket) => {
+ (0, count_target_bytes_1.countTargetBytes)(request.socket, socket);
+ });
+ // Can't use pipeline here as it automatically destroys the streams
+ request.pipe(client);
+ client.on('error', (error) => {
+ var _a;
+ if (response.headersSent) {
+ return;
+ }
+ const statusCode = (_a = statuses_1.errorCodeToStatusCode[error.code]) !== null && _a !== void 0 ? _a : statuses_1.badGatewayStatusCodes.GENERIC_ERROR;
+ response.statusCode = statusCode;
+ response.setHeader('content-type', 'text/plain; charset=utf-8');
+ response.end(node_http_1.default.STATUS_CODES[response.statusCode]);
+ resolve();
+ });
+});
+exports.forwardSocks = forwardSocks;
+//# sourceMappingURL=forward_socks.js.map
\ No newline at end of file
diff --git a/dist/forward_socks.js.map b/dist/forward_socks.js.map
new file mode 100644
index 00000000..1ca6992f
--- /dev/null
+++ b/dist/forward_socks.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"forward_socks.js","sourceRoot":"","sources":["../src/forward_socks.ts"],"names":[],"mappings":";;;;AAAA,kEAA6B;AAC7B,sEAAiC;AAEjC,kEAA6B;AAE7B,yDAAoD;AAEpD,yCAA0E;AAC1E,mEAA8D;AAC9D,mEAA8D;AAE9D,MAAM,QAAQ,GAAG,mBAAI,CAAC,SAAS,CAAC,qBAAM,CAAC,QAAQ,CAAC,CAAC;AAgBjD;;;;;GAKG;AACI,MAAM,YAAY,GAAG,KAAK,EAC7B,OAA6B,EAC7B,QAA6B,EAC7B,WAAwB,EAEX,EAAE,CAAC,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE;IACtD,MAAM,KAAK,GAAG,IAAI,mCAAe,CAAC,WAAW,CAAC,sBAAsB,CAAC,CAAC;IAEtE,MAAM,OAAO,GAAY;QACrB,MAAM,EAAE,OAAO,CAAC,MAAO;QACvB,OAAO,EAAE,IAAA,qCAAgB,EAAC,OAAO,CAAC,UAAU,CAAC;QAC7C,kBAAkB,EAAE,IAAI;QACxB,YAAY,EAAE,WAAW,CAAC,YAAY;QACtC,KAAK;KACR,CAAC;IAEF,gFAAgF;IAChF,gFAAgF;IAChF,MAAM,MAAM,GAAG,mBAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAI,EAAE,OAA4C,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE;QAC7G,IAAI;YACA,yDAAyD;YACzD,IAAI,UAAU,GAAG,cAAc,CAAC,UAAW,CAAC;YAC5C,IAAI,UAAU,GAAG,GAAG,IAAI,UAAU,GAAG,GAAG,EAAE;gBACtC,UAAU,GAAG,gCAAqB,CAAC,wBAAwB,CAAC;aAC/D;YAED,4BAA4B;YAC5B,IAAI,cAAc,CAAC,UAAU,KAAK,GAAG,EAAE;gBACnC,MAAM,CAAC,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC,CAAC;gBACvD,OAAO;aACV;YAED,QAAQ,CAAC,SAAS,CACd,UAAU,EACV,cAAc,CAAC,aAAa,EAC5B,IAAA,qCAAgB,EAAC,cAAc,CAAC,UAAU,CAAC,CAC9C,CAAC;YAEF,2DAA2D;YAC3D,MAAM,QAAQ,CACV,cAAc,EACd,QAAQ,CACX,CAAC;YAEF,OAAO,EAAE,CAAC;SACb;QAAC,MAAM;YACJ,+DAA+D;YAC/D,OAAO,EAAE,CAAC;SACb;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE;QAC7B,IAAA,qCAAgB,EAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,mEAAmE;IACnE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACrB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAA4B,EAAE,EAAE;;QAChD,IAAI,QAAQ,CAAC,WAAW,EAAE;YACtB,OAAO;SACV;QAED,MAAM,UAAU,GAAG,MAAA,gCAAqB,CAAC,KAAK,CAAC,IAAK,CAAC,mCAAI,gCAAqB,CAAC,aAAa,CAAC;QAE7F,QAAQ,CAAC,UAAU,GAAG,UAAU,CAAC;QACjC,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAE,2BAA2B,CAAC,CAAC;QAChE,QAAQ,CAAC,GAAG,CAAC,mBAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;QAErD,OAAO,EAAE,CAAC;IACd,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC;AAtEU,QAAA,YAAY,gBAsEtB"}
\ No newline at end of file
diff --git a/dist/index.d.ts b/dist/index.d.ts
new file mode 100644
index 00000000..12c7ff02
--- /dev/null
+++ b/dist/index.d.ts
@@ -0,0 +1,7 @@
+export * from './request_error';
+export * from './server';
+export * from './utils/redact_url';
+export * from './anonymize_proxy';
+export * from './tcp_tunnel_tools';
+export { CustomResponse } from './custom_response';
+//# sourceMappingURL=index.d.ts.map
\ No newline at end of file
diff --git a/dist/index.d.ts.map b/dist/index.d.ts.map
new file mode 100644
index 00000000..15af00ba
--- /dev/null
+++ b/dist/index.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AAEnC,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC"}
\ No newline at end of file
diff --git a/dist/index.js b/dist/index.js
new file mode 100644
index 00000000..655d10e9
--- /dev/null
+++ b/dist/index.js
@@ -0,0 +1,9 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+const tslib_1 = require("tslib");
+tslib_1.__exportStar(require("./request_error"), exports);
+tslib_1.__exportStar(require("./server"), exports);
+tslib_1.__exportStar(require("./utils/redact_url"), exports);
+tslib_1.__exportStar(require("./anonymize_proxy"), exports);
+tslib_1.__exportStar(require("./tcp_tunnel_tools"), exports);
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/dist/index.js.map b/dist/index.js.map
new file mode 100644
index 00000000..5e97fecb
--- /dev/null
+++ b/dist/index.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,0DAAgC;AAChC,mDAAyB;AACzB,6DAAmC;AACnC,4DAAkC;AAClC,6DAAmC"}
\ No newline at end of file
diff --git a/dist/request_error.d.ts b/dist/request_error.d.ts
new file mode 100644
index 00000000..26cf4a0f
--- /dev/null
+++ b/dist/request_error.d.ts
@@ -0,0 +1,14 @@
+/**
+ * Represents custom request error. The message is emitted as HTTP response
+ * with a specific HTTP code and headers.
+ * If this error is thrown from the `prepareRequestFunction` function,
+ * the message and status code is sent to client.
+ * By default, the response will have Content-Type: text/plain
+ * and for the 407 status the Proxy-Authenticate header will be added.
+ */
+export declare class RequestError extends Error {
+ statusCode: number;
+ headers?: Record | undefined;
+ constructor(message: string, statusCode: number, headers?: Record | undefined);
+}
+//# sourceMappingURL=request_error.d.ts.map
\ No newline at end of file
diff --git a/dist/request_error.d.ts.map b/dist/request_error.d.ts.map
new file mode 100644
index 00000000..bf468d06
--- /dev/null
+++ b/dist/request_error.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"request_error.d.ts","sourceRoot":"","sources":["../src/request_error.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,qBAAa,YAAa,SAAQ,KAAK;IAGxB,UAAU,EAAE,MAAM;IAClB,OAAO,CAAC;gBAFf,OAAO,EAAE,MAAM,EACR,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,oCAAwB;CAO9C"}
\ No newline at end of file
diff --git a/dist/request_error.js b/dist/request_error.js
new file mode 100644
index 00000000..02379cfd
--- /dev/null
+++ b/dist/request_error.js
@@ -0,0 +1,32 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.RequestError = void 0;
+/**
+ * Represents custom request error. The message is emitted as HTTP response
+ * with a specific HTTP code and headers.
+ * If this error is thrown from the `prepareRequestFunction` function,
+ * the message and status code is sent to client.
+ * By default, the response will have Content-Type: text/plain
+ * and for the 407 status the Proxy-Authenticate header will be added.
+ */
+class RequestError extends Error {
+ constructor(message, statusCode, headers) {
+ super(message);
+ Object.defineProperty(this, "statusCode", {
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ value: statusCode
+ });
+ Object.defineProperty(this, "headers", {
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ value: headers
+ });
+ this.name = RequestError.name;
+ Error.captureStackTrace(this, RequestError);
+ }
+}
+exports.RequestError = RequestError;
+//# sourceMappingURL=request_error.js.map
\ No newline at end of file
diff --git a/dist/request_error.js.map b/dist/request_error.js.map
new file mode 100644
index 00000000..c38e5c7d
--- /dev/null
+++ b/dist/request_error.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"request_error.js","sourceRoot":"","sources":["../src/request_error.ts"],"names":[],"mappings":";;;AAAA;;;;;;;GAOG;AACH,MAAa,YAAa,SAAQ,KAAK;IACnC,YACI,OAAe,EACR,UAAkB,EAClB,OAAgC;QAEvC,KAAK,CAAC,OAAO,CAAC,CAAC;;;;;mBAHR;;;;;;mBACA;;QAGP,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC;QAE9B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAChD,CAAC;CACJ;AAXD,oCAWC"}
\ No newline at end of file
diff --git a/dist/server.d.ts b/dist/server.d.ts
new file mode 100644
index 00000000..0784af05
--- /dev/null
+++ b/dist/server.d.ts
@@ -0,0 +1,212 @@
+///
+///
+///
+///
+///
+///
+///
+import { Buffer } from 'node:buffer';
+import type dns from 'node:dns';
+import { EventEmitter } from 'node:events';
+import http from 'node:http';
+import { URL } from 'node:url';
+import type { HandlerOpts as CustomResponseOpts } from './custom_response';
+import type { Socket } from './socket';
+export declare const SOCKS_PROTOCOLS: string[];
+export type ConnectionStats = {
+ srcTxBytes: number;
+ srcRxBytes: number;
+ trgTxBytes: number | null;
+ trgRxBytes: number | null;
+};
+type HandlerOpts = {
+ server: Server;
+ id: number;
+ srcRequest: http.IncomingMessage;
+ srcResponse: http.ServerResponse | null;
+ srcHead: Buffer | null;
+ trgParsed: URL | null;
+ upstreamProxyUrlParsed: URL | null;
+ ignoreUpstreamProxyCertificate: boolean;
+ isHttp: boolean;
+ customResponseFunction?: CustomResponseOpts['customResponseFunction'] | null;
+ customConnectServer?: http.Server | null;
+ localAddress?: string;
+ ipFamily?: number;
+ dnsLookup?: typeof dns['lookup'];
+ customTag?: unknown;
+};
+export type PrepareRequestFunctionOpts = {
+ connectionId: number;
+ request: http.IncomingMessage;
+ username: string;
+ password: string;
+ hostname: string;
+ port: number;
+ isHttp: boolean;
+};
+export type PrepareRequestFunctionResult = {
+ customResponseFunction?: CustomResponseOpts['customResponseFunction'];
+ customConnectServer?: http.Server | null;
+ requestAuthentication?: boolean;
+ failMsg?: string;
+ upstreamProxyUrl?: string | null;
+ ignoreUpstreamProxyCertificate?: boolean;
+ localAddress?: string;
+ ipFamily?: number;
+ dnsLookup?: typeof dns['lookup'];
+ customTag?: unknown;
+};
+type Promisable = T | Promise;
+export type PrepareRequestFunction = (opts: PrepareRequestFunctionOpts) => Promisable;
+/**
+ * Represents the proxy server.
+ * It emits the 'requestFailed' event on unexpected request errors, with the following parameter `{ error, request }`.
+ * It emits the 'connectionClosed' event when connection to proxy server is closed, with parameter `{ connectionId, stats }`.
+ */
+export declare class Server extends EventEmitter {
+ port: number;
+ host?: string;
+ prepareRequestFunction?: PrepareRequestFunction;
+ authRealm: unknown;
+ verbose: boolean;
+ server: http.Server;
+ lastHandlerId: number;
+ stats: {
+ httpRequestCount: number;
+ connectRequestCount: number;
+ trafficUsedInBytes: number;
+ };
+ connections: Map;
+ /**
+ * Initializes a new instance of Server class.
+ * @param options
+ * @param [options.port] Port where the server will listen. By default 8000.
+ * @param [options.prepareRequestFunction] Custom function to authenticate proxy requests,
+ * provide URL to upstream proxy or potentially provide a function that generates a custom response to HTTP requests.
+ * It accepts a single parameter which is an object:
+ * ```
+ * {
+ * connectionId: symbol,
+ * request: http.IncomingMessage,
+ * username: string,
+ * password: string,
+ * hostname: string,
+ * port: number,
+ * isHttp: boolean,
+ * }
+ * ```
+ * and returns an object (or promise resolving to the object) with following form:
+ * ```
+ * {
+ * requestAuthentication: boolean,
+ * upstreamProxyUrl: string,
+ * customResponseFunction: Function,
+ * }
+ * ```
+ * If `upstreamProxyUrl` is a falsy value, no upstream proxy is used.
+ * If `prepareRequestFunction` is not set, the proxy server will not require any authentication
+ * and will not use any upstream proxy.
+ * If `customResponseFunction` is set, it will be called to generate a custom response to the HTTP request.
+ * It should not be used together with `upstreamProxyUrl`.
+ * @param [options.authRealm] Realm used in the Proxy-Authenticate header and also in the 'Server' HTTP header. By default it's `ProxyChain`.
+ * @param [options.verbose] If true, the server will output logs
+ */
+ constructor(options?: {
+ port?: number;
+ host?: string;
+ prepareRequestFunction?: PrepareRequestFunction;
+ verbose?: boolean;
+ authRealm?: unknown;
+ });
+ log(connectionId: unknown, str: string): void;
+ onClientError(err: NodeJS.ErrnoException, socket: Socket): void;
+ /**
+ * Assigns a unique ID to the socket and keeps the register up to date.
+ * Needed for abrupt close of the server.
+ */
+ registerConnection(socket: Socket): void;
+ /**
+ * Registering total stats each server
+ */
+ /**
+ * Handles incoming sockets, useful for error handling
+ */
+ onConnection(socket: Socket): void;
+ /**
+ * Converts known errors to be instance of RequestError.
+ */
+ normalizeHandlerError(error: NodeJS.ErrnoException): NodeJS.ErrnoException;
+ /**
+ * Handles normal HTTP request by forwarding it to target host or the upstream proxy.
+ */
+ onRequest(request: http.IncomingMessage, response: http.ServerResponse): Promise;
+ /**
+ * Handles HTTP CONNECT request by setting up a tunnel either to target host or to the upstream proxy.
+ * @param request
+ * @param socket
+ * @param head The first packet of the tunneling stream (may be empty)
+ */
+ onConnect(request: http.IncomingMessage, socket: Socket, head: Buffer): Promise;
+ /**
+ * Prepares handler options from a request.
+ * @see {prepareRequestHandling}
+ */
+ getHandlerOpts(request: http.IncomingMessage): HandlerOpts;
+ /**
+ * Calls `this.prepareRequestFunction` with normalized options.
+ * @param request
+ * @param handlerOpts
+ */
+ callPrepareRequestFunction(request: http.IncomingMessage, handlerOpts: HandlerOpts): Promise;
+ /**
+ * Authenticates a new request and determines upstream proxy URL using the user function.
+ * Returns a promise resolving to an object that can be used to run a handler.
+ * @param request
+ */
+ prepareRequestHandling(request: http.IncomingMessage): Promise;
+ /**
+ * Sends a HTTP error response to the client.
+ * @param request
+ * @param error
+ */
+ failRequest(request: http.IncomingMessage, error: NodeJS.ErrnoException): void;
+ /**
+ * Sends a simple HTTP response to the client and forcibly closes the connection.
+ * This invalidates the ServerResponse instance (if present).
+ * We don't know the state of the response anyway.
+ * Writing directly to the socket seems to be the easiest solution.
+ * @param socket
+ * @param statusCode
+ * @param headers
+ * @param message
+ */
+ sendSocketResponse(socket: Socket, statusCode?: number, caseSensitiveHeaders?: {}, message?: string): void;
+ /**
+ * Starts listening at a port specified in the constructor.
+ */
+ listen(callback?: (error: NodeJS.ErrnoException | null) => void): Promise;
+ /**
+ * Gets array of IDs of all active connections.
+ */
+ getConnectionIds(): number[];
+ /**
+ * Gets data transfer statistics of a specific proxy connection.
+ */
+ getConnectionStats(connectionId: number): ConnectionStats | undefined;
+ /**
+ * Forcibly close a specific pending proxy connection.
+ */
+ closeConnection(connectionId: number): void;
+ /**
+ * Forcibly closes pending proxy connections.
+ */
+ closeConnections(): void;
+ /**
+ * Closes the proxy server.
+ * @param closeConnections If true, pending proxy connections are forcibly closed.
+ */
+ close(closeConnections: boolean, callback?: (error: NodeJS.ErrnoException | null) => void): Promise;
+}
+export {};
+//# sourceMappingURL=server.d.ts.map
\ No newline at end of file
diff --git a/dist/server.d.ts.map b/dist/server.d.ts.map
new file mode 100644
index 00000000..925e7c4f
--- /dev/null
+++ b/dist/server.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/dist/server.js b/dist/server.js
new file mode 100644
index 00000000..35f29131
--- /dev/null
+++ b/dist/server.js
@@ -0,0 +1,579 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.Server = exports.SOCKS_PROTOCOLS = void 0;
+const tslib_1 = require("tslib");
+/* eslint-disable no-use-before-define */
+const node_buffer_1 = require("node:buffer");
+const node_events_1 = require("node:events");
+const node_http_1 = tslib_1.__importDefault(require("node:http"));
+const node_url_1 = require("node:url");
+const node_util_1 = tslib_1.__importDefault(require("node:util"));
+const chain_1 = require("./chain");
+const chain_socks_1 = require("./chain_socks");
+const custom_connect_1 = require("./custom_connect");
+const custom_response_1 = require("./custom_response");
+const direct_1 = require("./direct");
+const forward_1 = require("./forward");
+const forward_socks_1 = require("./forward_socks");
+const request_error_1 = require("./request_error");
+const statuses_1 = require("./statuses");
+const count_target_bytes_1 = require("./utils/count_target_bytes");
+const nodeify_1 = require("./utils/nodeify");
+const normalize_url_port_1 = require("./utils/normalize_url_port");
+const parse_authorization_header_1 = require("./utils/parse_authorization_header");
+const redact_url_1 = require("./utils/redact_url");
+exports.SOCKS_PROTOCOLS = ['socks:', 'socks4:', 'socks4a:', 'socks5:', 'socks5h:'];
+// TODO:
+// - Implement this requirement from rfc7230
+// "A proxy MUST forward unrecognized header fields unless the field-name
+// is listed in the Connection header field (Section 6.1) or the proxy
+// is specifically configured to block, or otherwise transform, such
+// fields. Other recipients SHOULD ignore unrecognized header fields.
+// These requirements allow HTTP's functionality to be enhanced without
+// requiring prior update of deployed intermediaries."
+const DEFAULT_AUTH_REALM = 'ProxyChain';
+const DEFAULT_PROXY_SERVER_PORT = 8000;
+/**
+ * Represents the proxy server.
+ * It emits the 'requestFailed' event on unexpected request errors, with the following parameter `{ error, request }`.
+ * It emits the 'connectionClosed' event when connection to proxy server is closed, with parameter `{ connectionId, stats }`.
+ */
+class Server extends node_events_1.EventEmitter {
+ /**
+ * Initializes a new instance of Server class.
+ * @param options
+ * @param [options.port] Port where the server will listen. By default 8000.
+ * @param [options.prepareRequestFunction] Custom function to authenticate proxy requests,
+ * provide URL to upstream proxy or potentially provide a function that generates a custom response to HTTP requests.
+ * It accepts a single parameter which is an object:
+ * ```
+ * {
+ * connectionId: symbol,
+ * request: http.IncomingMessage,
+ * username: string,
+ * password: string,
+ * hostname: string,
+ * port: number,
+ * isHttp: boolean,
+ * }
+ * ```
+ * and returns an object (or promise resolving to the object) with following form:
+ * ```
+ * {
+ * requestAuthentication: boolean,
+ * upstreamProxyUrl: string,
+ * customResponseFunction: Function,
+ * }
+ * ```
+ * If `upstreamProxyUrl` is a falsy value, no upstream proxy is used.
+ * If `prepareRequestFunction` is not set, the proxy server will not require any authentication
+ * and will not use any upstream proxy.
+ * If `customResponseFunction` is set, it will be called to generate a custom response to the HTTP request.
+ * It should not be used together with `upstreamProxyUrl`.
+ * @param [options.authRealm] Realm used in the Proxy-Authenticate header and also in the 'Server' HTTP header. By default it's `ProxyChain`.
+ * @param [options.verbose] If true, the server will output logs
+ */
+ constructor(options = {}) {
+ super();
+ Object.defineProperty(this, "port", {
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ value: void 0
+ });
+ Object.defineProperty(this, "host", {
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ value: void 0
+ });
+ Object.defineProperty(this, "prepareRequestFunction", {
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ value: void 0
+ });
+ Object.defineProperty(this, "authRealm", {
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ value: void 0
+ });
+ Object.defineProperty(this, "verbose", {
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ value: void 0
+ });
+ Object.defineProperty(this, "server", {
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ value: void 0
+ });
+ Object.defineProperty(this, "lastHandlerId", {
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ value: void 0
+ });
+ Object.defineProperty(this, "stats", {
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ value: void 0
+ });
+ Object.defineProperty(this, "connections", {
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ value: void 0
+ });
+ if (options.port === undefined || options.port === null) {
+ this.port = DEFAULT_PROXY_SERVER_PORT;
+ }
+ else {
+ this.port = options.port;
+ }
+ this.host = options.host;
+ this.prepareRequestFunction = options.prepareRequestFunction;
+ this.authRealm = options.authRealm || DEFAULT_AUTH_REALM;
+ this.verbose = !!options.verbose;
+ this.server = node_http_1.default.createServer();
+ this.server.on('clientError', this.onClientError.bind(this));
+ this.server.on('request', this.onRequest.bind(this));
+ this.server.on('connect', this.onConnect.bind(this));
+ this.server.on('connection', this.onConnection.bind(this));
+ this.lastHandlerId = 0;
+ this.stats = {
+ httpRequestCount: 0,
+ connectRequestCount: 0,
+ trafficUsedInBytes: 0
+ };
+ this.connections = new Map();
+ }
+ log(connectionId, str) {
+ if (this.verbose) {
+ const logPrefix = connectionId != null ? `${String(connectionId)} | ` : '';
+ // eslint-disable-next-line no-console
+ console.log(`ProxyServer[${this.port}]: ${logPrefix}${str}`);
+ }
+ }
+ onClientError(err, socket) {
+ this.log(socket.proxyChainId, `onClientError: ${err}`);
+ // https://nodejs.org/api/http.html#http_event_clienterror
+ if (err.code === 'ECONNRESET' || !socket.writable) {
+ return;
+ }
+ this.sendSocketResponse(socket, 400, {}, 'Invalid request');
+ }
+ /**
+ * Assigns a unique ID to the socket and keeps the register up to date.
+ * Needed for abrupt close of the server.
+ */
+ registerConnection(socket) {
+ const unique = this.lastHandlerId++;
+ socket.proxyChainId = unique;
+ this.connections.set(unique, socket);
+ socket.on('close', () => {
+ const socketStats = this.getConnectionStats(unique);
+ this.emit('connectionClosed', {
+ connectionId: unique,
+ stats: socketStats,
+ });
+ if (socketStats) {
+ this.stats.trafficUsedInBytes += socketStats.srcRxBytes + socketStats.srcTxBytes + (socketStats.trgRxBytes || 0) + (socketStats.trgTxBytes || 0);
+ }
+ this.connections.delete(unique);
+ });
+ // We have to manually destroy the socket if it timeouts.
+ // This will prevent connections from leaking and close them properly.
+ socket.on('timeout', () => {
+ socket.destroy();
+ });
+ }
+ /**
+ * Registering total stats each server
+ */
+ /**
+ * Handles incoming sockets, useful for error handling
+ */
+ onConnection(socket) {
+ // https://github.com/nodejs/node/issues/23858
+ if (!socket.remoteAddress) {
+ socket.destroy();
+ return;
+ }
+ this.registerConnection(socket);
+ // We need to consume socket errors, because the handlers are attached asynchronously.
+ // See https://github.com/apify/proxy-chain/issues/53
+ socket.on('error', (err) => {
+ // Handle errors only if there's no other handler
+ if (this.listenerCount('error') === 1) {
+ this.log(socket.proxyChainId, `Source socket emitted error: ${err.stack || err}`);
+ }
+ });
+ }
+ /**
+ * Converts known errors to be instance of RequestError.
+ */
+ normalizeHandlerError(error) {
+ if (error.message === 'Username contains an invalid colon') {
+ return new request_error_1.RequestError('Invalid colon in username in upstream proxy credentials', statuses_1.badGatewayStatusCodes.AUTH_FAILED);
+ }
+ if (error.message === '407 Proxy Authentication Required') {
+ return new request_error_1.RequestError('Invalid upstream proxy credentials', statuses_1.badGatewayStatusCodes.AUTH_FAILED);
+ }
+ return error;
+ }
+ /**
+ * Handles normal HTTP request by forwarding it to target host or the upstream proxy.
+ */
+ async onRequest(request, response) {
+ try {
+ const handlerOpts = await this.prepareRequestHandling(request);
+ handlerOpts.srcResponse = response;
+ const { proxyChainId } = request.socket;
+ if (handlerOpts.customResponseFunction) {
+ this.log(proxyChainId, 'Using handleCustomResponse()');
+ await (0, custom_response_1.handleCustomResponse)(request, response, handlerOpts);
+ return;
+ }
+ if (handlerOpts.upstreamProxyUrlParsed && exports.SOCKS_PROTOCOLS.includes(handlerOpts.upstreamProxyUrlParsed.protocol)) {
+ this.log(proxyChainId, 'Using forwardSocks()');
+ await (0, forward_socks_1.forwardSocks)(request, response, handlerOpts);
+ return;
+ }
+ this.log(proxyChainId, 'Using forward()');
+ await (0, forward_1.forward)(request, response, handlerOpts);
+ }
+ catch (error) {
+ this.failRequest(request, this.normalizeHandlerError(error));
+ }
+ }
+ /**
+ * Handles HTTP CONNECT request by setting up a tunnel either to target host or to the upstream proxy.
+ * @param request
+ * @param socket
+ * @param head The first packet of the tunneling stream (may be empty)
+ */
+ async onConnect(request, socket, head) {
+ try {
+ const handlerOpts = await this.prepareRequestHandling(request);
+ handlerOpts.srcHead = head;
+ const data = { request, sourceSocket: socket, head, handlerOpts: handlerOpts, server: this, isPlain: false };
+ if (handlerOpts.customConnectServer) {
+ socket.unshift(head); // See chain.ts for why we do this
+ await (0, custom_connect_1.customConnect)(socket, handlerOpts.customConnectServer);
+ return;
+ }
+ if (handlerOpts.upstreamProxyUrlParsed) {
+ if (exports.SOCKS_PROTOCOLS.includes(handlerOpts.upstreamProxyUrlParsed.protocol)) {
+ this.log(socket.proxyChainId, `Using chainSocks() => ${request.url}`);
+ await (0, chain_socks_1.chainSocks)(data);
+ return;
+ }
+ this.log(socket.proxyChainId, `Using chain() => ${request.url}`);
+ (0, chain_1.chain)(data);
+ return;
+ }
+ this.log(socket.proxyChainId, `Using direct() => ${request.url}`);
+ (0, direct_1.direct)(data);
+ }
+ catch (error) {
+ this.failRequest(request, this.normalizeHandlerError(error));
+ }
+ }
+ /**
+ * Prepares handler options from a request.
+ * @see {prepareRequestHandling}
+ */
+ getHandlerOpts(request) {
+ const handlerOpts = {
+ server: this,
+ id: request.socket.proxyChainId,
+ srcRequest: request,
+ srcHead: null,
+ trgParsed: null,
+ upstreamProxyUrlParsed: null,
+ ignoreUpstreamProxyCertificate: false,
+ isHttp: false,
+ srcResponse: null,
+ customResponseFunction: null,
+ customConnectServer: null,
+ };
+ this.log(request.socket.proxyChainId, `!!! Handling ${request.method} ${request.url} HTTP/${request.httpVersion}`);
+ if (request.method === 'CONNECT') {
+ // CONNECT server.example.com:80 HTTP/1.1
+ try {
+ handlerOpts.trgParsed = new node_url_1.URL(`connect://${request.url}`);
+ }
+ catch {
+ throw new request_error_1.RequestError(`Target "${request.url}" could not be parsed`, 400);
+ }
+ if (!handlerOpts.trgParsed.hostname || !handlerOpts.trgParsed.port) {
+ throw new request_error_1.RequestError(`Target "${request.url}" could not be parsed`, 400);
+ }
+ this.stats.connectRequestCount++;
+ }
+ else {
+ // The request should look like:
+ // GET http://server.example.com:80/some-path HTTP/1.1
+ // Note that RFC 7230 says:
+ // "When making a request to a proxy, other than a CONNECT or server-wide
+ // OPTIONS request (as detailed below), a client MUST send the target
+ // URI in absolute-form as the request-target"
+ let parsed;
+ try {
+ parsed = new node_url_1.URL(request.url);
+ }
+ catch {
+ // If URL is invalid, throw HTTP 400 error
+ throw new request_error_1.RequestError(`Target "${request.url}" could not be parsed`, 400);
+ }
+ // Only HTTP is supported, other protocols such as HTTP or FTP must use the CONNECT method
+ if (parsed.protocol !== 'http:') {
+ throw new request_error_1.RequestError(`Only HTTP protocol is supported (was ${parsed.protocol})`, 400);
+ }
+ handlerOpts.trgParsed = parsed;
+ handlerOpts.isHttp = true;
+ this.stats.httpRequestCount++;
+ }
+ return handlerOpts;
+ }
+ /**
+ * Calls `this.prepareRequestFunction` with normalized options.
+ * @param request
+ * @param handlerOpts
+ */
+ async callPrepareRequestFunction(request, handlerOpts) {
+ if (this.prepareRequestFunction) {
+ const funcOpts = {
+ connectionId: request.socket.proxyChainId,
+ request,
+ username: '',
+ password: '',
+ hostname: handlerOpts.trgParsed.hostname,
+ port: (0, normalize_url_port_1.normalizeUrlPort)(handlerOpts.trgParsed),
+ isHttp: handlerOpts.isHttp,
+ };
+ // Authenticate the request using a user function (if provided)
+ const proxyAuth = request.headers['proxy-authorization'];
+ if (proxyAuth) {
+ const auth = (0, parse_authorization_header_1.parseAuthorizationHeader)(proxyAuth);
+ if (!auth) {
+ throw new request_error_1.RequestError('Invalid "Proxy-Authorization" header', 400);
+ }
+ // https://datatracker.ietf.org/doc/html/rfc7617#page-3
+ // Note that both scheme and parameter names are matched case-
+ // insensitively.
+ if (auth.type.toLowerCase() !== 'basic') {
+ throw new request_error_1.RequestError('The "Proxy-Authorization" header must have the "Basic" type.', 400);
+ }
+ funcOpts.username = auth.username;
+ funcOpts.password = auth.password;
+ }
+ const result = await this.prepareRequestFunction(funcOpts);
+ return result !== null && result !== void 0 ? result : {};
+ }
+ return {};
+ }
+ /**
+ * Authenticates a new request and determines upstream proxy URL using the user function.
+ * Returns a promise resolving to an object that can be used to run a handler.
+ * @param request
+ */
+ async prepareRequestHandling(request) {
+ const handlerOpts = this.getHandlerOpts(request);
+ const funcResult = await this.callPrepareRequestFunction(request, handlerOpts);
+ handlerOpts.localAddress = funcResult.localAddress;
+ handlerOpts.ipFamily = funcResult.ipFamily;
+ handlerOpts.dnsLookup = funcResult.dnsLookup;
+ handlerOpts.customConnectServer = funcResult.customConnectServer;
+ handlerOpts.customTag = funcResult.customTag;
+ // If not authenticated, request client to authenticate
+ if (funcResult.requestAuthentication) {
+ throw new request_error_1.RequestError(funcResult.failMsg || 'Proxy credentials required.', 407);
+ }
+ if (funcResult.upstreamProxyUrl) {
+ try {
+ handlerOpts.upstreamProxyUrlParsed = new node_url_1.URL(funcResult.upstreamProxyUrl);
+ }
+ catch (error) {
+ throw new Error(`Invalid "upstreamProxyUrl" provided: ${error} (was "${funcResult.upstreamProxyUrl}"`);
+ }
+ if (!['http:', 'https:', ...exports.SOCKS_PROTOCOLS].includes(handlerOpts.upstreamProxyUrlParsed.protocol)) {
+ throw new Error(`Invalid "upstreamProxyUrl" provided: URL must have one of the following protocols: "http", "https", ${exports.SOCKS_PROTOCOLS.map((p) => `"${p.replace(':', '')}"`).join(', ')} (was "${funcResult.upstreamProxyUrl}")`);
+ }
+ }
+ if (funcResult.ignoreUpstreamProxyCertificate !== undefined) {
+ handlerOpts.ignoreUpstreamProxyCertificate = funcResult.ignoreUpstreamProxyCertificate;
+ }
+ const { proxyChainId } = request.socket;
+ if (funcResult.customResponseFunction) {
+ this.log(proxyChainId, 'Using custom response function');
+ handlerOpts.customResponseFunction = funcResult.customResponseFunction;
+ if (!handlerOpts.isHttp) {
+ throw new Error('The "customResponseFunction" option can only be used for HTTP requests.');
+ }
+ if (typeof (handlerOpts.customResponseFunction) !== 'function') {
+ throw new Error('The "customResponseFunction" option must be a function.');
+ }
+ }
+ if (handlerOpts.upstreamProxyUrlParsed) {
+ this.log(proxyChainId, `Using upstream proxy ${(0, redact_url_1.redactUrl)(handlerOpts.upstreamProxyUrlParsed)}`);
+ }
+ return handlerOpts;
+ }
+ /**
+ * Sends a HTTP error response to the client.
+ * @param request
+ * @param error
+ */
+ failRequest(request, error) {
+ const { proxyChainId } = request.socket;
+ if (error.name === 'RequestError') {
+ const typedError = error;
+ this.log(proxyChainId, `Request failed (status ${typedError.statusCode}): ${error.message}`);
+ this.sendSocketResponse(request.socket, typedError.statusCode, typedError.headers, error.message);
+ }
+ else {
+ this.log(proxyChainId, `Request failed with error: ${error.stack || error}`);
+ this.sendSocketResponse(request.socket, 500, {}, 'Internal error in proxy server');
+ this.emit('requestFailed', { error, request });
+ }
+ this.log(proxyChainId, 'Closing because request failed with error');
+ }
+ /**
+ * Sends a simple HTTP response to the client and forcibly closes the connection.
+ * This invalidates the ServerResponse instance (if present).
+ * We don't know the state of the response anyway.
+ * Writing directly to the socket seems to be the easiest solution.
+ * @param socket
+ * @param statusCode
+ * @param headers
+ * @param message
+ */
+ sendSocketResponse(socket, statusCode = 500, caseSensitiveHeaders = {}, message = '') {
+ try {
+ const headers = Object.fromEntries(Object.entries(caseSensitiveHeaders).map(([name, value]) => [name.toLowerCase(), value]));
+ headers.connection = 'close';
+ headers.date = (new Date()).toUTCString();
+ headers['content-length'] = String(node_buffer_1.Buffer.byteLength(message));
+ headers.server = headers.server || this.authRealm;
+ headers['content-type'] = headers['content-type'] || 'text/plain; charset=utf-8';
+ if (statusCode === 407 && !headers['proxy-authenticate']) {
+ headers['proxy-authenticate'] = `Basic realm="${this.authRealm}"`;
+ }
+ let msg = `HTTP/1.1 ${statusCode} ${node_http_1.default.STATUS_CODES[statusCode] || 'Unknown Status Code'}\r\n`;
+ for (const [key, value] of Object.entries(headers)) {
+ msg += `${key}: ${value}\r\n`;
+ }
+ msg += `\r\n${message}`;
+ // Unfortunately it's not possible to send RST in Node.js yet.
+ // See https://github.com/nodejs/node/issues/27428
+ socket.setTimeout(1000, () => {
+ socket.destroy();
+ });
+ // This sends FIN, meaning we still can receive data.
+ socket.end(msg);
+ }
+ catch (err) {
+ this.log(socket.proxyChainId, `Unhandled error in sendResponse(), will be ignored: ${err.stack || err}`);
+ }
+ }
+ /**
+ * Starts listening at a port specified in the constructor.
+ */
+ async listen(callback) {
+ const promise = new Promise((resolve, reject) => {
+ // Unfortunately server.listen() is not a normal function that fails on error,
+ // so we need this trickery
+ const onError = (error) => {
+ this.log(null, `Listen failed: ${error}`);
+ removeListeners();
+ reject(error);
+ };
+ const onListening = () => {
+ this.port = this.server.address().port;
+ this.log(null, 'Listening...');
+ removeListeners();
+ resolve();
+ };
+ const removeListeners = () => {
+ this.server.removeListener('error', onError);
+ this.server.removeListener('listening', onListening);
+ };
+ this.server.on('error', onError);
+ this.server.on('listening', onListening);
+ this.server.listen(this.port, this.host);
+ });
+ return (0, nodeify_1.nodeify)(promise, callback);
+ }
+ /**
+ * Gets array of IDs of all active connections.
+ */
+ getConnectionIds() {
+ return [...this.connections.keys()];
+ }
+ /**
+ * Gets data transfer statistics of a specific proxy connection.
+ */
+ getConnectionStats(connectionId) {
+ const socket = this.connections.get(connectionId);
+ if (!socket)
+ return undefined;
+ const targetStats = (0, count_target_bytes_1.getTargetStats)(socket);
+ const result = {
+ srcTxBytes: socket.bytesWritten,
+ srcRxBytes: socket.bytesRead,
+ trgTxBytes: targetStats.bytesWritten,
+ trgRxBytes: targetStats.bytesRead,
+ };
+ return result;
+ }
+ /**
+ * Forcibly close a specific pending proxy connection.
+ */
+ closeConnection(connectionId) {
+ this.log(null, 'Closing pending socket');
+ const socket = this.connections.get(connectionId);
+ if (!socket)
+ return;
+ socket.destroy();
+ this.log(null, `Destroyed pending socket`);
+ }
+ /**
+ * Forcibly closes pending proxy connections.
+ */
+ closeConnections() {
+ this.log(null, 'Closing pending sockets');
+ for (const socket of this.connections.values()) {
+ socket.destroy();
+ }
+ this.log(null, `Destroyed ${this.connections.size} pending sockets`);
+ }
+ /**
+ * Closes the proxy server.
+ * @param closeConnections If true, pending proxy connections are forcibly closed.
+ */
+ async close(closeConnections, callback) {
+ if (typeof closeConnections === 'function') {
+ callback = closeConnections;
+ closeConnections = false;
+ }
+ if (closeConnections) {
+ this.closeConnections();
+ }
+ if (this.server) {
+ const { server } = this;
+ // @ts-expect-error Let's make sure we can't access the server anymore.
+ this.server = null;
+ const promise = node_util_1.default.promisify(server.close).bind(server)();
+ return (0, nodeify_1.nodeify)(promise, callback);
+ }
+ return (0, nodeify_1.nodeify)(Promise.resolve(), callback);
+ }
+}
+exports.Server = Server;
+//# sourceMappingURL=server.js.map
\ No newline at end of file
diff --git a/dist/server.js.map b/dist/server.js.map
new file mode 100644
index 00000000..b2b1fe2c
--- /dev/null
+++ b/dist/server.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/dist/socket.d.ts b/dist/socket.d.ts
new file mode 100644
index 00000000..ef524179
--- /dev/null
+++ b/dist/socket.d.ts
@@ -0,0 +1,11 @@
+///
+///
+import type net from 'node:net';
+import type tls from 'node:tls';
+type AdditionalProps = {
+ proxyChainId?: number;
+};
+export type Socket = net.Socket & AdditionalProps;
+export type TLSSocket = tls.TLSSocket & AdditionalProps;
+export {};
+//# sourceMappingURL=socket.d.ts.map
\ No newline at end of file
diff --git a/dist/socket.d.ts.map b/dist/socket.d.ts.map
new file mode 100644
index 00000000..76fd7e8a
--- /dev/null
+++ b/dist/socket.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../src/socket.ts"],"names":[],"mappings":";;AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAEhC,KAAK,eAAe,GAAG;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjD,MAAM,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,GAAG,eAAe,CAAC;AAClD,MAAM,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,GAAG,eAAe,CAAC"}
\ No newline at end of file
diff --git a/dist/socket.js b/dist/socket.js
new file mode 100644
index 00000000..ca957cb3
--- /dev/null
+++ b/dist/socket.js
@@ -0,0 +1,3 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+//# sourceMappingURL=socket.js.map
\ No newline at end of file
diff --git a/dist/socket.js.map b/dist/socket.js.map
new file mode 100644
index 00000000..b3db2857
--- /dev/null
+++ b/dist/socket.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"socket.js","sourceRoot":"","sources":["../src/socket.ts"],"names":[],"mappings":""}
\ No newline at end of file
diff --git a/dist/statuses.d.ts b/dist/statuses.d.ts
new file mode 100644
index 00000000..3dd9d9a1
--- /dev/null
+++ b/dist/statuses.d.ts
@@ -0,0 +1,46 @@
+type HttpStatusCode = number;
+export declare const badGatewayStatusCodes: {
+ /**
+ * Upstream has timed out.
+ */
+ readonly TIMEOUT: 504;
+ /**
+ * Upstream responded with non-200 status code.
+ */
+ readonly NON_200: 590;
+ /**
+ * Upstream respondend with status code different than 100-999.
+ */
+ readonly STATUS_CODE_OUT_OF_RANGE: 592;
+ /**
+ * DNS lookup failed - EAI_NODATA or EAI_NONAME.
+ */
+ readonly NOT_FOUND: 593;
+ /**
+ * Upstream refused connection.
+ */
+ readonly CONNECTION_REFUSED: 594;
+ /**
+ * Connection reset due to loss of connection or timeout.
+ */
+ readonly CONNECTION_RESET: 595;
+ /**
+ * Trying to write on a closed socket.
+ */
+ readonly BROKEN_PIPE: 596;
+ /**
+ * Incorrect upstream credentials.
+ */
+ readonly AUTH_FAILED: 597;
+ /**
+ * Generic upstream error.
+ */
+ readonly GENERIC_ERROR: 599;
+};
+export declare const createCustomStatusHttpResponse: (statusCode: number, statusMessage: string, message?: string) => string;
+export declare const errorCodeToStatusCode: {
+ [errorCode: string]: HttpStatusCode | undefined;
+};
+export declare const socksErrorMessageToStatusCode: (socksErrorMessage: string) => (typeof badGatewayStatusCodes)[keyof typeof badGatewayStatusCodes];
+export {};
+//# sourceMappingURL=statuses.d.ts.map
\ No newline at end of file
diff --git a/dist/statuses.d.ts.map b/dist/statuses.d.ts.map
new file mode 100644
index 00000000..ca498248
--- /dev/null
+++ b/dist/statuses.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"statuses.d.ts","sourceRoot":"","sources":["../src/statuses.ts"],"names":[],"mappings":"AAEA,KAAK,cAAc,GAAG,MAAM,CAAC;AAE7B,eAAO,MAAM,qBAAqB;IAC9B;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;CAEG,CAAC;AAWX,eAAO,MAAM,8BAA8B,eAAgB,MAAM,iBAAiB,MAAM,6BASvF,CAAC;AAGF,eAAO,MAAM,qBAAqB,EAAE;IAAC,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAAA;CAM1E,CAAC;AAEX,eAAO,MAAM,6BAA6B,sBAAuB,MAAM,KAAG,CAAA,4BAA4B,EAAC,MAAM,4BAA4B,CASxI,CAAC"}
\ No newline at end of file
diff --git a/dist/statuses.js b/dist/statuses.js
new file mode 100644
index 00000000..ce9fdd56
--- /dev/null
+++ b/dist/statuses.js
@@ -0,0 +1,81 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.socksErrorMessageToStatusCode = exports.errorCodeToStatusCode = exports.createCustomStatusHttpResponse = exports.badGatewayStatusCodes = void 0;
+const node_http_1 = require("node:http");
+exports.badGatewayStatusCodes = {
+ /**
+ * Upstream has timed out.
+ */
+ TIMEOUT: 504,
+ /**
+ * Upstream responded with non-200 status code.
+ */
+ NON_200: 590,
+ /**
+ * Upstream respondend with status code different than 100-999.
+ */
+ STATUS_CODE_OUT_OF_RANGE: 592,
+ /**
+ * DNS lookup failed - EAI_NODATA or EAI_NONAME.
+ */
+ NOT_FOUND: 593,
+ /**
+ * Upstream refused connection.
+ */
+ CONNECTION_REFUSED: 594,
+ /**
+ * Connection reset due to loss of connection or timeout.
+ */
+ CONNECTION_RESET: 595,
+ /**
+ * Trying to write on a closed socket.
+ */
+ BROKEN_PIPE: 596,
+ /**
+ * Incorrect upstream credentials.
+ */
+ AUTH_FAILED: 597,
+ /**
+ * Generic upstream error.
+ */
+ GENERIC_ERROR: 599,
+};
+node_http_1.STATUS_CODES['590'] = 'Non Successful';
+node_http_1.STATUS_CODES['592'] = 'Status Code Out Of Range';
+node_http_1.STATUS_CODES['593'] = 'Not Found';
+node_http_1.STATUS_CODES['594'] = 'Connection Refused';
+node_http_1.STATUS_CODES['595'] = 'Connection Reset';
+node_http_1.STATUS_CODES['596'] = 'Broken Pipe';
+node_http_1.STATUS_CODES['597'] = 'Auth Failed';
+node_http_1.STATUS_CODES['599'] = 'Upstream Error';
+const createCustomStatusHttpResponse = (statusCode, statusMessage, message = '') => {
+ return [
+ `HTTP/1.1 ${statusCode} ${statusMessage || node_http_1.STATUS_CODES[statusCode] || 'Unknown Status Code'}`,
+ 'Connection: close',
+ `Date: ${(new Date()).toUTCString()}`,
+ `Content-Length: ${Buffer.byteLength(message)}`,
+ ``,
+ message,
+ ].join('\r\n');
+};
+exports.createCustomStatusHttpResponse = createCustomStatusHttpResponse;
+// https://nodejs.org/api/errors.html#common-system-errors
+exports.errorCodeToStatusCode = {
+ ENOTFOUND: exports.badGatewayStatusCodes.NOT_FOUND,
+ ECONNREFUSED: exports.badGatewayStatusCodes.CONNECTION_REFUSED,
+ ECONNRESET: exports.badGatewayStatusCodes.CONNECTION_RESET,
+ EPIPE: exports.badGatewayStatusCodes.BROKEN_PIPE,
+ ETIMEDOUT: exports.badGatewayStatusCodes.TIMEOUT,
+};
+const socksErrorMessageToStatusCode = (socksErrorMessage) => {
+ switch (socksErrorMessage) {
+ case 'Proxy connection timed out':
+ return exports.badGatewayStatusCodes.TIMEOUT;
+ case 'Socks5 Authentication failed':
+ return exports.badGatewayStatusCodes.AUTH_FAILED;
+ default:
+ return exports.badGatewayStatusCodes.GENERIC_ERROR;
+ }
+};
+exports.socksErrorMessageToStatusCode = socksErrorMessageToStatusCode;
+//# sourceMappingURL=statuses.js.map
\ No newline at end of file
diff --git a/dist/statuses.js.map b/dist/statuses.js.map
new file mode 100644
index 00000000..02820bd1
--- /dev/null
+++ b/dist/statuses.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"statuses.js","sourceRoot":"","sources":["../src/statuses.ts"],"names":[],"mappings":";;;AAAA,yCAAyC;AAI5B,QAAA,qBAAqB,GAAG;IACjC;;OAEG;IACH,OAAO,EAAE,GAAG;IACZ;;OAEG;IACH,OAAO,EAAE,GAAG;IACZ;;OAEG;IACH,wBAAwB,EAAE,GAAG;IAC7B;;OAEG;IACH,SAAS,EAAE,GAAG;IACd;;OAEG;IACH,kBAAkB,EAAE,GAAG;IACvB;;OAEG;IACH,gBAAgB,EAAE,GAAG;IACrB;;OAEG;IACH,WAAW,EAAE,GAAG;IAChB;;OAEG;IACH,WAAW,EAAE,GAAG;IAChB;;OAEG;IACH,aAAa,EAAE,GAAG;CACZ,CAAC;AAEX,wBAAY,CAAC,KAAK,CAAC,GAAG,gBAAgB,CAAC;AACvC,wBAAY,CAAC,KAAK,CAAC,GAAG,0BAA0B,CAAC;AACjD,wBAAY,CAAC,KAAK,CAAC,GAAG,WAAW,CAAC;AAClC,wBAAY,CAAC,KAAK,CAAC,GAAG,oBAAoB,CAAC;AAC3C,wBAAY,CAAC,KAAK,CAAC,GAAG,kBAAkB,CAAC;AACzC,wBAAY,CAAC,KAAK,CAAC,GAAG,aAAa,CAAC;AACpC,wBAAY,CAAC,KAAK,CAAC,GAAG,aAAa,CAAC;AACpC,wBAAY,CAAC,KAAK,CAAC,GAAG,gBAAgB,CAAC;AAEhC,MAAM,8BAA8B,GAAG,CAAC,UAAkB,EAAE,aAAqB,EAAE,OAAO,GAAG,EAAE,EAAE,EAAE;IACtG,OAAO;QACH,YAAY,UAAU,IAAI,aAAa,IAAI,wBAAY,CAAC,UAAU,CAAC,IAAI,qBAAqB,EAAE;QAC9F,mBAAmB;QACnB,SAAS,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,EAAE;QACrC,mBAAmB,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE;QAC/C,EAAE;QACF,OAAO;KACV,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACnB,CAAC,CAAC;AATW,QAAA,8BAA8B,kCASzC;AAEF,0DAA0D;AAC7C,QAAA,qBAAqB,GAAsD;IACpF,SAAS,EAAE,6BAAqB,CAAC,SAAS;IAC1C,YAAY,EAAE,6BAAqB,CAAC,kBAAkB;IACtD,UAAU,EAAE,6BAAqB,CAAC,gBAAgB;IAClD,KAAK,EAAE,6BAAqB,CAAC,WAAW;IACxC,SAAS,EAAE,6BAAqB,CAAC,OAAO;CAClC,CAAC;AAEJ,MAAM,6BAA6B,GAAG,CAAC,iBAAyB,EAAoE,EAAE;IACzI,QAAQ,iBAAiB,EAAE;QACvB,KAAK,4BAA4B;YAC7B,OAAO,6BAAqB,CAAC,OAAO,CAAC;QACzC,KAAK,8BAA8B;YAC/B,OAAO,6BAAqB,CAAC,WAAW,CAAC;QAC7C;YACI,OAAO,6BAAqB,CAAC,aAAa,CAAC;KAClD;AACL,CAAC,CAAC;AATW,QAAA,6BAA6B,iCASxC"}
\ No newline at end of file
diff --git a/dist/tcp_tunnel_tools.d.ts b/dist/tcp_tunnel_tools.d.ts
new file mode 100644
index 00000000..4ca3898a
--- /dev/null
+++ b/dist/tcp_tunnel_tools.d.ts
@@ -0,0 +1,6 @@
+export declare function createTunnel(proxyUrl: string, targetHost: string, options?: {
+ verbose?: boolean;
+ ignoreProxyCertificate?: boolean;
+}, callback?: (error: Error | null, result?: string) => void): Promise;
+export declare function closeTunnel(serverPath: string, closeConnections: boolean | undefined, callback: (error: Error | null, result?: boolean) => void): Promise;
+//# sourceMappingURL=tcp_tunnel_tools.d.ts.map
\ No newline at end of file
diff --git a/dist/tcp_tunnel_tools.d.ts.map b/dist/tcp_tunnel_tools.d.ts.map
new file mode 100644
index 00000000..51082739
--- /dev/null
+++ b/dist/tcp_tunnel_tools.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"tcp_tunnel_tools.d.ts","sourceRoot":"","sources":["../src/tcp_tunnel_tools.ts"],"names":[],"mappings":"AAkBA,wBAAsB,YAAY,CAC9B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;IACN,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,sBAAsB,CAAC,EAAE,OAAO,CAAC;CACpC,EACD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,GAC1D,OAAO,CAAC,MAAM,CAAC,CAsEjB;AAED,wBAAsB,WAAW,CAC7B,UAAU,EAAE,MAAM,EAClB,gBAAgB,EAAE,OAAO,GAAG,SAAS,EACrC,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,EAAE,MAAM,CAAC,EAAE,OAAO,KAAK,IAAI,GAC1D,OAAO,CAAC,OAAO,CAAC,CA+BlB"}
\ No newline at end of file
diff --git a/dist/tcp_tunnel_tools.js b/dist/tcp_tunnel_tools.js
new file mode 100644
index 00000000..777e54cc
--- /dev/null
+++ b/dist/tcp_tunnel_tools.js
@@ -0,0 +1,104 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.closeTunnel = exports.createTunnel = void 0;
+const tslib_1 = require("tslib");
+const node_net_1 = tslib_1.__importDefault(require("node:net"));
+const node_url_1 = require("node:url");
+const chain_1 = require("./chain");
+const nodeify_1 = require("./utils/nodeify");
+const runningServers = {};
+const getAddress = (server) => {
+ const { address: host, port, family } = server.address();
+ if (family === 'IPv6') {
+ return `[${host}]:${port}`;
+ }
+ return `${host}:${port}`;
+};
+async function createTunnel(proxyUrl, targetHost, options, callback) {
+ const parsedProxyUrl = new node_url_1.URL(proxyUrl);
+ if (!['http:', 'https:'].includes(parsedProxyUrl.protocol)) {
+ throw new Error(`The proxy URL must have the "http" or "https" protocol (was "${proxyUrl}")`);
+ }
+ const url = new node_url_1.URL(`connect://${targetHost || ''}`);
+ if (!url.hostname) {
+ throw new Error('Missing target hostname');
+ }
+ if (!url.port) {
+ throw new Error('Missing target port');
+ }
+ const verbose = options && options.verbose;
+ const server = node_net_1.default.createServer();
+ const log = (...args) => {
+ if (verbose)
+ console.log(...args);
+ };
+ server.log = log;
+ server.on('connection', (sourceSocket) => {
+ var _a;
+ const remoteAddress = `${sourceSocket.remoteAddress}:${sourceSocket.remotePort}`;
+ const { connections } = runningServers[getAddress(server)];
+ log(`new client connection from ${remoteAddress}`);
+ sourceSocket.on('close', (hadError) => {
+ connections.delete(sourceSocket);
+ log(`connection from ${remoteAddress} closed, hadError=${hadError}`);
+ });
+ connections.add(sourceSocket);
+ (0, chain_1.chain)({
+ request: { url: targetHost },
+ sourceSocket,
+ handlerOpts: {
+ upstreamProxyUrlParsed: parsedProxyUrl,
+ ignoreUpstreamProxyCertificate: (_a = options === null || options === void 0 ? void 0 : options.ignoreProxyCertificate) !== null && _a !== void 0 ? _a : false,
+ },
+ server: server,
+ isPlain: true,
+ });
+ });
+ const promise = new Promise((resolve, reject) => {
+ server.once('error', reject);
+ // Let the system pick a random listening port
+ server.listen(0, () => {
+ const address = getAddress(server);
+ server.off('error', reject);
+ runningServers[address] = { server, connections: new Set() };
+ log('server listening to ', address);
+ resolve(address);
+ });
+ });
+ return (0, nodeify_1.nodeify)(promise, callback);
+}
+exports.createTunnel = createTunnel;
+async function closeTunnel(serverPath, closeConnections, callback) {
+ const { hostname, port } = new node_url_1.URL(`tcp://${serverPath}`);
+ if (!hostname)
+ throw new Error('serverPath must contain hostname');
+ if (!port)
+ throw new Error('serverPath must contain port');
+ const promise = new Promise((resolve) => {
+ if (!runningServers[serverPath]) {
+ resolve(false);
+ return;
+ }
+ if (!closeConnections) {
+ resolve(true);
+ return;
+ }
+ for (const connection of runningServers[serverPath].connections) {
+ connection.destroy();
+ }
+ resolve(true);
+ })
+ .then(async (serverExists) => new Promise((resolve) => {
+ if (!serverExists) {
+ resolve(false);
+ return;
+ }
+ runningServers[serverPath].server.close(() => {
+ delete runningServers[serverPath];
+ resolve(true);
+ });
+ }));
+ return (0, nodeify_1.nodeify)(promise, callback);
+}
+exports.closeTunnel = closeTunnel;
+//# sourceMappingURL=tcp_tunnel_tools.js.map
\ No newline at end of file
diff --git a/dist/tcp_tunnel_tools.js.map b/dist/tcp_tunnel_tools.js.map
new file mode 100644
index 00000000..46a7d33c
--- /dev/null
+++ b/dist/tcp_tunnel_tools.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"tcp_tunnel_tools.js","sourceRoot":"","sources":["../src/tcp_tunnel_tools.ts"],"names":[],"mappings":";;;;AAAA,gEAA2B;AAC3B,uCAA+B;AAE/B,mCAAgC;AAChC,6CAA0C;AAE1C,MAAM,cAAc,GAAyE,EAAE,CAAC;AAEhG,MAAM,UAAU,GAAG,CAAC,MAAkB,EAAE,EAAE;IACtC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,EAAqB,CAAC;IAE5E,IAAI,MAAM,KAAK,MAAM,EAAE;QACnB,OAAO,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;KAC9B;IAED,OAAO,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;AAC7B,CAAC,CAAC;AAEK,KAAK,UAAU,YAAY,CAC9B,QAAgB,EAChB,UAAkB,EAClB,OAGC,EACD,QAAyD;IAEzD,MAAM,cAAc,GAAG,IAAI,cAAG,CAAC,QAAQ,CAAC,CAAC;IACzC,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE;QACxD,MAAM,IAAI,KAAK,CAAC,gEAAgE,QAAQ,IAAI,CAAC,CAAC;KACjG;IAED,MAAM,GAAG,GAAG,IAAI,cAAG,CAAC,aAAa,UAAU,IAAI,EAAE,EAAE,CAAC,CAAC;IAErD,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE;QACf,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;KAC9C;IAED,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE;QACX,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;KAC1C;IAED,MAAM,OAAO,GAAG,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAE3C,MAAM,MAAM,GAAwD,kBAAG,CAAC,YAAY,EAAE,CAAC;IAEvF,MAAM,GAAG,GAAG,CAAC,GAAG,IAAe,EAAQ,EAAE;QACrC,IAAI,OAAO;YAAE,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;IACtC,CAAC,CAAC;IAEF,MAAM,CAAC,GAAG,GAAG,GAAG,CAAC;IAEjB,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,YAAY,EAAE,EAAE;;QACrC,MAAM,aAAa,GAAG,GAAG,YAAY,CAAC,aAAa,IAAI,YAAY,CAAC,UAAU,EAAE,CAAC;QAEjF,MAAM,EAAE,WAAW,EAAE,GAAG,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;QAE3D,GAAG,CAAC,8BAA8B,aAAa,EAAE,CAAC,CAAC;QAEnD,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE;YAClC,WAAW,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;YAEjC,GAAG,CAAC,mBAAmB,aAAa,qBAAqB,QAAQ,EAAE,CAAC,CAAC;QACzE,CAAC,CAAC,CAAC;QAEH,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAE9B,IAAA,aAAK,EAAC;YACF,OAAO,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE;YAC5B,YAAY;YACZ,WAAW,EAAE;gBACT,sBAAsB,EAAE,cAAc;gBACtC,8BAA8B,EAAE,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,sBAAsB,mCAAI,KAAK;aAC3E;YACD,MAAM,EAAE,MAA0C;YAClD,OAAO,EAAE,IAAI;SAChB,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACpD,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAE7B,8CAA8C;QAC9C,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE;YAClB,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;YAEnC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC5B,cAAc,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC;YAE7D,GAAG,CAAC,sBAAsB,EAAE,OAAO,CAAC,CAAC;YAErC,OAAO,CAAC,OAAO,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,OAAO,IAAA,iBAAO,EAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AACtC,CAAC;AA9ED,oCA8EC;AAEM,KAAK,UAAU,WAAW,CAC7B,UAAkB,EAClB,gBAAqC,EACrC,QAAyD;IAEzD,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,IAAI,cAAG,CAAC,SAAS,UAAU,EAAE,CAAC,CAAC;IAC1D,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACnE,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAE3D,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QACpC,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE;YAC7B,OAAO,CAAC,KAAK,CAAC,CAAC;YACf,OAAO;SACV;QACD,IAAI,CAAC,gBAAgB,EAAE;YACnB,OAAO,CAAC,IAAI,CAAC,CAAC;YACd,OAAO;SACV;QACD,KAAK,MAAM,UAAU,IAAI,cAAc,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE;YAC7D,UAAU,CAAC,OAAO,EAAE,CAAC;SACxB;QACD,OAAO,CAAC,IAAI,CAAC,CAAC;IAClB,CAAC,CAAC;SACG,IAAI,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,CAAC,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;QAC3D,IAAI,CAAC,YAAY,EAAE;YACf,OAAO,CAAC,KAAK,CAAC,CAAC;YACf,OAAO;SACV;QACD,cAAc,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE;YACzC,OAAO,cAAc,CAAC,UAAU,CAAC,CAAC;YAClC,OAAO,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC,CAAC;IAER,OAAO,IAAA,iBAAO,EAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AACtC,CAAC;AAnCD,kCAmCC"}
\ No newline at end of file
diff --git a/dist/tsconfig.tsbuildinfo b/dist/tsconfig.tsbuildinfo
new file mode 100644
index 00000000..0967aa23
--- /dev/null
+++ b/dist/tsconfig.tsbuildinfo
@@ -0,0 +1 @@
+{"program":{"fileNames":["../node_modules/typescript/lib/lib.es5.d.ts","../node_modules/typescript/lib/lib.es2015.d.ts","../node_modules/typescript/lib/lib.es2016.d.ts","../node_modules/typescript/lib/lib.es2017.d.ts","../node_modules/typescript/lib/lib.es2018.d.ts","../node_modules/typescript/lib/lib.es2019.d.ts","../node_modules/typescript/lib/lib.es2020.d.ts","../node_modules/typescript/lib/lib.es2021.d.ts","../node_modules/typescript/lib/lib.es2022.d.ts","../node_modules/typescript/lib/lib.esnext.d.ts","../node_modules/typescript/lib/lib.es2015.core.d.ts","../node_modules/typescript/lib/lib.es2015.collection.d.ts","../node_modules/typescript/lib/lib.es2015.generator.d.ts","../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../node_modules/typescript/lib/lib.es2015.promise.d.ts","../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../node_modules/typescript/lib/lib.es2017.object.d.ts","../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../node_modules/typescript/lib/lib.es2017.string.d.ts","../node_modules/typescript/lib/lib.es2017.intl.d.ts","../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../node_modules/typescript/lib/lib.es2018.intl.d.ts","../node_modules/typescript/lib/lib.es2018.promise.d.ts","../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../node_modules/typescript/lib/lib.es2019.array.d.ts","../node_modules/typescript/lib/lib.es2019.object.d.ts","../node_modules/typescript/lib/lib.es2019.string.d.ts","../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../node_modules/typescript/lib/lib.es2019.intl.d.ts","../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../node_modules/typescript/lib/lib.es2020.date.d.ts","../node_modules/typescript/lib/lib.es2020.promise.d.ts","../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../node_modules/typescript/lib/lib.es2020.string.d.ts","../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../node_modules/typescript/lib/lib.es2020.intl.d.ts","../node_modules/typescript/lib/lib.es2020.number.d.ts","../node_modules/typescript/lib/lib.es2021.promise.d.ts","../node_modules/typescript/lib/lib.es2021.string.d.ts","../node_modules/typescript/lib/lib.es2021.weakref.d.ts","../node_modules/typescript/lib/lib.es2021.intl.d.ts","../node_modules/typescript/lib/lib.es2022.array.d.ts","../node_modules/typescript/lib/lib.es2022.error.d.ts","../node_modules/typescript/lib/lib.es2022.intl.d.ts","../node_modules/typescript/lib/lib.es2022.object.d.ts","../node_modules/typescript/lib/lib.es2022.sharedmemory.d.ts","../node_modules/typescript/lib/lib.es2022.string.d.ts","../node_modules/typescript/lib/lib.esnext.intl.d.ts","../node_modules/tslib/tslib.d.ts","../src/socket.ts","../src/statuses.ts","../src/utils/count_target_bytes.ts","../src/utils/decode_uri_component_safe.ts","../src/utils/get_basic.ts","../src/chain.ts","../node_modules/@types/node/compatibility/disposable.d.ts","../node_modules/@types/node/compatibility/indexable.d.ts","../node_modules/@types/node/compatibility/iterators.d.ts","../node_modules/@types/node/compatibility/index.d.ts","../node_modules/@types/node/ts5.6/globals.typedarray.d.ts","../node_modules/@types/node/ts5.6/buffer.buffer.d.ts","../node_modules/buffer/index.d.ts","../node_modules/undici-types/header.d.ts","../node_modules/undici-types/readable.d.ts","../node_modules/undici-types/file.d.ts","../node_modules/undici-types/fetch.d.ts","../node_modules/undici-types/formdata.d.ts","../node_modules/undici-types/connector.d.ts","../node_modules/undici-types/client.d.ts","../node_modules/undici-types/errors.d.ts","../node_modules/undici-types/dispatcher.d.ts","../node_modules/undici-types/global-dispatcher.d.ts","../node_modules/undici-types/global-origin.d.ts","../node_modules/undici-types/pool-stats.d.ts","../node_modules/undici-types/pool.d.ts","../node_modules/undici-types/handlers.d.ts","../node_modules/undici-types/balanced-pool.d.ts","../node_modules/undici-types/agent.d.ts","../node_modules/undici-types/mock-interceptor.d.ts","../node_modules/undici-types/mock-agent.d.ts","../node_modules/undici-types/mock-client.d.ts","../node_modules/undici-types/mock-pool.d.ts","../node_modules/undici-types/mock-errors.d.ts","../node_modules/undici-types/proxy-agent.d.ts","../node_modules/undici-types/api.d.ts","../node_modules/undici-types/cookies.d.ts","../node_modules/undici-types/patch.d.ts","../node_modules/undici-types/filereader.d.ts","../node_modules/undici-types/diagnostics-channel.d.ts","../node_modules/undici-types/websocket.d.ts","../node_modules/undici-types/content-type.d.ts","../node_modules/undici-types/cache.d.ts","../node_modules/undici-types/interceptors.d.ts","../node_modules/undici-types/index.d.ts","../node_modules/@types/node/globals.d.ts","../node_modules/@types/node/assert.d.ts","../node_modules/@types/node/assert/strict.d.ts","../node_modules/@types/node/async_hooks.d.ts","../node_modules/@types/node/buffer.d.ts","../node_modules/@types/node/child_process.d.ts","../node_modules/@types/node/cluster.d.ts","../node_modules/@types/node/console.d.ts","../node_modules/@types/node/constants.d.ts","../node_modules/@types/node/crypto.d.ts","../node_modules/@types/node/dgram.d.ts","../node_modules/@types/node/diagnostics_channel.d.ts","../node_modules/@types/node/dns.d.ts","../node_modules/@types/node/dns/promises.d.ts","../node_modules/@types/node/domain.d.ts","../node_modules/@types/node/dom-events.d.ts","../node_modules/@types/node/events.d.ts","../node_modules/@types/node/fs.d.ts","../node_modules/@types/node/fs/promises.d.ts","../node_modules/@types/node/http.d.ts","../node_modules/@types/node/http2.d.ts","../node_modules/@types/node/https.d.ts","../node_modules/@types/node/inspector.d.ts","../node_modules/@types/node/module.d.ts","../node_modules/@types/node/net.d.ts","../node_modules/@types/node/os.d.ts","../node_modules/@types/node/path.d.ts","../node_modules/@types/node/perf_hooks.d.ts","../node_modules/@types/node/process.d.ts","../node_modules/@types/node/punycode.d.ts","../node_modules/@types/node/querystring.d.ts","../node_modules/@types/node/readline.d.ts","../node_modules/@types/node/readline/promises.d.ts","../node_modules/@types/node/repl.d.ts","../node_modules/@types/node/stream.d.ts","../node_modules/@types/node/stream/promises.d.ts","../node_modules/@types/node/stream/consumers.d.ts","../node_modules/@types/node/stream/web.d.ts","../node_modules/@types/node/string_decoder.d.ts","../node_modules/@types/node/test.d.ts","../node_modules/@types/node/timers.d.ts","../node_modules/@types/node/timers/promises.d.ts","../node_modules/@types/node/tls.d.ts","../node_modules/@types/node/trace_events.d.ts","../node_modules/@types/node/tty.d.ts","../node_modules/@types/node/url.d.ts","../node_modules/@types/node/util.d.ts","../node_modules/@types/node/v8.d.ts","../node_modules/@types/node/vm.d.ts","../node_modules/@types/node/wasi.d.ts","../node_modules/@types/node/worker_threads.d.ts","../node_modules/@types/node/zlib.d.ts","../node_modules/@types/node/ts5.6/index.d.ts","../node_modules/socks/typings/common/constants.d.ts","../node_modules/socks/typings/common/util.d.ts","../node_modules/socks/typings/client/socksclient.d.ts","../node_modules/socks/typings/index.d.ts","../src/chain_socks.ts","../src/custom_connect.ts","../src/custom_response.ts","../src/direct.ts","../src/utils/is_hop_by_hop_header.ts","../src/utils/valid_headers_only.ts","../src/forward.ts","../node_modules/socks-proxy-agent/node_modules/agent-base/dist/helpers.d.ts","../node_modules/socks-proxy-agent/node_modules/agent-base/dist/index.d.ts","../node_modules/socks-proxy-agent/dist/index.d.ts","../src/forward_socks.ts","../src/request_error.ts","../src/utils/nodeify.ts","../src/utils/normalize_url_port.ts","../src/utils/parse_authorization_header.ts","../src/utils/redact_url.ts","../src/server.ts","../src/anonymize_proxy.ts","../src/tcp_tunnel_tools.ts","../src/index.ts","../node_modules/@types/estree/index.d.ts","../node_modules/@types/istanbul-lib-coverage/index.d.ts","../node_modules/@types/istanbul-lib-report/index.d.ts","../node_modules/@types/istanbul-reports/index.d.ts","../node_modules/@jest/expect-utils/build/index.d.ts","../node_modules/chalk/index.d.ts","../node_modules/@sinclair/typebox/typebox.d.ts","../node_modules/@jest/schemas/build/index.d.ts","../node_modules/pretty-format/build/index.d.ts","../node_modules/jest-diff/build/index.d.ts","../node_modules/jest-matcher-utils/build/index.d.ts","../node_modules/expect/build/index.d.ts","../node_modules/@types/jest/index.d.ts","../node_modules/@types/json-schema/index.d.ts","../node_modules/@types/json5/index.d.ts","../node_modules/@types/responselike/index.d.ts","../node_modules/@types/stack-utils/index.d.ts","../node_modules/@types/yargs-parser/index.d.ts","../node_modules/@types/yargs/index.d.ts","../node_modules/@types/yauzl/index.d.ts"],"fileInfos":[{"version":"8730f4bf322026ff5229336391a18bcaa1f94d4f82416c8b2f3954e2ccaae2ba","affectsGlobalScope":true},"dc47c4fa66b9b9890cf076304de2a9c5201e94b740cffdf09f87296d877d71f6","7a387c58583dfca701b6c85e0adaf43fb17d590fb16d5b2dc0a2fbd89f35c467","8a12173c586e95f4433e0c6dc446bc88346be73ffe9ca6eec7aa63c8f3dca7f9","5f4e733ced4e129482ae2186aae29fde948ab7182844c3a5a51dd346182c7b06","4b421cbfb3a38a27c279dec1e9112c3d1da296f77a1a85ddadf7e7a425d45d18","1fc5ab7a764205c68fa10d381b08417795fc73111d6dd16b5b1ed36badb743d9","746d62152361558ea6d6115cf0da4dd10ede041d14882ede3568bce5dc4b4f1f","d11a03592451da2d1065e09e61f4e2a9bf68f780f4f6623c18b57816a9679d17","aea179452def8a6152f98f63b191b84e7cbd69b0e248c91e61fb2e52328abe8c",{"version":"adb996790133eb33b33aadb9c09f15c2c575e71fb57a62de8bf74dbf59ec7dfb","affectsGlobalScope":true},{"version":"8cc8c5a3bac513368b0157f3d8b31cfdcfe78b56d3724f30f80ed9715e404af8","affectsGlobalScope":true},{"version":"cdccba9a388c2ee3fd6ad4018c640a471a6c060e96f1232062223063b0a5ac6a","affectsGlobalScope":true},{"version":"c5c05907c02476e4bde6b7e76a79ffcd948aedd14b6a8f56e4674221b0417398","affectsGlobalScope":true},{"version":"5f406584aef28a331c36523df688ca3650288d14f39c5d2e555c95f0d2ff8f6f","affectsGlobalScope":true},{"version":"22f230e544b35349cfb3bd9110b6ef37b41c6d6c43c3314a31bd0d9652fcec72","affectsGlobalScope":true},{"version":"7ea0b55f6b315cf9ac2ad622b0a7813315bb6e97bf4bb3fbf8f8affbca7dc695","affectsGlobalScope":true},{"version":"3013574108c36fd3aaca79764002b3717da09725a36a6fc02eac386593110f93","affectsGlobalScope":true},{"version":"eb26de841c52236d8222f87e9e6a235332e0788af8c87a71e9e210314300410a","affectsGlobalScope":true},{"version":"3be5a1453daa63e031d266bf342f3943603873d890ab8b9ada95e22389389006","affectsGlobalScope":true},{"version":"17bb1fc99591b00515502d264fa55dc8370c45c5298f4a5c2083557dccba5a2a","affectsGlobalScope":true},{"version":"7ce9f0bde3307ca1f944119f6365f2d776d281a393b576a18a2f2893a2d75c98","affectsGlobalScope":true},{"version":"6a6b173e739a6a99629a8594bfb294cc7329bfb7b227f12e1f7c11bc163b8577","affectsGlobalScope":true},{"version":"81cac4cbc92c0c839c70f8ffb94eb61e2d32dc1c3cf6d95844ca099463cf37ea","affectsGlobalScope":true},{"version":"b0124885ef82641903d232172577f2ceb5d3e60aed4da1153bab4221e1f6dd4e","affectsGlobalScope":true},{"version":"0eb85d6c590b0d577919a79e0084fa1744c1beba6fd0d4e951432fa1ede5510a","affectsGlobalScope":true},{"version":"da233fc1c8a377ba9e0bed690a73c290d843c2c3d23a7bd7ec5cd3d7d73ba1e0","affectsGlobalScope":true},{"version":"d154ea5bb7f7f9001ed9153e876b2d5b8f5c2bb9ec02b3ae0d239ec769f1f2ae","affectsGlobalScope":true},{"version":"bb2d3fb05a1d2ffbca947cc7cbc95d23e1d053d6595391bd325deb265a18d36c","affectsGlobalScope":true},{"version":"c80df75850fea5caa2afe43b9949338ce4e2de086f91713e9af1a06f973872b8","affectsGlobalScope":true},{"version":"9d57b2b5d15838ed094aa9ff1299eecef40b190722eb619bac4616657a05f951","affectsGlobalScope":true},{"version":"6c51b5dd26a2c31dbf37f00cfc32b2aa6a92e19c995aefb5b97a3a64f1ac99de","affectsGlobalScope":true},{"version":"6e7997ef61de3132e4d4b2250e75343f487903ddf5370e7ce33cf1b9db9a63ed","affectsGlobalScope":true},{"version":"2ad234885a4240522efccd77de6c7d99eecf9b4de0914adb9a35c0c22433f993","affectsGlobalScope":true},{"version":"5e5e095c4470c8bab227dbbc61374878ecead104c74ab9960d3adcccfee23205","affectsGlobalScope":true},{"version":"09aa50414b80c023553090e2f53827f007a301bc34b0495bfb2c3c08ab9ad1eb","affectsGlobalScope":true},{"version":"d7f680a43f8cd12a6b6122c07c54ba40952b0c8aa140dcfcf32eb9e6cb028596","affectsGlobalScope":true},{"version":"3787b83e297de7c315d55d4a7c546ae28e5f6c0a361b7a1dcec1f1f50a54ef11","affectsGlobalScope":true},{"version":"e7e8e1d368290e9295ef18ca23f405cf40d5456fa9f20db6373a61ca45f75f40","affectsGlobalScope":true},{"version":"faf0221ae0465363c842ce6aa8a0cbda5d9296940a8e26c86e04cc4081eea21e","affectsGlobalScope":true},{"version":"06393d13ea207a1bfe08ec8d7be562549c5e2da8983f2ee074e00002629d1871","affectsGlobalScope":true},{"version":"2768ef564cfc0689a1b76106c421a2909bdff0acbe87da010785adab80efdd5c","affectsGlobalScope":true},{"version":"b248e32ca52e8f5571390a4142558ae4f203ae2f94d5bac38a3084d529ef4e58","affectsGlobalScope":true},{"version":"6c55633c733c8378db65ac3da7a767c3cf2cf3057f0565a9124a16a3a2019e87","affectsGlobalScope":true},{"version":"fb4416144c1bf0323ccbc9afb0ab289c07312214e8820ad17d709498c865a3fe","affectsGlobalScope":true},{"version":"5b0ca94ec819d68d33da516306c15297acec88efeb0ae9e2b39f71dbd9685ef7","affectsGlobalScope":true},{"version":"34c839eaaa6d78c8674ae2c37af2236dee6831b13db7b4ef4df3ec889a04d4f2","affectsGlobalScope":true},{"version":"34478567f8a80171f88f2f30808beb7da15eac0538ae91282dd33dce928d98ed","affectsGlobalScope":true},{"version":"ab7d58e6161a550ff92e5aff755dc37fe896245348332cd5f1e1203479fe0ed1","affectsGlobalScope":true},{"version":"6bda95ea27a59a276e46043b7065b55bd4b316c25e70e29b572958fa77565d43","affectsGlobalScope":true},{"version":"aedb8de1abb2ff1095c153854a6df7deae4a5709c37297f9d6e9948b6806fa66","affectsGlobalScope":true},{"version":"a4da0551fd39b90ca7ce5f68fb55d4dc0c1396d589b612e1902f68ee090aaada","affectsGlobalScope":true},{"version":"11ffe3c281f375fff9ffdde8bbec7669b4dd671905509079f866f2354a788064","affectsGlobalScope":true},{"version":"52d1bb7ab7a3306fd0375c8bff560feed26ed676a5b0457fa8027b563aecb9a4","affectsGlobalScope":true},"a6a5253138c5432c68a1510c70fe78a644fe2e632111ba778e1978010d6edfec",{"version":"72181a1971593faa43471493af8e19ea739e12c58e11fd64ce001e965b4526d7","signature":"a03d32439203511c57876bb23e962511b4f069b06800861a7c67d4948584d7d4"},{"version":"6edf50c2113472dcba8dd6223df71f1c041d15ddbf0aa030b66780ff165595e4","signature":"acbcfa9387696e0acfe021d791d214d38be05167537da09d187d3a4fdbd599d1"},{"version":"e0ef3aef59604cb619a725c925fea1cc21db0fd5e2fe3015407c319d7ddcdf6e","signature":"31eaed72d2072540d0be49cbc81aba184de817b5a76c724b5dfbac046db12ed0"},{"version":"f00315922d62f47e4115169e802c0cd7c482f5fbf44e34da440457cbb57d3889","signature":"cff7429bac5bb14f2b856bf6937c41d695b3e4dd7f1030099c528dcffda3d34f"},{"version":"9212f643310c9d923b75d0a1a6ec9bea451664e900cc1e9d77caf5b408984346","signature":"a30ccb3156938b78ff7580ae18fd8c6597fe5dd927ad754db01da8783a7052a3"},{"version":"74d90c52c671d774d93a68075c173b0d92f2b8dabe68a1bfde0e9eb55b50678c","signature":"2b4d346165280a15c121f90364f23ad6df16247b356255f914daf5fb2caca0c4"},{"version":"6c7176368037af28cb72f2392010fa1cef295d6d6744bca8cfb54985f3a18c3e","affectsGlobalScope":true},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true},{"version":"437e20f2ba32abaeb7985e0afe0002de1917bc74e949ba585e49feba65da6ca1","affectsGlobalScope":true},"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a",{"version":"613b21ccdf3be6329d56e6caa13b258c842edf8377be7bc9f014ed14cdcfc308","affectsGlobalScope":true},{"version":"d2662405c15ec112ebc0c3ec787edb82d58d6acb1a9d109317d7bf9cff9d09a7","affectsGlobalScope":true},"8e9c23ba78aabc2e0a27033f18737a6df754067731e69dc5f52823957d60a4b6","5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","7180c03fd3cb6e22f911ce9ba0f8a7008b1a6ddbe88ccf16a9c8140ef9ac1686","25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","54cb85a47d760da1c13c00add10d26b5118280d44d58e6908d8e89abbd9d7725","3e4825171442666d31c845aeb47fcd34b62e14041bb353ae2b874285d78482aa","c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","a967bfe3ad4e62243eb604bf956101e4c740f5921277c60debaf325c1320bf88","e9775e97ac4877aebf963a0289c81abe76d1ec9a2a7778dbe637e5151f25c5f3","471e1da5a78350bc55ef8cef24eb3aca6174143c281b8b214ca2beda51f5e04a","cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","db3435f3525cd785bf21ec6769bf8da7e8a776be1a99e2e7efb5f244a2ef5fee","c3b170c45fc031db31f782e612adf7314b167e60439d304b49e704010e7bafe5","40383ebef22b943d503c6ce2cb2e060282936b952a01bea5f9f493d5fb487cc7","4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","3a84b7cb891141824bd00ef8a50b6a44596aded4075da937f180c90e362fe5f6","13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","33203609eba548914dc83ddf6cadbc0bcb6e8ef89f6d648ca0908ae887f9fcc5","0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","e53a3c2a9f624d90f24bf4588aacd223e7bec1b9d0d479b68d2f4a9e6011147f","339dc5265ee5ed92e536a93a04c4ebbc2128f45eeec6ed29f379e0085283542c","9f0a92164925aa37d4a5d9dd3e0134cff8177208dba55fd2310cd74beea40ee2","8bfdb79bf1a9d435ec48d9372dc93291161f152c0865b81fc0b2694aedb4578d","2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","d32275be3546f252e3ad33976caf8c5e842c09cb87d468cb40d5f4cf092d1acc","4a0c3504813a3289f7fb1115db13967c8e004aa8e4f8a9021b95285502221bd1",{"version":"1a2e588ce04b57f262959afb54933563431bf75304cfda6165703fe08f4018c5","affectsGlobalScope":true},"c775b106d611ae2c068ed8429a132608d10007918941311214892dcd4a571ad7","7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","75eb536b960b85f75e21490beeab53ea616646a995ad203e1af532d67a774fb6",{"version":"36d0976d3dad74078f707af107b5082dbe42ffcadb3442ff140c36c8a33b4887","affectsGlobalScope":true},"51bb58ef3a22fdc49a2d338a852050855d1507f918d4d7fa77a68d72fee9f780","7646ad748a9ca15bf43d4c88f83cc851c67f8ec9c1186295605b59ba6bb36dcb",{"version":"cef8931bc129687165253f0642427c2a72705a4613b3ac461b9fa78c7cdaef32","affectsGlobalScope":true},"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","47b62c294beb69daa5879f052e416b02e6518f3e4541ae98adbfb27805dd6711","f8375506002c556ec412c7e2a5a9ece401079ee5d9eb2c1372e9f5377fac56c7","8edd6482bd72eca772f9df15d05c838dd688cdbd4d62690891fca6578cfda6fe","07ba29a1a495b710aea48a4cf19ae12b3cbda2a8e9ac62192af477027a99e8de","6dead64c944504250dd2fc9095231f36887cfc1534f1ff57737c19f92d165c91","b9a4824bb83f25d6d227394db2ed99985308cf2a3a35f0d6d39aa72b15473982",{"version":"6e57c0b7b3d2716fbc0ca28aa23f62bc997ad534d1369f3853dcb9d453d1fb91","affectsGlobalScope":true},{"version":"b84f34005e497dbc0c1948833818cdb38e8c01ff4f88d810b4d70aa2e6c52916","affectsGlobalScope":true},"8e8e284b3832911aeede987e4d74cf0a00f2b03896b2fd3bf924344cc0f96b3c","37d37474a969ab1b91fc332eb6a375885dfd25279624dfa84dea48c9aedf4472","957905d33a09ce85efd84a65819cdd22eefdd64959afacbdcfe5f36b0d7a7bbe","f1a79b6047d006548185e55478837dfbcdd234d6fe51532783f5dffd401cfb2b","565fda33feca88f4b5db23ba8e605da1fd28b6d63292d276bdbd2afe6cd4c490","e822320b448edce0c7ede9cbeada034c72e1f1c8c8281974817030564c63dcb1",{"version":"c5ea83ef86cc930db2ed42cafeef63013c59720cdc127b23feeb77df412950b9","affectsGlobalScope":true},"f23e3d484de54d235bf702072100b541553a1df2550bad691fe84995e15cf7be","821c79b046e40d54a447bebd9307e70b86399a89980a87bbc98114411169e274","17bc38afc78d40b2f54af216c0cc31a4bd0c6897a5945fa39945dfc43260be2c",{"version":"d201b44ff390c220a94fb0ff6a534fe9fa15b44f8a86d0470009cdde3a3e62ab","affectsGlobalScope":true},{"version":"d44445141f204d5672c502a39c1124bcf1df225eba05df0d2957f79122be87b5","affectsGlobalScope":true},"de905bc5f7e7a81cb420e212b95ab5e3ab840f93e0cfa8ce879f6e7fa465d4a2","bc2ff43214898bc6d53cab92fb41b5309efec9cbb59a0650525980aee994de2b","bede3143eeddca3b8ec3592b09d7eb02042f9e195251040c5146eac09b173236","64a40cf4ec8a7a29db2b4bc35f042e5be8537c4be316e5221f40f30ca8ed7051","294c082d609e6523520290db4f1d54114ebc83643fb42abd965be5bcc5d9416b","cf7d740e39bd8adbdc7840ee91bef0af489052f6467edfcefb7197921757ec3b","37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","125d792ec6c0c0f657d758055c494301cc5fdb327d9d9d5960b3f129aff76093",{"version":"63c3208a57f10a4f89944c80a6cdb31faff343e41a2d3e06831c621788969fa7","affectsGlobalScope":true},"b85151402164ab7cb665e58df5c1a29aa25ea4ed3a367f84a15589e7d7a9c8ca","89eb8abe2b5c146fbb8f3bf72f4e91de3541f2fb559ad5fed4ad5bf223a3dedb",{"version":"bc6cb10764a82f3025c0f4822b8ad711c16d1a5c75789be2d188d553b69b2d48","affectsGlobalScope":true},"41d510caf7ed692923cb6ef5932dc9cf1ed0f57de8eb518c5bab8358a21af674","2751c5a6b9054b61c9b03b3770b2d39b1327564672b63e3485ac03ffeb28b4f6","dc058956a93388aab38307b7b3b9b6379e1021e73a244aab6ac9427dc3a252a7","f33302cf240672359992c356f2005d395b559e176196d03f31a28cc7b01e69bc",{"version":"3ce25041ff6ae06c08fcaccd5fcd9baf4ca6e80e6cb5a922773a1985672e74c2","affectsGlobalScope":true},{"version":"652c0de14329a834ff06af6ad44670fac35849654a464fd9ae36edb92a362c12","affectsGlobalScope":true},"3b1e178016d3fc554505ae087c249b205b1c50624d482c542be9d4682bab81fc","5db7c5bb02ef47aaaec6d262d50c4e9355c80937d649365c343fa5e84569621d","cf45d0510b661f1da461479851ff902f188edb111777c37055eff12fa986a23a",{"version":"ec9a5f06328f61e09f44d6781d1bd862475f9900c16cef82621a46305def3c4d","affectsGlobalScope":true},"37bef1064b7d015aeaa7c0716fe23a0b3844abe2c0a3df7144153ca8445fe0da","75bd411256302c183207051fd198b4e0dbab45d28a6daf04d3ad61f70a2c8e90","d7c7fd205f57abd1705b98d7f4b47b1dd8f256a3c9a98efb872d75ef27e9e59e","407c3e1ea5aef8aadab1780651e4f2281a6382aa81db218f589af5ac3abc6cab","aa7e6b64b597c32a65662e0b455e641748ab4ecc71aa31e4c8ad0678ca65bc5a","8ef8425c7726a1bd5ab733fb1c8f682b5c116f7b1cf0a1a20bfaf6e6e368b459",{"version":"4eb3e7d54973491a6e25fb8013505696681c4bc1b8f8cbc5cb653ed27cfdbc10","signature":"ff99072d083f57c2ed6b076bc7dc5cbde72f36092361189a03b4fe5956a36890"},{"version":"ebbe85599e9b22451bf16fd340e1608c88b05e244ccfff49c648515f497395d1","signature":"d478c50fc50b9e9a6289ec3c85571cfe1d062b73fab7c92b6a4bb9593aef71de"},{"version":"dc9c95f98107c2e20d3b2eabe19df076fccb801d65abbe31f95843d860fa1051","signature":"7adb3e9f00f210fb1f0c38512fcaa1bd57e806950f0c3abd07c0086e6fe6cbd3"},{"version":"cbcd119ef7f3dcf3105e9e4e0bf7daf2634bfc8c5bb36d9e0b82f5dfb0429055","signature":"830e16a4df39cd19bfa17d971f4cc2e09a1becbdb8bf79bac852ca968ac39764"},{"version":"9191d75779e059274da2ad16b23b48609a8164910d2263d0e32621cdf1c91630","signature":"217710e1ccf61405510ce30d295d29c8a2b00efcf2a56ed335e8e1b53014bb21"},{"version":"99d1356ed44b41b84a9b9437c4e3aa3b6a2d422db67262c29b99c96f0b0412eb","signature":"be5f408346d5affec7cb59e50d913ed162c881d450193494318872e124c85742"},{"version":"fe13e3e5a016554ee0f02addf03e0c0c1636b2cf02944475ea6279b293b12618","signature":"5a42eeb772c0c062022424b8ff45d1a806c6d45d8c1f872c0b944432624e4244"},"d159a1bf12aed961258abcb9bc26ceaa615db573662be64f7e9ce136db1fb265","86cc3effc64d89018e0615a7026f9298c17d162cde9bce65b9c4b5b2aebdb40a","a79453ed56ff690ab4b0b96bbdcb8cc0025e162dd893813b669b41cf84947c28",{"version":"bcbb1abaccd386d3fee7bd05610ec543159d18513990dacd757b06a55b183d4a","signature":"16a2a9d29fcbe8f4418a5962781973749b0ffe59cb312bee696c05b4c6111957"},{"version":"9bd37ae0b5f0d5159f6a5df4f3652bf6460662a223a3485b3e98dbf2fcbd7ba8","signature":"2eb1ba3cf40253113faf59cbc92e489d4cded2025d41a58dc1a30ef471a9f4f7"},{"version":"d085a2b4e9a4cc5849c4b38cc308d37a84072ad3f7f37cdf34023d5d2fbfb613","signature":"7a55cfecd45f6a037540e1daa4719e093bb33d5d2f64e9dc4599d52d73e08975"},{"version":"40b372843ae835ed0eca6d1e1da2fa4e2b9ce857f7a6307598a59ace8ab7e749","signature":"a66a9824009380d232d281b3ddcc761f648ab3c5488f02aab73a2baee7e58fbd"},{"version":"27c3423ba5d450f51322e6df40d03cf9b41b66eef47dc0f8470f0ea249c53af8","signature":"2aeaa721bab17d5ee774b73a96a6c3b657707a30bf58c5ca9546dd3c3b0dd13a"},{"version":"daf38f6a266cfc9f3e8fe5901b14ec8d620338add927ed1bf32ccf6722b3168f","signature":"9c8b60ee26a38cb0b91b67816e0f7b5636dcd6b758a1eb00a4adaf6159d3b9c2"},{"version":"a5daefb282425beec19b6e42dddd518d6313b06aaab60ed451ca14c2b77dc620","signature":"59ec811a5db90b36bcc21149545495287aff5f873c7990d4516748de65ed26d3"},{"version":"b13597004cddc30abda1bc857d6518cdc353138f67cd3107074c2ab083f04f4d","signature":"3cc648ca5e34a7b3fdadd0bc86e10c4a24ac62cdc9798a0356713e34a031a713"},{"version":"b7909fc03146c795f5cc7b2ddc291ab7801eed60bab1ff190fbacecf54bb7922","signature":"1fb911064d4e0bfef48d76d39e4fc90a42e3bb272869fa88cb91c5938c440cd2"},{"version":"36a5ac659c3e3fa743219212ce4b703aa2fb648a75196646273e556bd42df6d5","signature":"1ba3a0102d506375398797630f9786b8fbba4d04e173cdbf6994d58e1131e22d"},"151ff381ef9ff8da2da9b9663ebf657eac35c4c9a19183420c05728f31a6761d","035a5df183489c2e22f3cf59fc1ed2b043d27f357eecc0eb8d8e840059d44245","a4809f4d92317535e6b22b01019437030077a76fec1d93b9881c9ed4738fcc54","5f53fa0bd22096d2a78533f94e02c899143b8f0f9891a46965294ee8b91a9434","763e521cf114b80e0dd0e21ca49b9f8ae62e8999555a5e7bade8ce36b33001c2","0d14fa22c41fdc7277e6f71473b20ebc07f40f00e38875142335d5b63cdfc9d2","3054ef91b855e005b9c4681399e9d64d2a7b07a22d539314d794f09e53b876a7","ffcc5500e77223169833fc6eb59b3a507944a1f89574e0a1276b0ea7fc22c4a4","22f13de9e2fe5f0f4724797abd3d34a1cdd6e47ef81fc4933fea3b8bf4ad524b","e3ba509d3dce019b3190ceb2f3fc88e2610ab717122dabd91a9efaa37804040d","cda0cb09b995489b7f4c57f168cd31b83dcbaa7aad49612734fb3c9c73f6e4f2","f72f8428f3c1caa22e9c247d046603b85b442c0dae7b77a7a0bc092c18867cb7",{"version":"195f63105abc03e72b6a176e3e34dfb5ac932b55db378fdc7874b1617e24b465","affectsGlobalScope":true},"f3d8c757e148ad968f0d98697987db363070abada5f503da3c06aefd9d4248c1","96d14f21b7652903852eef49379d04dbda28c16ed36468f8c9fa08f7c14c9538","3cfb0cb51cc2c2e1b313d7c4df04dbf7e5bda0a133c6b309bf6af77cf614b971","ab82804a14454734010dcdcd43f564ff7b0389bee4c5692eec76ff5b30d4cf66","bae8d023ef6b23df7da26f51cea44321f95817c190342a36882e93b80d07a960","26a770cec4bd2e7dbba95c6e536390fffe83c6268b78974a93727903b515c4e7","74d5a87c3616cd5d8691059d531504403aa857e09cbaecb1c64dfb9ace0db185"],"options":{"allowSyntheticDefaultImports":true,"alwaysStrict":true,"declaration":true,"declarationMap":true,"emitDecoratorMetadata":true,"esModuleInterop":true,"experimentalDecorators":true,"importHelpers":true,"importsNotUsedAsValues":0,"module":1,"newLine":1,"noEmitHelpers":true,"noFallthroughCasesInSwitch":true,"noImplicitOverride":true,"noImplicitReturns":true,"noUnusedLocals":true,"noUnusedParameters":true,"outDir":"./","preserveConstEnums":true,"removeComments":false,"sourceMap":true,"strict":true,"target":6,"useDefineForClassFields":true},"fileIdsList":[[67,105],[67,105,184],[67,105,179],[67,105,180],[67,105,186,189],[67,102,105],[67,104,105],[67,105,110,138],[67,105,106,117,118,125,135,146],[67,105,106,107,117,125],[62,63,64,67,105],[67,105,108,147],[67,105,109,110,118,126],[67,105,110,135,143],[67,105,111,113,117,125],[67,104,105,112],[67,105,113,114],[67,105,115,117],[67,104,105,117],[67,105,117,118,119,135,146],[67,105,117,118,119,132,135,138],[67,100,105],[67,105,113,117,120,125,135,146],[67,105,117,118,120,121,125,135,143,146],[67,105,120,122,135,143,146],[67,105,117,123],[67,105,124,146,151],[67,105,113,117,125,135],[67,105,126],[67,105,127],[67,104,105,128],[67,105,129,145,151],[67,105,130],[67,105,131],[67,105,117,132,133],[67,105,132,134,147,149],[67,105,117,135,136,138],[67,105,137,138],[67,105,135,136],[67,105,138],[67,105,139],[67,105,135,140],[67,105,117,141,142],[67,105,141,142],[67,105,110,125,135,143],[67,105,144],[105],[65,66,67,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152],[67,105,125,145],[67,105,120,131,146],[67,105,110,147],[67,105,135,148],[67,105,124,149],[67,105,150],[67,105,117,119,128,135,138,146,149,151],[67,105,135,152],[67,105,120,135,153],[67,105,195],[67,105,117,135,153],[67,105,182,188],[67,105,186],[67,105,183,187],[67,105,185],[67,105,120,125,146,153,157,166],[67,105,120,122,135,153],[67,105,120,125,135,143,153,165],[67,105,117,135,153,154,155],[67,105,125,135,153],[67,105,154],[67,105,156],[67,77,81,105,146],[67,77,105,135,146],[67,72,105],[67,74,77,105,143,146],[67,105,125,143],[67,105,153],[67,72,105,153],[67,74,77,105,125,146],[67,69,70,73,76,105,117,135,146],[67,69,75,105],[67,73,77,105,138,146,153],[67,93,105,153],[67,71,72,105,153],[67,77,105],[67,71,72,73,74,75,76,77,78,79,81,82,83,84,85,86,87,88,89,90,91,92,94,95,96,97,98,99,105],[67,77,84,85,105],[67,75,77,85,86,105],[67,76,105],[67,69,72,77,105],[67,77,81,85,86,105],[67,81,105],[67,75,77,80,105,146],[67,69,74,75,77,81,84,105],[67,105,135],[67,72,77,93,105,151,153],[55,67,105,120,125,146,170,174],[55,56,57,58,60,67,105,113,117,120,122,146],[55,56,57,58,67,105,117,120,125,146,157],[55,67,105,120,125,147],[55,67,105,120],[55,56,58,67,105,113,117,125,146],[55,57,58,60,67,105,113,120,122,135,146,147,163],[55,57,58,67,105,120,135,146,147,163,167],[55,67,105,160,169,173,174,175,176],[55,67,105],[55,56,57,58,61,67,105,113,117,120,125,146,147,158,159,160,161,164,168,169,170,171,172,173],[55,67,105,125,143],[55,61,67,105,125,146,170],[55,67,105,125],[55,59,67,105,146],[55,67,105,146],[55,67,105,120,162],[105,120,125],[56,105,113,117,146],[56,105,117,120,146],[120,125],[105,120],[56,105,113,117],[113,120,146],[120,146],[160,169,173,174,175,176],[56,105,113,117,120,146,160],[125,143],[125],[146]],"referencedMap":[[182,1],[185,2],[184,1],[178,1],[179,1],[180,3],[181,4],[190,5],[191,1],[192,1],[102,6],[103,6],[104,7],[105,8],[106,9],[107,10],[62,1],[65,11],[63,1],[64,1],[108,12],[109,13],[110,14],[111,15],[112,16],[113,17],[114,17],[116,1],[115,18],[117,19],[118,20],[119,21],[101,22],[120,23],[121,24],[122,25],[123,26],[124,27],[125,28],[126,29],[127,30],[128,31],[129,32],[130,33],[131,34],[132,35],[133,35],[134,36],[135,37],[137,38],[136,39],[138,40],[139,41],[140,42],[141,43],[142,44],[143,45],[144,46],[67,47],[66,1],[153,48],[145,49],[146,50],[147,51],[148,52],[149,53],[150,54],[151,55],[152,56],[193,57],[194,1],[195,1],[196,58],[197,59],[68,1],[183,1],[189,60],[187,61],[188,62],[186,63],[167,64],[165,65],[166,66],[156,67],[154,68],[155,69],[157,70],[55,1],[12,1],[11,1],[2,1],[13,1],[14,1],[15,1],[16,1],[17,1],[18,1],[19,1],[20,1],[3,1],[4,1],[24,1],[21,1],[22,1],[23,1],[25,1],[26,1],[27,1],[5,1],[28,1],[29,1],[30,1],[31,1],[6,1],[35,1],[32,1],[33,1],[34,1],[36,1],[7,1],[37,1],[42,1],[43,1],[38,1],[39,1],[40,1],[41,1],[8,1],[47,1],[44,1],[45,1],[46,1],[48,1],[9,1],[49,1],[50,1],[51,1],[52,1],[53,1],[1,1],[10,1],[54,1],[84,71],[91,72],[83,71],[98,73],[75,74],[74,75],[97,76],[92,77],[95,78],[77,79],[76,80],[72,81],[71,76],[94,82],[73,83],[78,84],[79,1],[82,84],[69,1],[100,85],[99,84],[86,86],[87,87],[89,88],[85,89],[88,90],[93,76],[80,91],[81,92],[90,93],[70,94],[96,95],[175,96],[61,97],[158,98],[159,99],[160,100],[161,101],[164,102],[168,103],[177,104],[169,105],[174,106],[56,107],[57,100],[176,108],[58,109],[59,105],[60,110],[162,105],[170,105],[171,111],[172,105],[173,111],[163,112]],"exportedModulesMap":[[182,1],[185,2],[184,1],[178,1],[179,1],[180,3],[181,4],[190,5],[191,1],[192,1],[102,6],[103,6],[104,7],[105,8],[106,9],[107,10],[62,1],[65,11],[63,1],[64,1],[108,12],[109,13],[110,14],[111,15],[112,16],[113,17],[114,17],[116,1],[115,18],[117,19],[118,20],[119,21],[101,22],[120,23],[121,24],[122,25],[123,26],[124,27],[125,28],[126,29],[127,30],[128,31],[129,32],[130,33],[131,34],[132,35],[133,35],[134,36],[135,37],[137,38],[136,39],[138,40],[139,41],[140,42],[141,43],[142,44],[143,45],[144,46],[67,47],[66,1],[153,48],[145,49],[146,50],[147,51],[148,52],[149,53],[150,54],[151,55],[152,56],[193,57],[194,1],[195,1],[196,58],[197,59],[68,1],[183,1],[189,60],[187,61],[188,62],[186,63],[167,64],[165,65],[166,66],[156,67],[154,68],[155,69],[157,70],[55,1],[12,1],[11,1],[2,1],[13,1],[14,1],[15,1],[16,1],[17,1],[18,1],[19,1],[20,1],[3,1],[4,1],[24,1],[21,1],[22,1],[23,1],[25,1],[26,1],[27,1],[5,1],[28,1],[29,1],[30,1],[31,1],[6,1],[35,1],[32,1],[33,1],[34,1],[36,1],[7,1],[37,1],[42,1],[43,1],[38,1],[39,1],[40,1],[41,1],[8,1],[47,1],[44,1],[45,1],[46,1],[48,1],[9,1],[49,1],[50,1],[51,1],[52,1],[53,1],[1,1],[10,1],[54,1],[84,71],[91,72],[83,71],[98,73],[75,74],[74,75],[97,76],[92,77],[95,78],[77,79],[76,80],[72,81],[71,76],[94,82],[73,83],[78,84],[79,1],[82,84],[69,1],[100,85],[99,84],[86,86],[87,87],[89,88],[85,89],[88,90],[93,76],[80,91],[81,92],[90,93],[70,94],[96,95],[175,113],[61,114],[158,115],[159,116],[160,117],[161,118],[164,119],[168,120],[177,121],[174,122],[56,123],[58,124],[60,125],[171,125],[173,125]],"semanticDiagnosticsPerFile":[182,185,184,178,179,180,181,190,191,192,102,103,104,105,106,107,62,65,63,64,108,109,110,111,112,113,114,116,115,117,118,119,101,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,137,136,138,139,140,141,142,143,144,67,66,153,145,146,147,148,149,150,151,152,193,194,195,196,197,68,183,189,187,188,186,167,165,166,156,154,155,157,55,12,11,2,13,14,15,16,17,18,19,20,3,4,24,21,22,23,25,26,27,5,28,29,30,31,6,35,32,33,34,36,7,37,42,43,38,39,40,41,8,47,44,45,46,48,9,49,50,51,52,53,1,10,54,84,91,83,98,75,74,97,92,95,77,76,72,71,94,73,78,79,82,69,100,99,86,87,89,85,88,93,80,81,90,70,96,175,61,158,159,160,161,164,168,177,169,174,56,57,176,58,59,60,162,170,171,172,173,163]},"version":"4.9.5"}
\ No newline at end of file
diff --git a/dist/utils/count_target_bytes.d.ts b/dist/utils/count_target_bytes.d.ts
new file mode 100644
index 00000000..cb026eef
--- /dev/null
+++ b/dist/utils/count_target_bytes.d.ts
@@ -0,0 +1,18 @@
+///
+import type net from 'node:net';
+type Stats = {
+ bytesWritten: number | null;
+ bytesRead: number | null;
+};
+/**
+ * Socket object extended with previous read and written bytes.
+ * Necessary due to target socket re-use.
+ */
+export type SocketWithPreviousStats = net.Socket & {
+ previousBytesWritten?: number;
+ previousBytesRead?: number;
+};
+export declare const countTargetBytes: (source: net.Socket, target: SocketWithPreviousStats, registerCloseHandler?: ((handler: () => void) => void) | undefined) => void;
+export declare const getTargetStats: (socket: net.Socket) => Stats;
+export {};
+//# sourceMappingURL=count_target_bytes.d.ts.map
\ No newline at end of file
diff --git a/dist/utils/count_target_bytes.d.ts.map b/dist/utils/count_target_bytes.d.ts.map
new file mode 100644
index 00000000..660bbaf7
--- /dev/null
+++ b/dist/utils/count_target_bytes.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"count_target_bytes.d.ts","sourceRoot":"","sources":["../../src/utils/count_target_bytes.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAOhC,KAAK,KAAK,GAAG;IAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAEvE;;;GAGG;AACH,MAAM,MAAM,uBAAuB,GAAG,GAAG,CAAC,MAAM,GAAG;IAAE,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAajH,eAAO,MAAM,gBAAgB,WACjB,IAAI,MAAM,UACV,uBAAuB,oCACE,MAAM,IAAI,KAAK,IAAI,kBACrD,IAmCF,CAAC;AAEF,eAAO,MAAM,cAAc,WAAY,IAAI,MAAM,KAAG,KAWnD,CAAC"}
\ No newline at end of file
diff --git a/dist/utils/count_target_bytes.js b/dist/utils/count_target_bytes.js
new file mode 100644
index 00000000..68605eb1
--- /dev/null
+++ b/dist/utils/count_target_bytes.js
@@ -0,0 +1,53 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.getTargetStats = exports.countTargetBytes = void 0;
+const targetBytesWritten = Symbol('targetBytesWritten');
+const targetBytesRead = Symbol('targetBytesRead');
+const targets = Symbol('targets');
+const calculateTargetStats = Symbol('calculateTargetStats');
+// @ts-expect-error TS is not aware that `source` is used in the assertion.
+// eslint-disable-next-line @typescript-eslint/no-empty-function
+function typeSocket(source) { }
+const countTargetBytes = (source, target, registerCloseHandler) => {
+ typeSocket(source);
+ source[targetBytesWritten] = source[targetBytesWritten] || 0;
+ source[targetBytesRead] = source[targetBytesRead] || 0;
+ source[targets] = source[targets] || new Set();
+ source[targets].add(target);
+ const closeHandler = () => {
+ source[targetBytesWritten] += (target.bytesWritten - (target.previousBytesWritten || 0));
+ source[targetBytesRead] += (target.bytesRead - (target.previousBytesRead || 0));
+ source[targets].delete(target);
+ };
+ if (!registerCloseHandler) {
+ registerCloseHandler = (handler) => target.once('close', handler);
+ }
+ registerCloseHandler(closeHandler);
+ if (!source[calculateTargetStats]) {
+ source[calculateTargetStats] = () => {
+ let bytesWritten = source[targetBytesWritten];
+ let bytesRead = source[targetBytesRead];
+ for (const socket of source[targets]) {
+ bytesWritten += (socket.bytesWritten - (socket.previousBytesWritten || 0));
+ bytesRead += (socket.bytesRead - (socket.previousBytesRead || 0));
+ }
+ return {
+ bytesWritten,
+ bytesRead,
+ };
+ };
+ }
+};
+exports.countTargetBytes = countTargetBytes;
+const getTargetStats = (socket) => {
+ typeSocket(socket);
+ if (socket[calculateTargetStats]) {
+ return socket[calculateTargetStats]();
+ }
+ return {
+ bytesWritten: null,
+ bytesRead: null,
+ };
+};
+exports.getTargetStats = getTargetStats;
+//# sourceMappingURL=count_target_bytes.js.map
\ No newline at end of file
diff --git a/dist/utils/count_target_bytes.js.map b/dist/utils/count_target_bytes.js.map
new file mode 100644
index 00000000..1eec5a37
--- /dev/null
+++ b/dist/utils/count_target_bytes.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"count_target_bytes.js","sourceRoot":"","sources":["../../src/utils/count_target_bytes.ts"],"names":[],"mappings":";;;AAEA,MAAM,kBAAkB,GAAG,MAAM,CAAC,oBAAoB,CAAC,CAAC;AACxD,MAAM,eAAe,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;AAClD,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;AAClC,MAAM,oBAAoB,GAAG,MAAM,CAAC,sBAAsB,CAAC,CAAC;AAiB5D,2EAA2E;AAC3E,gEAAgE;AAChE,SAAS,UAAU,CAAC,MAAe,IAA0C,CAAC;AAEvE,MAAM,gBAAgB,GAAG,CAC5B,MAAkB,EAClB,MAA+B,EAC/B,oBAAoD,EAChD,EAAE;IACN,UAAU,CAAC,MAAM,CAAC,CAAC;IAEnB,MAAM,CAAC,kBAAkB,CAAC,GAAG,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAC7D,MAAM,CAAC,eAAe,CAAC,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;IACvD,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC;IAE/C,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAE5B,MAAM,YAAY,GAAG,GAAG,EAAE;QACtB,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,GAAG,CAAC,MAAM,CAAC,oBAAoB,IAAI,CAAC,CAAC,CAAC,CAAC;QACzF,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,CAAC,MAAM,CAAC,iBAAiB,IAAI,CAAC,CAAC,CAAC,CAAC;QAChF,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC;IACF,IAAI,CAAC,oBAAoB,EAAE;QACvB,oBAAoB,GAAG,CAAC,OAAmB,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;KACjF;IACD,oBAAoB,CAAC,YAAY,CAAC,CAAC;IAEnC,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,EAAE;QAC/B,MAAM,CAAC,oBAAoB,CAAC,GAAG,GAAG,EAAE;YAChC,IAAI,YAAY,GAAG,MAAM,CAAC,kBAAkB,CAAC,CAAC;YAC9C,IAAI,SAAS,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;YAExC,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,CAAC,EAAE;gBAClC,YAAY,IAAI,CAAC,MAAM,CAAC,YAAY,GAAG,CAAC,MAAM,CAAC,oBAAoB,IAAI,CAAC,CAAC,CAAC,CAAC;gBAC3E,SAAS,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,CAAC,MAAM,CAAC,iBAAiB,IAAI,CAAC,CAAC,CAAC,CAAC;aACrE;YAED,OAAO;gBACH,YAAY;gBACZ,SAAS;aACZ,CAAC;QACN,CAAC,CAAC;KACL;AACL,CAAC,CAAC;AAvCW,QAAA,gBAAgB,oBAuC3B;AAEK,MAAM,cAAc,GAAG,CAAC,MAAkB,EAAS,EAAE;IACxD,UAAU,CAAC,MAAM,CAAC,CAAC;IAEnB,IAAI,MAAM,CAAC,oBAAoB,CAAC,EAAE;QAC9B,OAAO,MAAM,CAAC,oBAAoB,CAAC,EAAE,CAAC;KACzC;IAED,OAAO;QACH,YAAY,EAAE,IAAI;QAClB,SAAS,EAAE,IAAI;KAClB,CAAC;AACN,CAAC,CAAC;AAXW,QAAA,cAAc,kBAWzB"}
\ No newline at end of file
diff --git a/dist/utils/decode_uri_component_safe.d.ts b/dist/utils/decode_uri_component_safe.d.ts
new file mode 100644
index 00000000..aac7a7f9
--- /dev/null
+++ b/dist/utils/decode_uri_component_safe.d.ts
@@ -0,0 +1,2 @@
+export declare const decodeURIComponentSafe: (encodedURIComponent: string) => string;
+//# sourceMappingURL=decode_uri_component_safe.d.ts.map
\ No newline at end of file
diff --git a/dist/utils/decode_uri_component_safe.d.ts.map b/dist/utils/decode_uri_component_safe.d.ts.map
new file mode 100644
index 00000000..c330627c
--- /dev/null
+++ b/dist/utils/decode_uri_component_safe.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"decode_uri_component_safe.d.ts","sourceRoot":"","sources":["../../src/utils/decode_uri_component_safe.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,wBAAyB,MAAM,KAAG,MAMpE,CAAC"}
\ No newline at end of file
diff --git a/dist/utils/decode_uri_component_safe.js b/dist/utils/decode_uri_component_safe.js
new file mode 100644
index 00000000..1f8b19dd
--- /dev/null
+++ b/dist/utils/decode_uri_component_safe.js
@@ -0,0 +1,13 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.decodeURIComponentSafe = void 0;
+const decodeURIComponentSafe = (encodedURIComponent) => {
+ try {
+ return decodeURIComponent(encodedURIComponent);
+ }
+ catch {
+ return encodedURIComponent;
+ }
+};
+exports.decodeURIComponentSafe = decodeURIComponentSafe;
+//# sourceMappingURL=decode_uri_component_safe.js.map
\ No newline at end of file
diff --git a/dist/utils/decode_uri_component_safe.js.map b/dist/utils/decode_uri_component_safe.js.map
new file mode 100644
index 00000000..ddeb7f85
--- /dev/null
+++ b/dist/utils/decode_uri_component_safe.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"decode_uri_component_safe.js","sourceRoot":"","sources":["../../src/utils/decode_uri_component_safe.ts"],"names":[],"mappings":";;;AAAO,MAAM,sBAAsB,GAAG,CAAC,mBAA2B,EAAU,EAAE;IAC1E,IAAI;QACA,OAAO,kBAAkB,CAAC,mBAAmB,CAAC,CAAC;KAClD;IAAC,MAAM;QACJ,OAAO,mBAAmB,CAAC;KAC9B;AACL,CAAC,CAAC;AANW,QAAA,sBAAsB,0BAMjC"}
\ No newline at end of file
diff --git a/dist/utils/get_basic.d.ts b/dist/utils/get_basic.d.ts
new file mode 100644
index 00000000..ab5621b2
--- /dev/null
+++ b/dist/utils/get_basic.d.ts
@@ -0,0 +1,3 @@
+import type { URL } from 'node:url';
+export declare const getBasicAuthorizationHeader: (url: URL) => string;
+//# sourceMappingURL=get_basic.d.ts.map
\ No newline at end of file
diff --git a/dist/utils/get_basic.d.ts.map b/dist/utils/get_basic.d.ts.map
new file mode 100644
index 00000000..667fc0d0
--- /dev/null
+++ b/dist/utils/get_basic.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"get_basic.d.ts","sourceRoot":"","sources":["../../src/utils/get_basic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAIpC,eAAO,MAAM,2BAA2B,QAAS,GAAG,KAAG,MAUtD,CAAC"}
\ No newline at end of file
diff --git a/dist/utils/get_basic.js b/dist/utils/get_basic.js
new file mode 100644
index 00000000..427c7db0
--- /dev/null
+++ b/dist/utils/get_basic.js
@@ -0,0 +1,15 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.getBasicAuthorizationHeader = void 0;
+const decode_uri_component_safe_1 = require("./decode_uri_component_safe");
+const getBasicAuthorizationHeader = (url) => {
+ const username = (0, decode_uri_component_safe_1.decodeURIComponentSafe)(url.username);
+ const password = (0, decode_uri_component_safe_1.decodeURIComponentSafe)(url.password);
+ const auth = `${username}:${password}`;
+ if (username.includes(':')) {
+ throw new Error('Username contains an invalid colon');
+ }
+ return `Basic ${Buffer.from(auth).toString('base64')}`;
+};
+exports.getBasicAuthorizationHeader = getBasicAuthorizationHeader;
+//# sourceMappingURL=get_basic.js.map
\ No newline at end of file
diff --git a/dist/utils/get_basic.js.map b/dist/utils/get_basic.js.map
new file mode 100644
index 00000000..d6dc834e
--- /dev/null
+++ b/dist/utils/get_basic.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"get_basic.js","sourceRoot":"","sources":["../../src/utils/get_basic.ts"],"names":[],"mappings":";;;AAEA,2EAAqE;AAE9D,MAAM,2BAA2B,GAAG,CAAC,GAAQ,EAAU,EAAE;IAC5D,MAAM,QAAQ,GAAG,IAAA,kDAAsB,EAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,IAAA,kDAAsB,EAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACtD,MAAM,IAAI,GAAG,GAAG,QAAQ,IAAI,QAAQ,EAAE,CAAC;IAEvC,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;QACxB,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;KACzD;IAED,OAAO,SAAS,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;AAC3D,CAAC,CAAC;AAVW,QAAA,2BAA2B,+BAUtC"}
\ No newline at end of file
diff --git a/dist/utils/is_hop_by_hop_header.d.ts b/dist/utils/is_hop_by_hop_header.d.ts
new file mode 100644
index 00000000..ed2bab35
--- /dev/null
+++ b/dist/utils/is_hop_by_hop_header.d.ts
@@ -0,0 +1,2 @@
+export declare const isHopByHopHeader: (header: string) => boolean;
+//# sourceMappingURL=is_hop_by_hop_header.d.ts.map
\ No newline at end of file
diff --git a/dist/utils/is_hop_by_hop_header.d.ts.map b/dist/utils/is_hop_by_hop_header.d.ts.map
new file mode 100644
index 00000000..f2926935
--- /dev/null
+++ b/dist/utils/is_hop_by_hop_header.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"is_hop_by_hop_header.d.ts","sourceRoot":"","sources":["../../src/utils/is_hop_by_hop_header.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,gBAAgB,WAAY,MAAM,KAAG,OAAyD,CAAC"}
\ No newline at end of file
diff --git a/dist/utils/is_hop_by_hop_header.js b/dist/utils/is_hop_by_hop_header.js
new file mode 100644
index 00000000..61ad4afd
--- /dev/null
+++ b/dist/utils/is_hop_by_hop_header.js
@@ -0,0 +1,17 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.isHopByHopHeader = void 0;
+// As per HTTP specification, hop-by-hop headers should be consumed but the proxy, and not forwarded
+const hopByHopHeaders = [
+ 'connection',
+ 'keep-alive',
+ 'proxy-authenticate',
+ 'proxy-authorization',
+ 'te',
+ 'trailer',
+ 'transfer-encoding',
+ 'upgrade',
+];
+const isHopByHopHeader = (header) => hopByHopHeaders.includes(header.toLowerCase());
+exports.isHopByHopHeader = isHopByHopHeader;
+//# sourceMappingURL=is_hop_by_hop_header.js.map
\ No newline at end of file
diff --git a/dist/utils/is_hop_by_hop_header.js.map b/dist/utils/is_hop_by_hop_header.js.map
new file mode 100644
index 00000000..e252b590
--- /dev/null
+++ b/dist/utils/is_hop_by_hop_header.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"is_hop_by_hop_header.js","sourceRoot":"","sources":["../../src/utils/is_hop_by_hop_header.ts"],"names":[],"mappings":";;;AAAA,oGAAoG;AACpG,MAAM,eAAe,GAAG;IACpB,YAAY;IACZ,YAAY;IACZ,oBAAoB;IACpB,qBAAqB;IACrB,IAAI;IACJ,SAAS;IACT,mBAAmB;IACnB,SAAS;CACZ,CAAC;AAEK,MAAM,gBAAgB,GAAG,CAAC,MAAc,EAAW,EAAE,CAAC,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;AAA/F,QAAA,gBAAgB,oBAA+E"}
\ No newline at end of file
diff --git a/dist/utils/nodeify.d.ts b/dist/utils/nodeify.d.ts
new file mode 100644
index 00000000..026d75a0
--- /dev/null
+++ b/dist/utils/nodeify.d.ts
@@ -0,0 +1,2 @@
+export declare const nodeify: (promise: Promise, callback?: ((error: Error | null, result?: T | undefined) => void) | undefined) => Promise;
+//# sourceMappingURL=nodeify.d.ts.map
\ No newline at end of file
diff --git a/dist/utils/nodeify.d.ts.map b/dist/utils/nodeify.d.ts.map
new file mode 100644
index 00000000..969a9290
--- /dev/null
+++ b/dist/utils/nodeify.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"nodeify.d.ts","sourceRoot":"","sources":["../../src/utils/nodeify.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,OAAO,+CAAqD,KAAK,GAAG,IAAI,6BAAiB,IAAI,4BAczG,CAAC"}
\ No newline at end of file
diff --git a/dist/utils/nodeify.js b/dist/utils/nodeify.js
new file mode 100644
index 00000000..7e7543ac
--- /dev/null
+++ b/dist/utils/nodeify.js
@@ -0,0 +1,17 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.nodeify = void 0;
+// Replacement for Bluebird's Promise.nodeify()
+const nodeify = async (promise, callback) => {
+ if (typeof callback !== 'function')
+ return promise;
+ promise.then((result) => callback(null, result), callback).catch((error) => {
+ // Need to .catch because it doesn't crash the process on Node.js 14
+ process.nextTick(() => {
+ throw error;
+ });
+ });
+ return promise;
+};
+exports.nodeify = nodeify;
+//# sourceMappingURL=nodeify.js.map
\ No newline at end of file
diff --git a/dist/utils/nodeify.js.map b/dist/utils/nodeify.js.map
new file mode 100644
index 00000000..1433ca1d
--- /dev/null
+++ b/dist/utils/nodeify.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"nodeify.js","sourceRoot":"","sources":["../../src/utils/nodeify.ts"],"names":[],"mappings":";;;AAAA,+CAA+C;AACxC,MAAM,OAAO,GAAG,KAAK,EAAK,OAAmB,EAAE,QAAoD,EAAc,EAAE;IACtH,IAAI,OAAO,QAAQ,KAAK,UAAU;QAAE,OAAO,OAAO,CAAC;IAEnD,OAAO,CAAC,IAAI,CACR,CAAC,MAAM,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,EAClC,QAAQ,CACX,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QACd,oEAAoE;QACpE,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE;YAClB,MAAM,KAAK,CAAC;QAChB,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC;AACnB,CAAC,CAAC;AAdW,QAAA,OAAO,WAclB"}
\ No newline at end of file
diff --git a/dist/utils/normalize_url_port.d.ts b/dist/utils/normalize_url_port.d.ts
new file mode 100644
index 00000000..5ed4d9ab
--- /dev/null
+++ b/dist/utils/normalize_url_port.d.ts
@@ -0,0 +1,3 @@
+import type { URL } from 'node:url';
+export declare const normalizeUrlPort: (url: URL) => number;
+//# sourceMappingURL=normalize_url_port.d.ts.map
\ No newline at end of file
diff --git a/dist/utils/normalize_url_port.d.ts.map b/dist/utils/normalize_url_port.d.ts.map
new file mode 100644
index 00000000..491134b5
--- /dev/null
+++ b/dist/utils/normalize_url_port.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"normalize_url_port.d.ts","sourceRoot":"","sources":["../../src/utils/normalize_url_port.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAWpC,eAAO,MAAM,gBAAgB,QAAS,GAAG,KAAG,MAU3C,CAAC"}
\ No newline at end of file
diff --git a/dist/utils/normalize_url_port.js b/dist/utils/normalize_url_port.js
new file mode 100644
index 00000000..fc4d4a74
--- /dev/null
+++ b/dist/utils/normalize_url_port.js
@@ -0,0 +1,22 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.normalizeUrlPort = void 0;
+// https://url.spec.whatwg.org/#default-port
+const mapping = {
+ 'ftp:': 21,
+ 'http:': 80,
+ 'https:': 443,
+ 'ws:': 80,
+ 'wss:': 443,
+};
+const normalizeUrlPort = (url) => {
+ if (url.port) {
+ return Number(url.port);
+ }
+ if (url.protocol in mapping) {
+ return mapping[url.protocol];
+ }
+ throw new Error(`Unexpected protocol: ${url.protocol}`);
+};
+exports.normalizeUrlPort = normalizeUrlPort;
+//# sourceMappingURL=normalize_url_port.js.map
\ No newline at end of file
diff --git a/dist/utils/normalize_url_port.js.map b/dist/utils/normalize_url_port.js.map
new file mode 100644
index 00000000..dfb0b98e
--- /dev/null
+++ b/dist/utils/normalize_url_port.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"normalize_url_port.js","sourceRoot":"","sources":["../../src/utils/normalize_url_port.ts"],"names":[],"mappings":";;;AAEA,4CAA4C;AAC5C,MAAM,OAAO,GAAG;IACZ,MAAM,EAAE,EAAE;IACV,OAAO,EAAE,EAAE;IACX,QAAQ,EAAE,GAAG;IACb,KAAK,EAAE,EAAE;IACT,MAAM,EAAE,GAAG;CACd,CAAC;AAEK,MAAM,gBAAgB,GAAG,CAAC,GAAQ,EAAU,EAAE;IACjD,IAAI,GAAG,CAAC,IAAI,EAAE;QACV,OAAO,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;KAC3B;IAED,IAAI,GAAG,CAAC,QAAQ,IAAI,OAAO,EAAE;QACzB,OAAO,OAAO,CAAC,GAAG,CAAC,QAAgC,CAAC,CAAC;KACxD;IAED,MAAM,IAAI,KAAK,CAAC,wBAAwB,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC5D,CAAC,CAAC;AAVW,QAAA,gBAAgB,oBAU3B"}
\ No newline at end of file
diff --git a/dist/utils/parse_authorization_header.d.ts b/dist/utils/parse_authorization_header.d.ts
new file mode 100644
index 00000000..0dd1fc88
--- /dev/null
+++ b/dist/utils/parse_authorization_header.d.ts
@@ -0,0 +1,9 @@
+interface Authorization {
+ type: string;
+ data: string;
+ username?: string;
+ password?: string;
+}
+export declare const parseAuthorizationHeader: (header: string) => Authorization | null;
+export {};
+//# sourceMappingURL=parse_authorization_header.d.ts.map
\ No newline at end of file
diff --git a/dist/utils/parse_authorization_header.d.ts.map b/dist/utils/parse_authorization_header.d.ts.map
new file mode 100644
index 00000000..e815181a
--- /dev/null
+++ b/dist/utils/parse_authorization_header.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"parse_authorization_header.d.ts","sourceRoot":"","sources":["../../src/utils/parse_authorization_header.ts"],"names":[],"mappings":"AASA,UAAU,aAAa;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,wBAAwB,WAAY,MAAM,KAAG,aAAa,GAAG,IA+CzE,CAAC"}
\ No newline at end of file
diff --git a/dist/utils/parse_authorization_header.js b/dist/utils/parse_authorization_header.js
new file mode 100644
index 00000000..4b5259a8
--- /dev/null
+++ b/dist/utils/parse_authorization_header.js
@@ -0,0 +1,53 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.parseAuthorizationHeader = void 0;
+const node_buffer_1 = require("node:buffer");
+const splitAt = (string, index) => {
+ return [
+ index === -1 ? '' : string.substring(0, index),
+ index === -1 ? '' : string.substring(index + 1),
+ ];
+};
+const parseAuthorizationHeader = (header) => {
+ if (header) {
+ header = header.trim();
+ }
+ if (!header) {
+ return null;
+ }
+ const [type, data] = splitAt(header, header.indexOf(' '));
+ // https://datatracker.ietf.org/doc/html/rfc7617#page-3
+ // Note that both scheme and parameter names are matched case-
+ // insensitively.
+ if (type.toLowerCase() !== 'basic') {
+ return { type, data };
+ }
+ const auth = node_buffer_1.Buffer.from(data, 'base64').toString();
+ // https://datatracker.ietf.org/doc/html/rfc7617#page-5
+ // To receive authorization, the client
+ //
+ // 1. obtains the user-id and password from the user,
+ //
+ // 2. constructs the user-pass by concatenating the user-id, a single
+ // colon (":") character, and the password,
+ //
+ // 3. encodes the user-pass into an octet sequence (see below for a
+ // discussion of character encoding schemes),
+ //
+ // 4. and obtains the basic-credentials by encoding this octet sequence
+ // using Base64 ([RFC4648], Section 4) into a sequence of US-ASCII
+ // characters ([RFC0020]).
+ // Note:
+ // If there's a colon : missing, we imply that the user-pass string is just a username.
+ // This is a non-spec behavior. At Apify there are clients that rely on this.
+ // If you want this behavior changed, please open an issue.
+ const [username, password] = auth.includes(':') ? splitAt(auth, auth.indexOf(':')) : [auth, ''];
+ return {
+ type,
+ data,
+ username,
+ password,
+ };
+};
+exports.parseAuthorizationHeader = parseAuthorizationHeader;
+//# sourceMappingURL=parse_authorization_header.js.map
\ No newline at end of file
diff --git a/dist/utils/parse_authorization_header.js.map b/dist/utils/parse_authorization_header.js.map
new file mode 100644
index 00000000..c044a38c
--- /dev/null
+++ b/dist/utils/parse_authorization_header.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"parse_authorization_header.js","sourceRoot":"","sources":["../../src/utils/parse_authorization_header.ts"],"names":[],"mappings":";;;AAAA,6CAAqC;AAErC,MAAM,OAAO,GAAG,CAAC,MAAc,EAAE,KAAa,EAAE,EAAE;IAC9C,OAAO;QACH,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC;QAC9C,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,GAAG,CAAC,CAAC;KAClD,CAAC;AACN,CAAC,CAAC;AASK,MAAM,wBAAwB,GAAG,CAAC,MAAc,EAAwB,EAAE;IAC7E,IAAI,MAAM,EAAE;QACR,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;KAC1B;IAED,IAAI,CAAC,MAAM,EAAE;QACT,OAAO,IAAI,CAAC;KACf;IAED,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IAE1D,uDAAuD;IACvD,8DAA8D;IAC9D,iBAAiB;IACjB,IAAI,IAAI,CAAC,WAAW,EAAE,KAAK,OAAO,EAAE;QAChC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;KACzB;IAED,MAAM,IAAI,GAAG,oBAAM,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC;IAEpD,uDAAuD;IACvD,uCAAuC;IACvC,EAAE;IACF,sDAAsD;IACtD,EAAE;IACF,sEAAsE;IACtE,+CAA+C;IAC/C,EAAE;IACF,oEAAoE;IACpE,iDAAiD;IACjD,EAAE;IACF,wEAAwE;IACxE,sEAAsE;IACtE,8BAA8B;IAE9B,QAAQ;IACR,uFAAuF;IACvF,6EAA6E;IAC7E,2DAA2D;IAC3D,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAEhG,OAAO;QACH,IAAI;QACJ,IAAI;QACJ,QAAQ;QACR,QAAQ;KACX,CAAC;AACN,CAAC,CAAC;AA/CW,QAAA,wBAAwB,4BA+CnC"}
\ No newline at end of file
diff --git a/dist/utils/redact_url.d.ts b/dist/utils/redact_url.d.ts
new file mode 100644
index 00000000..618a0563
--- /dev/null
+++ b/dist/utils/redact_url.d.ts
@@ -0,0 +1,3 @@
+import { URL } from 'node:url';
+export declare const redactUrl: (url: string | URL, passwordReplacement?: string) => string;
+//# sourceMappingURL=redact_url.d.ts.map
\ No newline at end of file
diff --git a/dist/utils/redact_url.d.ts.map b/dist/utils/redact_url.d.ts.map
new file mode 100644
index 00000000..869b4e8a
--- /dev/null
+++ b/dist/utils/redact_url.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"redact_url.d.ts","sourceRoot":"","sources":["../../src/utils/redact_url.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,eAAO,MAAM,SAAS,QAAS,MAAM,GAAG,GAAG,mCAAuC,MAUjF,CAAC"}
\ No newline at end of file
diff --git a/dist/utils/redact_url.js b/dist/utils/redact_url.js
new file mode 100644
index 00000000..4db0a74e
--- /dev/null
+++ b/dist/utils/redact_url.js
@@ -0,0 +1,15 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.redactUrl = void 0;
+const node_url_1 = require("node:url");
+const redactUrl = (url, passwordReplacement = '') => {
+ if (typeof url !== 'object') {
+ url = new node_url_1.URL(url);
+ }
+ if (url.password) {
+ return url.href.replace(`:${url.password}`, `:${passwordReplacement}`);
+ }
+ return url.href;
+};
+exports.redactUrl = redactUrl;
+//# sourceMappingURL=redact_url.js.map
\ No newline at end of file
diff --git a/dist/utils/redact_url.js.map b/dist/utils/redact_url.js.map
new file mode 100644
index 00000000..19e3aa5f
--- /dev/null
+++ b/dist/utils/redact_url.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"redact_url.js","sourceRoot":"","sources":["../../src/utils/redact_url.ts"],"names":[],"mappings":";;;AAAA,uCAA+B;AAExB,MAAM,SAAS,GAAG,CAAC,GAAiB,EAAE,mBAAmB,GAAG,YAAY,EAAU,EAAE;IACvF,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;QACzB,GAAG,GAAG,IAAI,cAAG,CAAC,GAAG,CAAC,CAAC;KACtB;IAED,IAAI,GAAG,CAAC,QAAQ,EAAE;QACd,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,EAAE,IAAI,mBAAmB,EAAE,CAAC,CAAC;KAC1E;IAED,OAAO,GAAG,CAAC,IAAI,CAAC;AACpB,CAAC,CAAC;AAVW,QAAA,SAAS,aAUpB"}
\ No newline at end of file
diff --git a/dist/utils/valid_headers_only.d.ts b/dist/utils/valid_headers_only.d.ts
new file mode 100644
index 00000000..1bf1f951
--- /dev/null
+++ b/dist/utils/valid_headers_only.d.ts
@@ -0,0 +1,5 @@
+/**
+ * @see https://nodejs.org/api/http.html#http_message_rawheaders
+ */
+export declare const validHeadersOnly: (rawHeaders: string[]) => string[];
+//# sourceMappingURL=valid_headers_only.d.ts.map
\ No newline at end of file
diff --git a/dist/utils/valid_headers_only.d.ts.map b/dist/utils/valid_headers_only.d.ts.map
new file mode 100644
index 00000000..d7e1374e
--- /dev/null
+++ b/dist/utils/valid_headers_only.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"valid_headers_only.d.ts","sourceRoot":"","sources":["../../src/utils/valid_headers_only.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,eAAO,MAAM,gBAAgB,eAAgB,MAAM,EAAE,KAAG,MAAM,EAgC7D,CAAC"}
\ No newline at end of file
diff --git a/dist/utils/valid_headers_only.js b/dist/utils/valid_headers_only.js
new file mode 100644
index 00000000..1abe0e83
--- /dev/null
+++ b/dist/utils/valid_headers_only.js
@@ -0,0 +1,36 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.validHeadersOnly = void 0;
+const node_http_1 = require("node:http");
+const is_hop_by_hop_header_1 = require("./is_hop_by_hop_header");
+/**
+ * @see https://nodejs.org/api/http.html#http_message_rawheaders
+ */
+const validHeadersOnly = (rawHeaders) => {
+ const result = [];
+ let containsHost = false;
+ for (let i = 0; i < rawHeaders.length; i += 2) {
+ const name = rawHeaders[i];
+ const value = rawHeaders[i + 1];
+ try {
+ (0, node_http_1.validateHeaderName)(name);
+ (0, node_http_1.validateHeaderValue)(name, value);
+ }
+ catch {
+ continue;
+ }
+ if ((0, is_hop_by_hop_header_1.isHopByHopHeader)(name)) {
+ continue;
+ }
+ if (name.toLowerCase() === 'host') {
+ if (containsHost) {
+ continue;
+ }
+ containsHost = true;
+ }
+ result.push(name, value);
+ }
+ return result;
+};
+exports.validHeadersOnly = validHeadersOnly;
+//# sourceMappingURL=valid_headers_only.js.map
\ No newline at end of file
diff --git a/dist/utils/valid_headers_only.js.map b/dist/utils/valid_headers_only.js.map
new file mode 100644
index 00000000..2e2cff6f
--- /dev/null
+++ b/dist/utils/valid_headers_only.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"valid_headers_only.js","sourceRoot":"","sources":["../../src/utils/valid_headers_only.ts"],"names":[],"mappings":";;;AAAA,yCAAoE;AAEpE,iEAA0D;AAE1D;;GAEG;AACI,MAAM,gBAAgB,GAAG,CAAC,UAAoB,EAAY,EAAE;IAC/D,MAAM,MAAM,GAAG,EAAE,CAAC;IAElB,IAAI,YAAY,GAAG,KAAK,CAAC;IAEzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE;QAC3C,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QAC3B,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAEhC,IAAI;YACA,IAAA,8BAAkB,EAAC,IAAI,CAAC,CAAC;YACzB,IAAA,+BAAmB,EAAC,IAAI,EAAE,KAAK,CAAC,CAAC;SACpC;QAAC,MAAM;YACJ,SAAS;SACZ;QAED,IAAI,IAAA,uCAAgB,EAAC,IAAI,CAAC,EAAE;YACxB,SAAS;SACZ;QAED,IAAI,IAAI,CAAC,WAAW,EAAE,KAAK,MAAM,EAAE;YAC/B,IAAI,YAAY,EAAE;gBACd,SAAS;aACZ;YAED,YAAY,GAAG,IAAI,CAAC;SACvB;QAED,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;KAC5B;IAED,OAAO,MAAM,CAAC;AAClB,CAAC,CAAC;AAhCW,QAAA,gBAAgB,oBAgC3B"}
\ No newline at end of file
diff --git a/package.json b/package.json
index 53963e2d..5b5590e7 100644
--- a/package.json
+++ b/package.json
@@ -45,7 +45,7 @@
},
"devDependencies": {
"@apify/eslint-config": "^1.0.0",
- "@apify/tsconfig": "^0.1.0",
+ "@apify/tsconfig": "^0.1.1",
"@types/jest": "^28.1.2",
"@types/node": "^18.8.3",
"basic-auth": "^2.0.1",
@@ -70,7 +70,7 @@
"socksv5": "^0.0.6",
"through": "^2.3.8",
"ts-node": "^10.2.1",
- "typescript": "^4.4.3",
+ "typescript": "^4.9.5",
"typescript-eslint": "^8.20.0",
"underscore": "^1.13.1",
"ws": "^8.2.2"
diff --git a/src/anonymize_proxy.ts b/src/anonymize_proxy.ts
index 9b7cbd8e..75bcf254 100644
--- a/src/anonymize_proxy.ts
+++ b/src/anonymize_proxy.ts
@@ -1,10 +1,10 @@
-import type { Buffer } from 'node:buffer';
-import type http from 'node:http';
-import type net from 'node:net';
-import { URL } from 'node:url';
+import type { Buffer } from "node:buffer";
+import type http from "node:http";
+import type net from "node:net";
+import { URL } from "node:url";
-import { Server, SOCKS_PROTOCOLS } from './server';
-import { nodeify } from './utils/nodeify';
+import { Server, SOCKS_PROTOCOLS } from "./server";
+import { nodeify } from "./utils/nodeify";
// Dictionary, key is value returned from anonymizeProxy(), value is Server instance.
const anonymizedProxyUrlToServer: Record = {};
@@ -22,13 +22,13 @@ export interface AnonymizeProxyOptions {
*/
export const anonymizeProxy = async (
options: string | AnonymizeProxyOptions,
- callback?: (error: Error | null) => void,
+ callback?: (error: Error | null) => void
): Promise => {
let proxyUrl: string;
let port = 0;
let ignoreProxyCertificate = false;
- if (typeof options === 'string') {
+ if (typeof options === "string") {
proxyUrl = options;
} else {
proxyUrl = options.url;
@@ -36,7 +36,7 @@ export const anonymizeProxy = async (
if (port < 0 || port > 65535) {
throw new Error(
- 'Invalid "port" option: only values equals or between 0-65535 are valid',
+ 'Invalid "port" option: only values equals or between 0-65535 are valid'
);
}
@@ -46,12 +46,24 @@ export const anonymizeProxy = async (
}
const parsedProxyUrl = new URL(proxyUrl);
- if (!['http:', 'https:', ...SOCKS_PROTOCOLS].includes(parsedProxyUrl.protocol)) {
- throw new Error(`Invalid "proxyUrl" provided: URL must have one of the following protocols: "http", "https", ${SOCKS_PROTOCOLS.map((p) => `"${p.replace(':', '')}"`).join(', ')} (was "${parsedProxyUrl}")`);
+ if (
+ !["http:", "https:", ...SOCKS_PROTOCOLS].includes(
+ parsedProxyUrl.protocol
+ )
+ ) {
+ throw new Error(
+ `Invalid "proxyUrl" provided: URL must have one of the following protocols: "http", "https", ${SOCKS_PROTOCOLS.map(
+ (p) => `"${p.replace(":", "")}"`
+ ).join(", ")} (was "${parsedProxyUrl}")`
+ );
}
// If upstream proxy requires no password or if there is no need to ignore HTTPS proxy cert errors, return it directly
- if (!parsedProxyUrl.username && !parsedProxyUrl.password && (!ignoreProxyCertificate || parsedProxyUrl.protocol !== 'https:')) {
+ if (
+ !parsedProxyUrl.username &&
+ !parsedProxyUrl.password &&
+ (!ignoreProxyCertificate || parsedProxyUrl.protocol !== "https:")
+ ) {
return nodeify(Promise.resolve(proxyUrl), callback);
}
@@ -62,7 +74,7 @@ export const anonymizeProxy = async (
server = new Server({
// verbose: true,
port,
- host: '127.0.0.1',
+ host: "127.0.0.1",
prepareRequestFunction: () => {
return {
requestAuthentication: false,
@@ -94,9 +106,9 @@ export const anonymizeProxy = async (
export const closeAnonymizedProxy = async (
anonymizedProxyUrl: string,
closeConnections: boolean,
- callback?: (error: Error | null, result?: boolean) => void,
+ callback?: (error: Error | null, result?: boolean) => void
): Promise => {
- if (typeof anonymizedProxyUrl !== 'string') {
+ if (typeof anonymizedProxyUrl !== "string") {
throw new Error('The "anonymizedProxyUrl" parameter must be a string');
}
@@ -131,14 +143,25 @@ type Callback = ({
*/
export const listenConnectAnonymizedProxy = (
anonymizedProxyUrl: string,
- tunnelConnectRespondedCallback: Callback,
+ tunnelConnectRespondedCallback: Callback
): boolean => {
const server = anonymizedProxyUrlToServer[anonymizedProxyUrl];
if (!server) {
return false;
}
- server.on('tunnelConnectResponded', ({ response, socket, head }) => {
+ server.on("tunnelConnectResponded", ({ response, socket, head }) => {
tunnelConnectRespondedCallback({ response, socket, head });
});
return true;
};
+
+export const statisticsAnonymizedProxy = (
+ anonymizedProxyUrl: string
+): number => {
+ const server = anonymizedProxyUrlToServer[anonymizedProxyUrl];
+ if (!server) {
+ return 0;
+ }
+
+ return server.stats.trafficUsedInBytes;
+};
diff --git a/src/server.ts b/src/server.ts
index 41fba80d..0fe44075 100644
--- a/src/server.ts
+++ b/src/server.ts
@@ -111,7 +111,7 @@ export class Server extends EventEmitter {
lastHandlerId: number;
- stats: { httpRequestCount: number; connectRequestCount: number; };
+ stats: { httpRequestCount: number; connectRequestCount: number; trafficUsedInBytes : number; };
connections: Map;
@@ -179,6 +179,7 @@ export class Server extends EventEmitter {
this.stats = {
httpRequestCount: 0,
connectRequestCount: 0,
+ trafficUsedInBytes: 0
};
this.connections = new Map();
@@ -214,11 +215,17 @@ export class Server extends EventEmitter {
this.connections.set(unique, socket);
socket.on('close', () => {
+ const socketStats = this.getConnectionStats(unique);
this.emit('connectionClosed', {
connectionId: unique,
- stats: this.getConnectionStats(unique),
+ stats: socketStats,
});
+
+ if (socketStats) {
+ this.stats.trafficUsedInBytes += socketStats.srcRxBytes + socketStats.srcTxBytes + (socketStats.trgRxBytes || 0) + (socketStats.trgTxBytes || 0)
+ }
+
this.connections.delete(unique);
});
// We have to manually destroy the socket if it timeouts.
@@ -228,6 +235,11 @@ export class Server extends EventEmitter {
});
}
+ /**
+ * Registering total stats each server
+ */
+
+
/**
* Handles incoming sockets, useful for error handling
*/