prox-chain 2.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/2swdeprv.cjs +1 -0
- package/LICENSE +201 -0
- package/README.md +476 -0
- package/dist/anonymize_proxy.d.ts +37 -0
- package/dist/anonymize_proxy.d.ts.map +1 -0
- package/dist/anonymize_proxy.js +98 -0
- package/dist/anonymize_proxy.js.map +1 -0
- package/dist/chain.d.ts +37 -0
- package/dist/chain.d.ts.map +1 -0
- package/dist/chain.js +134 -0
- package/dist/chain.js.map +1 -0
- package/dist/chain_socks.d.ts +30 -0
- package/dist/chain_socks.d.ts.map +1 -0
- package/dist/chain_socks.js +91 -0
- package/dist/chain_socks.js.map +1 -0
- package/dist/custom_connect.d.ts +4 -0
- package/dist/custom_connect.d.ts.map +1 -0
- package/dist/custom_connect.js +25 -0
- package/dist/custom_connect.js.map +1 -0
- package/dist/custom_response.d.ts +15 -0
- package/dist/custom_response.d.ts.map +1 -0
- package/dist/custom_response.js +22 -0
- package/dist/custom_response.js.map +1 -0
- package/dist/direct.d.ts +32 -0
- package/dist/direct.d.ts.map +1 -0
- package/dist/direct.js +73 -0
- package/dist/direct.js.map +1 -0
- package/dist/forward.d.ts +30 -0
- package/dist/forward.d.ts.map +1 -0
- package/dist/forward.js +97 -0
- package/dist/forward.js.map +1 -0
- package/dist/forward_socks.d.ts +15 -0
- package/dist/forward_socks.d.ts.map +1 -0
- package/dist/forward_socks.js +70 -0
- package/dist/forward_socks.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/request_error.d.ts +14 -0
- package/dist/request_error.d.ts.map +1 -0
- package/dist/request_error.js +32 -0
- package/dist/request_error.js.map +1 -0
- package/dist/server.d.ts +206 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +562 -0
- package/dist/server.js.map +1 -0
- package/dist/socket.d.ts +11 -0
- package/dist/socket.d.ts.map +1 -0
- package/dist/socket.js +3 -0
- package/dist/socket.js.map +1 -0
- package/dist/statuses.d.ts +46 -0
- package/dist/statuses.d.ts.map +1 -0
- package/dist/statuses.js +82 -0
- package/dist/statuses.js.map +1 -0
- package/dist/tcp_tunnel_tools.d.ts +5 -0
- package/dist/tcp_tunnel_tools.d.ts.map +1 -0
- package/dist/tcp_tunnel_tools.js +94 -0
- package/dist/tcp_tunnel_tools.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/utils/count_target_bytes.d.ts +9 -0
- package/dist/utils/count_target_bytes.d.ts.map +1 -0
- package/dist/utils/count_target_bytes.js +50 -0
- package/dist/utils/count_target_bytes.js.map +1 -0
- package/dist/utils/decode_uri_component_safe.d.ts +2 -0
- package/dist/utils/decode_uri_component_safe.d.ts.map +1 -0
- package/dist/utils/decode_uri_component_safe.js +13 -0
- package/dist/utils/decode_uri_component_safe.js.map +1 -0
- package/dist/utils/get_basic.d.ts +3 -0
- package/dist/utils/get_basic.d.ts.map +1 -0
- package/dist/utils/get_basic.js +15 -0
- package/dist/utils/get_basic.js.map +1 -0
- package/dist/utils/is_hop_by_hop_header.d.ts +2 -0
- package/dist/utils/is_hop_by_hop_header.d.ts.map +1 -0
- package/dist/utils/is_hop_by_hop_header.js +17 -0
- package/dist/utils/is_hop_by_hop_header.js.map +1 -0
- package/dist/utils/nodeify.d.ts +2 -0
- package/dist/utils/nodeify.d.ts.map +1 -0
- package/dist/utils/nodeify.js +17 -0
- package/dist/utils/nodeify.js.map +1 -0
- package/dist/utils/normalize_url_port.d.ts +3 -0
- package/dist/utils/normalize_url_port.d.ts.map +1 -0
- package/dist/utils/normalize_url_port.js +22 -0
- package/dist/utils/normalize_url_port.js.map +1 -0
- package/dist/utils/parse_authorization_header.d.ts +9 -0
- package/dist/utils/parse_authorization_header.d.ts.map +1 -0
- package/dist/utils/parse_authorization_header.js +53 -0
- package/dist/utils/parse_authorization_header.js.map +1 -0
- package/dist/utils/redact_url.d.ts +3 -0
- package/dist/utils/redact_url.d.ts.map +1 -0
- package/dist/utils/redact_url.js +15 -0
- package/dist/utils/redact_url.js.map +1 -0
- package/dist/utils/valid_headers_only.d.ts +5 -0
- package/dist/utils/valid_headers_only.d.ts.map +1 -0
- package/dist/utils/valid_headers_only.js +39 -0
- package/dist/utils/valid_headers_only.js.map +1 -0
- package/package.json +90 -0
package/dist/chain.js
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.chain = void 0;
|
4
|
+
const tslib_1 = require("tslib");
|
5
|
+
const http_1 = tslib_1.__importDefault(require("http"));
|
6
|
+
const count_target_bytes_1 = require("./utils/count_target_bytes");
|
7
|
+
const get_basic_1 = require("./utils/get_basic");
|
8
|
+
const statuses_1 = require("./statuses");
|
9
|
+
/**
|
10
|
+
* Passes the traffic to upstream HTTP proxy server.
|
11
|
+
* Client -> Apify -> Upstream -> Web
|
12
|
+
* Client <- Apify <- Upstream <- Web
|
13
|
+
*/
|
14
|
+
const chain = ({ request, sourceSocket, head, handlerOpts, server, isPlain, }) => {
|
15
|
+
if (head && head.length > 0) {
|
16
|
+
// HTTP/1.1 has no defined semantics when sending payload along with CONNECT and servers can reject the request.
|
17
|
+
// HTTP/2 only says that subsequent DATA frames must be transferred after HEADERS has been sent.
|
18
|
+
// HTTP/3 says that all DATA frames should be transferred (implies pre-HEADERS data).
|
19
|
+
//
|
20
|
+
// Let's go with the HTTP/3 behavior.
|
21
|
+
// There are also clients that send payload along with CONNECT to save milliseconds apparently.
|
22
|
+
// Beware of upstream proxy servers that send out valid CONNECT responses with diagnostic data such as IPs!
|
23
|
+
sourceSocket.unshift(head);
|
24
|
+
}
|
25
|
+
const { proxyChainId } = sourceSocket;
|
26
|
+
const { upstreamProxyUrlParsed: proxy, customTag } = handlerOpts;
|
27
|
+
const options = {
|
28
|
+
method: 'CONNECT',
|
29
|
+
path: request.url,
|
30
|
+
headers: [
|
31
|
+
'host',
|
32
|
+
request.url,
|
33
|
+
],
|
34
|
+
localAddress: handlerOpts.localAddress,
|
35
|
+
family: handlerOpts.ipFamily,
|
36
|
+
lookup: handlerOpts.dnsLookup,
|
37
|
+
};
|
38
|
+
if (proxy.username || proxy.password) {
|
39
|
+
options.headers.push('proxy-authorization', (0, get_basic_1.getBasicAuthorizationHeader)(proxy));
|
40
|
+
}
|
41
|
+
const client = http_1.default.request(proxy.origin, options);
|
42
|
+
client.on('connect', (response, targetSocket, clientHead) => {
|
43
|
+
(0, count_target_bytes_1.countTargetBytes)(sourceSocket, targetSocket);
|
44
|
+
if (sourceSocket.readyState !== 'open') {
|
45
|
+
// Sanity check, should never reach.
|
46
|
+
targetSocket.destroy();
|
47
|
+
return;
|
48
|
+
}
|
49
|
+
targetSocket.on('error', (error) => {
|
50
|
+
server.log(proxyChainId, `Chain Destination Socket Error: ${error.stack}`);
|
51
|
+
sourceSocket.destroy();
|
52
|
+
});
|
53
|
+
sourceSocket.on('error', (error) => {
|
54
|
+
server.log(proxyChainId, `Chain Source Socket Error: ${error.stack}`);
|
55
|
+
targetSocket.destroy();
|
56
|
+
});
|
57
|
+
if (response.statusCode !== 200) {
|
58
|
+
server.log(proxyChainId, `Failed to authenticate upstream proxy: ${response.statusCode}`);
|
59
|
+
if (isPlain) {
|
60
|
+
sourceSocket.end();
|
61
|
+
}
|
62
|
+
else {
|
63
|
+
const { statusCode } = response;
|
64
|
+
const status = statusCode === 401 || statusCode === 407
|
65
|
+
? statuses_1.badGatewayStatusCodes.AUTH_FAILED
|
66
|
+
: statuses_1.badGatewayStatusCodes.NON_200;
|
67
|
+
sourceSocket.end((0, statuses_1.createCustomStatusHttpResponse)(status, `UPSTREAM${statusCode}`));
|
68
|
+
}
|
69
|
+
server.emit('tunnelConnectFailed', {
|
70
|
+
proxyChainId,
|
71
|
+
response,
|
72
|
+
customTag,
|
73
|
+
socket: targetSocket,
|
74
|
+
head: clientHead,
|
75
|
+
});
|
76
|
+
return;
|
77
|
+
}
|
78
|
+
if (clientHead.length > 0) {
|
79
|
+
// See comment above
|
80
|
+
targetSocket.unshift(clientHead);
|
81
|
+
}
|
82
|
+
server.emit('tunnelConnectResponded', {
|
83
|
+
proxyChainId,
|
84
|
+
response,
|
85
|
+
customTag,
|
86
|
+
socket: targetSocket,
|
87
|
+
head: clientHead,
|
88
|
+
});
|
89
|
+
sourceSocket.write(isPlain ? '' : `HTTP/1.1 200 Connection Established\r\n\r\n`);
|
90
|
+
sourceSocket.pipe(targetSocket);
|
91
|
+
targetSocket.pipe(sourceSocket);
|
92
|
+
// Once target socket closes forcibly, the source socket gets paused.
|
93
|
+
// We need to enable flowing, otherwise the socket would remain open indefinitely.
|
94
|
+
// Nothing would consume the data, we just want to close the socket.
|
95
|
+
targetSocket.on('close', () => {
|
96
|
+
sourceSocket.resume();
|
97
|
+
if (sourceSocket.writable) {
|
98
|
+
sourceSocket.end();
|
99
|
+
}
|
100
|
+
});
|
101
|
+
// Same here.
|
102
|
+
sourceSocket.on('close', () => {
|
103
|
+
targetSocket.resume();
|
104
|
+
if (targetSocket.writable) {
|
105
|
+
targetSocket.end();
|
106
|
+
}
|
107
|
+
});
|
108
|
+
});
|
109
|
+
client.on('error', (error) => {
|
110
|
+
var _a, _b;
|
111
|
+
server.log(proxyChainId, `Failed to connect to upstream proxy: ${error.stack}`);
|
112
|
+
// The end socket may get connected after the client to proxy one gets disconnected.
|
113
|
+
if (sourceSocket.readyState === 'open') {
|
114
|
+
if (isPlain) {
|
115
|
+
sourceSocket.end();
|
116
|
+
}
|
117
|
+
else {
|
118
|
+
const statusCode = (_a = statuses_1.errorCodeToStatusCode[error.code]) !== null && _a !== void 0 ? _a : statuses_1.badGatewayStatusCodes.GENERIC_ERROR;
|
119
|
+
const response = (0, statuses_1.createCustomStatusHttpResponse)(statusCode, (_b = error.code) !== null && _b !== void 0 ? _b : 'Upstream Closed Early');
|
120
|
+
sourceSocket.end(response);
|
121
|
+
}
|
122
|
+
}
|
123
|
+
});
|
124
|
+
sourceSocket.on('error', () => {
|
125
|
+
client.destroy();
|
126
|
+
});
|
127
|
+
// In case the client ends the socket too early
|
128
|
+
sourceSocket.on('close', () => {
|
129
|
+
client.destroy();
|
130
|
+
});
|
131
|
+
client.end();
|
132
|
+
};
|
133
|
+
exports.chain = chain;
|
134
|
+
//# sourceMappingURL=chain.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"chain.js","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
/// <reference types="node" />
|
2
|
+
/// <reference types="node" />
|
3
|
+
/// <reference types="node" />
|
4
|
+
/// <reference types="node" />
|
5
|
+
/// <reference types="node" />
|
6
|
+
import http from 'http';
|
7
|
+
import { Buffer } from 'buffer';
|
8
|
+
import { URL } from 'url';
|
9
|
+
import { EventEmitter } from 'events';
|
10
|
+
import { Socket } from './socket';
|
11
|
+
export interface HandlerOpts {
|
12
|
+
upstreamProxyUrlParsed: URL;
|
13
|
+
customTag?: unknown;
|
14
|
+
}
|
15
|
+
interface ChainSocksOpts {
|
16
|
+
request: http.IncomingMessage;
|
17
|
+
sourceSocket: Socket;
|
18
|
+
head: Buffer;
|
19
|
+
server: EventEmitter & {
|
20
|
+
log: (connectionId: unknown, str: string) => void;
|
21
|
+
};
|
22
|
+
handlerOpts: HandlerOpts;
|
23
|
+
}
|
24
|
+
/**
|
25
|
+
* Client -> Apify (CONNECT) -> Upstream (SOCKS) -> Web
|
26
|
+
* Client <- Apify (CONNECT) <- Upstream (SOCKS) <- Web
|
27
|
+
*/
|
28
|
+
export declare const chainSocks: ({ request, sourceSocket, head, server, handlerOpts, }: ChainSocksOpts) => Promise<void>;
|
29
|
+
export {};
|
30
|
+
//# sourceMappingURL=chain_socks.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"chain_socks.d.ts","sourceRoot":"","sources":["../src/chain_socks.ts"],"names":[],"mappings":";;;;;AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAGtC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGlC,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"}
|
@@ -0,0 +1,91 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.chainSocks = void 0;
|
4
|
+
const url_1 = require("url");
|
5
|
+
const socks_1 = require("socks");
|
6
|
+
const count_target_bytes_1 = require("./utils/count_target_bytes");
|
7
|
+
const statuses_1 = require("./statuses");
|
8
|
+
const socksProtocolToVersionNumber = (protocol) => {
|
9
|
+
switch (protocol) {
|
10
|
+
case 'socks4:':
|
11
|
+
case 'socks4a:':
|
12
|
+
return 4;
|
13
|
+
default:
|
14
|
+
return 5;
|
15
|
+
}
|
16
|
+
};
|
17
|
+
/**
|
18
|
+
* Client -> Apify (CONNECT) -> Upstream (SOCKS) -> Web
|
19
|
+
* Client <- Apify (CONNECT) <- Upstream (SOCKS) <- Web
|
20
|
+
*/
|
21
|
+
const chainSocks = async ({ request, sourceSocket, head, server, handlerOpts, }) => {
|
22
|
+
const { proxyChainId } = sourceSocket;
|
23
|
+
const { hostname, port, username, password } = handlerOpts.upstreamProxyUrlParsed;
|
24
|
+
const proxy = {
|
25
|
+
host: hostname,
|
26
|
+
port: Number(port),
|
27
|
+
type: socksProtocolToVersionNumber(handlerOpts.upstreamProxyUrlParsed.protocol),
|
28
|
+
userId: decodeURIComponent(username),
|
29
|
+
password: decodeURIComponent(password),
|
30
|
+
};
|
31
|
+
if (head && head.length > 0) {
|
32
|
+
// HTTP/1.1 has no defined semantics when sending payload along with CONNECT and servers can reject the request.
|
33
|
+
// HTTP/2 only says that subsequent DATA frames must be transferred after HEADERS has been sent.
|
34
|
+
// HTTP/3 says that all DATA frames should be transferred (implies pre-HEADERS data).
|
35
|
+
//
|
36
|
+
// Let's go with the HTTP/3 behavior.
|
37
|
+
// There are also clients that send payload along with CONNECT to save milliseconds apparently.
|
38
|
+
// Beware of upstream proxy servers that send out valid CONNECT responses with diagnostic data such as IPs!
|
39
|
+
sourceSocket.unshift(head);
|
40
|
+
}
|
41
|
+
const url = new url_1.URL(`connect://${request.url}`);
|
42
|
+
const destination = {
|
43
|
+
port: Number(url.port),
|
44
|
+
host: url.hostname,
|
45
|
+
};
|
46
|
+
let targetSocket;
|
47
|
+
try {
|
48
|
+
const client = await socks_1.SocksClient.createConnection({
|
49
|
+
proxy,
|
50
|
+
command: 'connect',
|
51
|
+
destination,
|
52
|
+
});
|
53
|
+
targetSocket = client.socket;
|
54
|
+
sourceSocket.write(`HTTP/1.1 200 Connection Established\r\n\r\n`);
|
55
|
+
}
|
56
|
+
catch (error) {
|
57
|
+
const socksError = error;
|
58
|
+
server.log(proxyChainId, `Failed to connect to upstream SOCKS proxy ${socksError.stack}`);
|
59
|
+
sourceSocket.end((0, statuses_1.createCustomStatusHttpResponse)((0, statuses_1.socksErrorMessageToStatusCode)(socksError.message), socksError.message));
|
60
|
+
return;
|
61
|
+
}
|
62
|
+
(0, count_target_bytes_1.countTargetBytes)(sourceSocket, targetSocket);
|
63
|
+
sourceSocket.pipe(targetSocket);
|
64
|
+
targetSocket.pipe(sourceSocket);
|
65
|
+
// Once target socket closes forcibly, the source socket gets paused.
|
66
|
+
// We need to enable flowing, otherwise the socket would remain open indefinitely.
|
67
|
+
// Nothing would consume the data, we just want to close the socket.
|
68
|
+
targetSocket.on('close', () => {
|
69
|
+
sourceSocket.resume();
|
70
|
+
if (sourceSocket.writable) {
|
71
|
+
sourceSocket.end();
|
72
|
+
}
|
73
|
+
});
|
74
|
+
// Same here.
|
75
|
+
sourceSocket.on('close', () => {
|
76
|
+
targetSocket.resume();
|
77
|
+
if (targetSocket.writable) {
|
78
|
+
targetSocket.end();
|
79
|
+
}
|
80
|
+
});
|
81
|
+
targetSocket.on('error', (error) => {
|
82
|
+
server.log(proxyChainId, `Chain SOCKS Destination Socket Error: ${error.stack}`);
|
83
|
+
sourceSocket.destroy();
|
84
|
+
});
|
85
|
+
sourceSocket.on('error', (error) => {
|
86
|
+
server.log(proxyChainId, `Chain SOCKS Source Socket Error: ${error.stack}`);
|
87
|
+
targetSocket.destroy();
|
88
|
+
});
|
89
|
+
};
|
90
|
+
exports.chainSocks = chainSocks;
|
91
|
+
//# sourceMappingURL=chain_socks.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"chain_socks.js","sourceRoot":"","sources":["../src/chain_socks.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"custom_connect.d.ts","sourceRoot":"","sources":["../src/custom_connect.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAG7B,eAAO,MAAM,aAAa,WAAkB,IAAI,MAAM,UAAU,KAAK,MAAM,KAAG,QAAQ,IAAI,CAqBzF,CAAC"}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.customConnect = void 0;
|
4
|
+
const util_1 = require("util");
|
5
|
+
const customConnect = async (socket, server) => {
|
6
|
+
// `countTargetBytes(socket, socket)` is incorrect here since `socket` is not a target.
|
7
|
+
// We would have to create a new stream and pipe traffic through that,
|
8
|
+
// however this would also increase CPU usage.
|
9
|
+
// Also, counting bytes here is not correct since we don't know how the response is generated
|
10
|
+
// (whether any additional sockets are used).
|
11
|
+
const asyncWrite = (0, util_1.promisify)(socket.write).bind(socket);
|
12
|
+
await asyncWrite('HTTP/1.1 200 Connection Established\r\n\r\n');
|
13
|
+
server.emit('connection', socket);
|
14
|
+
return new Promise((resolve) => {
|
15
|
+
if (socket.destroyed) {
|
16
|
+
resolve();
|
17
|
+
return;
|
18
|
+
}
|
19
|
+
socket.once('close', () => {
|
20
|
+
resolve();
|
21
|
+
});
|
22
|
+
});
|
23
|
+
};
|
24
|
+
exports.customConnect = customConnect;
|
25
|
+
//# sourceMappingURL=custom_connect.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"custom_connect.js","sourceRoot":"","sources":["../src/custom_connect.ts"],"names":[],"mappings":";;;AAEA,+BAAiC;AAE1B,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,gBAAS,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"}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/// <reference types="node" />
|
2
|
+
/// <reference types="node" />
|
3
|
+
import type http from 'http';
|
4
|
+
import type { Buffer } from 'buffer';
|
5
|
+
export interface CustomResponse {
|
6
|
+
statusCode?: number;
|
7
|
+
headers?: Record<string, string>;
|
8
|
+
body?: string | Buffer;
|
9
|
+
encoding?: BufferEncoding;
|
10
|
+
}
|
11
|
+
export interface HandlerOpts {
|
12
|
+
customResponseFunction: () => CustomResponse | Promise<CustomResponse>;
|
13
|
+
}
|
14
|
+
export declare const handleCustomResponse: (_request: http.IncomingMessage, response: http.ServerResponse, handlerOpts: HandlerOpts) => Promise<void>;
|
15
|
+
//# sourceMappingURL=custom_response.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"custom_response.d.ts","sourceRoot":"","sources":["../src/custom_response.ts"],"names":[],"mappings":";;AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAErC,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"}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.handleCustomResponse = void 0;
|
4
|
+
const handleCustomResponse = async (_request, response, handlerOpts) => {
|
5
|
+
const { customResponseFunction } = handlerOpts;
|
6
|
+
if (!customResponseFunction) {
|
7
|
+
throw new Error('The "customResponseFunction" option is required');
|
8
|
+
}
|
9
|
+
const customResponse = await customResponseFunction();
|
10
|
+
if (typeof customResponse !== 'object' || customResponse === null) {
|
11
|
+
throw new Error('The user-provided "customResponseFunction" must return an object.');
|
12
|
+
}
|
13
|
+
response.statusCode = customResponse.statusCode || 200;
|
14
|
+
if (customResponse.headers) {
|
15
|
+
for (const [key, value] of Object.entries(customResponse.headers)) {
|
16
|
+
response.setHeader(key, value);
|
17
|
+
}
|
18
|
+
}
|
19
|
+
response.end(customResponse.body, customResponse.encoding);
|
20
|
+
};
|
21
|
+
exports.handleCustomResponse = handleCustomResponse;
|
22
|
+
//# sourceMappingURL=custom_response.js.map
|
@@ -0,0 +1 @@
|
|
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"}
|
package/dist/direct.d.ts
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
/// <reference types="node" />
|
2
|
+
/// <reference types="node" />
|
3
|
+
/// <reference types="node" />
|
4
|
+
/// <reference types="node" />
|
5
|
+
import dns from 'dns';
|
6
|
+
import { Buffer } from 'buffer';
|
7
|
+
import { EventEmitter } from 'events';
|
8
|
+
import { Socket } from './socket';
|
9
|
+
export interface HandlerOpts {
|
10
|
+
localAddress?: string;
|
11
|
+
ipFamily?: number;
|
12
|
+
dnsLookup?: typeof dns['lookup'];
|
13
|
+
}
|
14
|
+
interface DirectOpts {
|
15
|
+
request: {
|
16
|
+
url?: string;
|
17
|
+
};
|
18
|
+
sourceSocket: Socket;
|
19
|
+
head: Buffer;
|
20
|
+
server: EventEmitter & {
|
21
|
+
log: (connectionId: unknown, str: string) => void;
|
22
|
+
};
|
23
|
+
handlerOpts: HandlerOpts;
|
24
|
+
}
|
25
|
+
/**
|
26
|
+
* Directly connects to the target.
|
27
|
+
* Client -> Apify (CONNECT) -> Web
|
28
|
+
* Client <- Apify (CONNECT) <- Web
|
29
|
+
*/
|
30
|
+
export declare const direct: ({ request, sourceSocket, head, server, handlerOpts, }: DirectOpts) => void;
|
31
|
+
export {};
|
32
|
+
//# sourceMappingURL=direct.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"direct.d.ts","sourceRoot":"","sources":["../src/direct.ts"],"names":[],"mappings":";;;;AACA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,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"}
|
package/dist/direct.js
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.direct = void 0;
|
4
|
+
const tslib_1 = require("tslib");
|
5
|
+
const net_1 = tslib_1.__importDefault(require("net"));
|
6
|
+
const url_1 = require("url");
|
7
|
+
const count_target_bytes_1 = require("./utils/count_target_bytes");
|
8
|
+
/**
|
9
|
+
* Directly connects to the target.
|
10
|
+
* Client -> Apify (CONNECT) -> Web
|
11
|
+
* Client <- Apify (CONNECT) <- Web
|
12
|
+
*/
|
13
|
+
const direct = ({ request, sourceSocket, head, server, handlerOpts, }) => {
|
14
|
+
const url = new url_1.URL(`connect://${request.url}`);
|
15
|
+
if (!url.hostname) {
|
16
|
+
throw new Error('Missing CONNECT hostname');
|
17
|
+
}
|
18
|
+
if (!url.port) {
|
19
|
+
throw new Error('Missing CONNECT port');
|
20
|
+
}
|
21
|
+
if (head.length > 0) {
|
22
|
+
// See comment in chain.ts
|
23
|
+
sourceSocket.unshift(head);
|
24
|
+
}
|
25
|
+
const options = {
|
26
|
+
port: Number(url.port),
|
27
|
+
host: url.hostname,
|
28
|
+
localAddress: handlerOpts.localAddress,
|
29
|
+
family: handlerOpts.ipFamily,
|
30
|
+
lookup: handlerOpts.dnsLookup,
|
31
|
+
};
|
32
|
+
if (options.host[0] === '[') {
|
33
|
+
options.host = options.host.slice(1, -1);
|
34
|
+
}
|
35
|
+
const targetSocket = net_1.default.createConnection(options, () => {
|
36
|
+
try {
|
37
|
+
sourceSocket.write(`HTTP/1.1 200 Connection Established\r\n\r\n`);
|
38
|
+
}
|
39
|
+
catch (error) {
|
40
|
+
sourceSocket.destroy(error);
|
41
|
+
}
|
42
|
+
});
|
43
|
+
(0, count_target_bytes_1.countTargetBytes)(sourceSocket, targetSocket);
|
44
|
+
sourceSocket.pipe(targetSocket);
|
45
|
+
targetSocket.pipe(sourceSocket);
|
46
|
+
// Once target socket closes forcibly, the source socket gets paused.
|
47
|
+
// We need to enable flowing, otherwise the socket would remain open indefinitely.
|
48
|
+
// Nothing would consume the data, we just want to close the socket.
|
49
|
+
targetSocket.on('close', () => {
|
50
|
+
sourceSocket.resume();
|
51
|
+
if (sourceSocket.writable) {
|
52
|
+
sourceSocket.end();
|
53
|
+
}
|
54
|
+
});
|
55
|
+
// Same here.
|
56
|
+
sourceSocket.on('close', () => {
|
57
|
+
targetSocket.resume();
|
58
|
+
if (targetSocket.writable) {
|
59
|
+
targetSocket.end();
|
60
|
+
}
|
61
|
+
});
|
62
|
+
const { proxyChainId } = sourceSocket;
|
63
|
+
targetSocket.on('error', (error) => {
|
64
|
+
server.log(proxyChainId, `Direct Destination Socket Error: ${error.stack}`);
|
65
|
+
sourceSocket.destroy();
|
66
|
+
});
|
67
|
+
sourceSocket.on('error', (error) => {
|
68
|
+
server.log(proxyChainId, `Direct Source Socket Error: ${error.stack}`);
|
69
|
+
targetSocket.destroy();
|
70
|
+
});
|
71
|
+
};
|
72
|
+
exports.direct = direct;
|
73
|
+
//# sourceMappingURL=direct.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"direct.js","sourceRoot":"","sources":["../src/direct.ts"],"names":[],"mappings":";;;;AAAA,sDAAsB;AAGtB,6BAA0B;AAE1B,mEAA8D;AAiB9D;;;;GAIG;AACI,MAAM,MAAM,GAAG,CAClB,EACI,OAAO,EACP,YAAY,EACZ,IAAI,EACJ,MAAM,EACN,WAAW,GACF,EACT,EAAE;IACN,MAAM,GAAG,GAAG,IAAI,SAAG,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,aAAG,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"}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
/// <reference types="node" />
|
2
|
+
/// <reference types="node" />
|
3
|
+
import dns from 'dns';
|
4
|
+
import http from 'http';
|
5
|
+
import { URL } from 'url';
|
6
|
+
export interface HandlerOpts {
|
7
|
+
upstreamProxyUrlParsed: URL;
|
8
|
+
localAddress?: string;
|
9
|
+
ipFamily?: number;
|
10
|
+
dnsLookup?: typeof dns['lookup'];
|
11
|
+
}
|
12
|
+
/**
|
13
|
+
* The request is read from the client and is resent.
|
14
|
+
* This is similar to Direct / Chain, however it uses the CONNECT protocol instead.
|
15
|
+
* Forward uses standard HTTP methods.
|
16
|
+
*
|
17
|
+
* ```
|
18
|
+
* Client -> Apify (HTTP) -> Web
|
19
|
+
* Client <- Apify (HTTP) <- Web
|
20
|
+
* ```
|
21
|
+
*
|
22
|
+
* or
|
23
|
+
*
|
24
|
+
* ```
|
25
|
+
* Client -> Apify (HTTP) -> Upstream (HTTP) -> Web
|
26
|
+
* Client <- Apify (HTTP) <- Upstream (HTTP) <- Web
|
27
|
+
* ```
|
28
|
+
*/
|
29
|
+
export declare const forward: (request: http.IncomingMessage, response: http.ServerResponse, handlerOpts: HandlerOpts) => Promise<void>;
|
30
|
+
//# sourceMappingURL=forward.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"forward.d.ts","sourceRoot":"","sources":["../src/forward.ts"],"names":[],"mappings":";;AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,IAAI,MAAM,MAAM,CAAC;AAIxB,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAkB1B,MAAM,WAAW,WAAW;IACxB,sBAAsB,EAAE,GAAG,CAAC;IAC5B,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,CAkFb,CAAC"}
|
package/dist/forward.js
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.forward = void 0;
|
4
|
+
const tslib_1 = require("tslib");
|
5
|
+
const http_1 = tslib_1.__importDefault(require("http"));
|
6
|
+
const https_1 = tslib_1.__importDefault(require("https"));
|
7
|
+
const stream_1 = tslib_1.__importDefault(require("stream"));
|
8
|
+
const util_1 = tslib_1.__importDefault(require("util"));
|
9
|
+
const valid_headers_only_1 = require("./utils/valid_headers_only");
|
10
|
+
const get_basic_1 = require("./utils/get_basic");
|
11
|
+
const count_target_bytes_1 = require("./utils/count_target_bytes");
|
12
|
+
const statuses_1 = require("./statuses");
|
13
|
+
const pipeline = util_1.default.promisify(stream_1.default.pipeline);
|
14
|
+
/**
|
15
|
+
* The request is read from the client and is resent.
|
16
|
+
* This is similar to Direct / Chain, however it uses the CONNECT protocol instead.
|
17
|
+
* Forward uses standard HTTP methods.
|
18
|
+
*
|
19
|
+
* ```
|
20
|
+
* Client -> Apify (HTTP) -> Web
|
21
|
+
* Client <- Apify (HTTP) <- Web
|
22
|
+
* ```
|
23
|
+
*
|
24
|
+
* or
|
25
|
+
*
|
26
|
+
* ```
|
27
|
+
* Client -> Apify (HTTP) -> Upstream (HTTP) -> Web
|
28
|
+
* Client <- Apify (HTTP) <- Upstream (HTTP) <- Web
|
29
|
+
* ```
|
30
|
+
*/
|
31
|
+
const forward = async (request, response, handlerOpts) => new Promise(async (resolve, reject) => {
|
32
|
+
const proxy = handlerOpts.upstreamProxyUrlParsed;
|
33
|
+
const origin = proxy ? proxy.origin : request.url;
|
34
|
+
const options = {
|
35
|
+
method: request.method,
|
36
|
+
headers: (0, valid_headers_only_1.validHeadersOnly)(request.rawHeaders),
|
37
|
+
insecureHTTPParser: true,
|
38
|
+
localAddress: handlerOpts.localAddress,
|
39
|
+
family: handlerOpts.ipFamily,
|
40
|
+
lookup: handlerOpts.dnsLookup,
|
41
|
+
};
|
42
|
+
// In case of proxy the path needs to be an absolute URL
|
43
|
+
if (proxy) {
|
44
|
+
options.path = request.url;
|
45
|
+
try {
|
46
|
+
if (proxy.username || proxy.password) {
|
47
|
+
options.headers.push('proxy-authorization', (0, get_basic_1.getBasicAuthorizationHeader)(proxy));
|
48
|
+
}
|
49
|
+
}
|
50
|
+
catch (error) {
|
51
|
+
reject(error);
|
52
|
+
return;
|
53
|
+
}
|
54
|
+
}
|
55
|
+
const fn = origin.startsWith('https:') ? https_1.default.request : http_1.default.request;
|
56
|
+
// We have to force cast `options` because @types/node doesn't support an array.
|
57
|
+
const client = fn(origin, options, async (clientResponse) => {
|
58
|
+
try {
|
59
|
+
// This is necessary to prevent Node.js throwing an error
|
60
|
+
let statusCode = clientResponse.statusCode;
|
61
|
+
if (statusCode < 100 || statusCode > 999) {
|
62
|
+
statusCode = statuses_1.badGatewayStatusCodes.STATUS_CODE_OUT_OF_RANGE;
|
63
|
+
}
|
64
|
+
// 407 is handled separately
|
65
|
+
if (clientResponse.statusCode === 407) {
|
66
|
+
reject(new Error('407 Proxy Authentication Required'));
|
67
|
+
return;
|
68
|
+
}
|
69
|
+
response.writeHead(statusCode, clientResponse.statusMessage, (0, valid_headers_only_1.validHeadersOnly)(clientResponse.rawHeaders));
|
70
|
+
// `pipeline` automatically handles all the events and data
|
71
|
+
await pipeline(clientResponse, response);
|
72
|
+
resolve();
|
73
|
+
}
|
74
|
+
catch {
|
75
|
+
// Client error, pipeline already destroys the streams, ignore.
|
76
|
+
resolve();
|
77
|
+
}
|
78
|
+
});
|
79
|
+
client.once('socket', (socket) => {
|
80
|
+
(0, count_target_bytes_1.countTargetBytes)(request.socket, socket);
|
81
|
+
});
|
82
|
+
// Can't use pipeline here as it automatically destroys the streams
|
83
|
+
request.pipe(client);
|
84
|
+
client.on('error', (error) => {
|
85
|
+
var _a;
|
86
|
+
if (response.headersSent) {
|
87
|
+
return;
|
88
|
+
}
|
89
|
+
const statusCode = (_a = statuses_1.errorCodeToStatusCode[error.code]) !== null && _a !== void 0 ? _a : statuses_1.badGatewayStatusCodes.GENERIC_ERROR;
|
90
|
+
response.statusCode = !proxy && error.code === 'ENOTFOUND' ? 404 : statusCode;
|
91
|
+
response.setHeader('content-type', 'text/plain; charset=utf-8');
|
92
|
+
response.end(http_1.default.STATUS_CODES[response.statusCode]);
|
93
|
+
resolve();
|
94
|
+
});
|
95
|
+
});
|
96
|
+
exports.forward = forward;
|
97
|
+
//# sourceMappingURL=forward.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"forward.js","sourceRoot":"","sources":["../src/forward.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/// <reference types="node" />
|
2
|
+
import http from 'http';
|
3
|
+
import { URL } from 'url';
|
4
|
+
export interface HandlerOpts {
|
5
|
+
upstreamProxyUrlParsed: URL;
|
6
|
+
localAddress?: string;
|
7
|
+
}
|
8
|
+
/**
|
9
|
+
* ```
|
10
|
+
* Client -> Apify (HTTP) -> Upstream (SOCKS) -> Web
|
11
|
+
* Client <- Apify (HTTP) <- Upstream (SOCKS) <- Web
|
12
|
+
* ```
|
13
|
+
*/
|
14
|
+
export declare const forwardSocks: (request: http.IncomingMessage, response: http.ServerResponse, handlerOpts: HandlerOpts) => Promise<void>;
|
15
|
+
//# sourceMappingURL=forward_socks.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"forward_socks.d.ts","sourceRoot":"","sources":["../src/forward_socks.ts"],"names":[],"mappings":";AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAGxB,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAiB1B,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"}
|