proxy_chain_rb 0.1.0 → 0.1.2
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.
- checksums.yaml +4 -4
- data/Gemfile.lock +16 -16
- data/README.md +14 -5
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/.yarn-integrity +23 -0
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/bluebird/README.md +1 -1
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/bluebird/js/browser/bluebird.core.js +254 -121
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/bluebird/js/browser/bluebird.core.min.js +3 -3
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/bluebird/js/browser/bluebird.js +284 -129
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/bluebird/js/browser/bluebird.min.js +4 -4
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/bluebird/js/release/async.js +3 -48
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/bluebird/js/release/debuggability.js +145 -27
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/bluebird/js/release/join.js +4 -7
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/bluebird/js/release/map.js +10 -3
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/bluebird/js/release/promise.js +58 -28
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/bluebird/js/release/promise_array.js +1 -0
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/bluebird/js/release/reduce.js +16 -5
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/bluebird/js/release/settle.js +4 -0
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/bluebird/js/release/util.js +39 -7
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/bluebird/package.json +39 -63
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/commander/CHANGELOG.md +11 -0
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/commander/index.js +1 -1
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/commander/package.json +20 -52
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/debug/package.json +21 -60
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/ms/package.json +19 -51
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/portastic/node_modules/bluebird/package.json +41 -66
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/portastic/package.json +23 -51
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/proxy-chain/CHANGELOG.md +18 -0
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/proxy-chain/README.md +8 -0
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/proxy-chain/build/anonymize_proxy.js +5 -0
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/proxy-chain/build/handler_base.js +86 -53
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/proxy-chain/build/handler_forward.js +23 -5
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/proxy-chain/build/handler_tunnel_chain.js +3 -7
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/proxy-chain/build/handler_tunnel_direct.js +1 -1
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/proxy-chain/build/index.js +3 -5
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/proxy-chain/build/server.js +3 -1
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/proxy-chain/build/tcp_tunnel.js +245 -115
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/proxy-chain/build/tcp_tunnel_tools.js +138 -0
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/proxy-chain/node_modules/.bin/portastic +1 -0
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/proxy-chain/package.json +41 -68
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/underscore/package.json +27 -58
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/package.json +1 -1
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/server.js +4 -2
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/yarn.lock +53 -0
- data/lib/proxy_chain_rb/server.rb +8 -6
- data/lib/proxy_chain_rb/version.rb +1 -1
- data/proxy_chain_rb.gemspec +3 -3
- metadata +16 -14
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/proxy-chain/build/handler_tunnel_tcp_chain.js +0 -271
- data/lib/proxy_chain_rb/node_js/proxy-chain-server/package-lock.json +0 -63
data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/proxy-chain/build/handler_forward.js
CHANGED
@@ -16,6 +16,8 @@ var _handler_base = require('./handler_base');
|
|
16
16
|
|
17
17
|
var _handler_base2 = _interopRequireDefault(_handler_base);
|
18
18
|
|
19
|
+
var _server = require('./server');
|
20
|
+
|
19
21
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
20
22
|
|
21
23
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
@@ -51,21 +53,30 @@ var HandlerForward = function (_HandlerBase) {
|
|
51
53
|
// var hasVia = false;
|
52
54
|
// var via = '1.1 ' + hostname + ' (proxy/' + version + ')';
|
53
55
|
|
56
|
+
var hostHeaderFound = false;
|
57
|
+
|
58
|
+
// TODO: We should probably use a raw HTTP message via socket instead of http.request(),
|
59
|
+
// since Node transforms the headers to lower case and thus makes it easy to detect the proxy
|
54
60
|
for (var i = 0; i < this.srcRequest.rawHeaders.length; i += 2) {
|
55
61
|
var headerName = this.srcRequest.rawHeaders[i];
|
56
62
|
var headerValue = this.srcRequest.rawHeaders[i + 1];
|
57
63
|
|
58
|
-
if (headerName
|
64
|
+
if (/^connection$/i.test(headerName) && /^keep-alive$/i.test(headerValue)) {
|
59
65
|
// Keep the "Connection: keep-alive" header, to reduce the chance that the server
|
60
66
|
// will detect we're not a browser and also to improve performance
|
61
67
|
} else if ((0, _tools.isHopByHopHeader)(headerName)) {
|
62
68
|
continue;
|
63
69
|
} else if ((0, _tools.isInvalidHeader)(headerName, headerValue)) {
|
64
70
|
continue;
|
71
|
+
} else if (/^host$/i.test(headerName)) {
|
72
|
+
// If Host header was used multiple times, only consider the first one.
|
73
|
+
// This is to prevent "TypeError: hostHeader.startsWith is not a function at calculateServerName (_http_agent.js:240:20)"
|
74
|
+
if (hostHeaderFound) continue;
|
75
|
+
hostHeaderFound = true;
|
65
76
|
}
|
66
77
|
|
67
78
|
/*
|
68
|
-
|
79
|
+
if (!hasXForwardedFor && 'x-forwarded-for' === keyLower) {
|
69
80
|
// append to existing "X-Forwarded-For" header
|
70
81
|
// http://en.wikipedia.org/wiki/X-Forwarded-For
|
71
82
|
hasXForwardedFor = true;
|
@@ -137,12 +148,9 @@ var HandlerForward = function (_HandlerBase) {
|
|
137
148
|
value: function onTrgResponse(response) {
|
138
149
|
if (this.isClosed) return;
|
139
150
|
this.log('Received response from target (' + response.statusCode + ')');
|
140
|
-
// console.dir(response);
|
141
151
|
|
142
152
|
if (this.checkUpstreamProxy407(response)) return;
|
143
153
|
|
144
|
-
this.srcGotResponse = true;
|
145
|
-
|
146
154
|
// Prepare response headers
|
147
155
|
var headers = {};
|
148
156
|
for (var i = 0; i < response.rawHeaders.length; i += 2) {
|
@@ -155,6 +163,16 @@ var HandlerForward = function (_HandlerBase) {
|
|
155
163
|
(0, _tools.addHeader)(headers, name, value);
|
156
164
|
}
|
157
165
|
|
166
|
+
// Ensure status code is in the range accepted by Node, otherwise proxy will crash with
|
167
|
+
// "RangeError: Invalid status code: 0" (see writeHead in Node's _http_server.js)
|
168
|
+
// Fixes https://github.com/apifytech/proxy-chain/issues/35
|
169
|
+
if (response.statusCode < 100 || response.statusCode > 999) {
|
170
|
+
this.fail(new _server.RequestError('Target server responded with an invalid HTTP status code (' + response.statusCode + ')', 500));
|
171
|
+
return;
|
172
|
+
}
|
173
|
+
|
174
|
+
this.srcGotResponse = true;
|
175
|
+
|
158
176
|
this.srcResponse.writeHead(response.statusCode, headers);
|
159
177
|
response.pipe(this.srcResponse);
|
160
178
|
}
|
@@ -24,10 +24,6 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen
|
|
24
24
|
|
25
25
|
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
26
26
|
|
27
|
-
// import { tee } from './tools';
|
28
|
-
|
29
|
-
/* globals Buffer */
|
30
|
-
|
31
27
|
/**
|
32
28
|
* Represents a connection from source client to an external proxy using HTTP CONNECT tunnel.
|
33
29
|
*/
|
@@ -68,8 +64,8 @@ var HandlerTunnelChain = function (_HandlerBase) {
|
|
68
64
|
|
69
65
|
this.trgRequest.once('connect', this.onTrgRequestConnect);
|
70
66
|
this.trgRequest.once('abort', this.onTrgRequestAbort);
|
71
|
-
this.trgRequest.once('
|
72
|
-
this.trgRequest.on('
|
67
|
+
this.trgRequest.once('socket', this.onTrgSocket);
|
68
|
+
this.trgRequest.on('error', this.onTrgRequestError);
|
73
69
|
|
74
70
|
// Send the data
|
75
71
|
this.trgRequest.end();
|
@@ -84,7 +80,7 @@ var HandlerTunnelChain = function (_HandlerBase) {
|
|
84
80
|
|
85
81
|
this.srcGotResponse = true;
|
86
82
|
this.srcResponse.removeListener('finish', this.onSrcResponseFinish);
|
87
|
-
this.srcResponse.writeHead(200, 'Connection
|
83
|
+
this.srcResponse.writeHead(200, 'Connection Established');
|
88
84
|
|
89
85
|
// HACK: force a flush of the HTTP header. This is to ensure 'head' is empty to avoid
|
90
86
|
// assert at https://github.com/request/tunnel-agent/blob/master/index.js#L160
|
@@ -56,7 +56,7 @@ var HandlerTunnelDirect = function (_HandlerBase) {
|
|
56
56
|
this.srcGotResponse = true;
|
57
57
|
|
58
58
|
this.srcResponse.removeListener('finish', this.onSrcResponseFinish);
|
59
|
-
this.srcResponse.writeHead(200, 'Connection
|
59
|
+
this.srcResponse.writeHead(200, 'Connection Established');
|
60
60
|
|
61
61
|
// HACK: force a flush of the HTTP header. This is to ensure 'head' is empty to avoid
|
62
62
|
// assert at https://github.com/request/tunnel-agent/blob/master/index.js#L160
|
@@ -6,9 +6,7 @@ var _tools = require('./tools');
|
|
6
6
|
|
7
7
|
var _anonymize_proxy = require('./anonymize_proxy');
|
8
8
|
|
9
|
-
var
|
10
|
-
|
11
|
-
/* globals module */
|
9
|
+
var _tcp_tunnel_tools = require('./tcp_tunnel_tools');
|
12
10
|
|
13
11
|
// Publicly exported functions and classes
|
14
12
|
var ProxyChain = {
|
@@ -19,8 +17,8 @@ var ProxyChain = {
|
|
19
17
|
redactParsedUrl: _tools.redactParsedUrl,
|
20
18
|
anonymizeProxy: _anonymize_proxy.anonymizeProxy,
|
21
19
|
closeAnonymizedProxy: _anonymize_proxy.closeAnonymizedProxy,
|
22
|
-
createTunnel:
|
23
|
-
closeTunnel:
|
20
|
+
createTunnel: _tcp_tunnel_tools.createTunnel,
|
21
|
+
closeTunnel: _tcp_tunnel_tools.closeTunnel
|
24
22
|
};
|
25
23
|
|
26
24
|
module.exports = ProxyChain;
|
@@ -172,7 +172,7 @@ var Server = exports.Server = function (_EventEmitter) {
|
|
172
172
|
value: function log(handlerId, str) {
|
173
173
|
if (this.verbose) {
|
174
174
|
var logPrefix = handlerId ? handlerId + ' | ' : '';
|
175
|
-
console.log('
|
175
|
+
console.log('ProxyServer[' + this.port + ']: ' + logPrefix + str);
|
176
176
|
}
|
177
177
|
}
|
178
178
|
}, {
|
@@ -270,6 +270,7 @@ var Server = exports.Server = function (_EventEmitter) {
|
|
270
270
|
this.log(handlerOpts.id, '!!! Handling ' + request.method + ' ' + request.url + ' HTTP/' + request.httpVersion);
|
271
271
|
|
272
272
|
var socket = request.socket;
|
273
|
+
|
273
274
|
var isHttp = false;
|
274
275
|
|
275
276
|
return _bluebird2.default.resolve().then(function () {
|
@@ -585,6 +586,7 @@ var Server = exports.Server = function (_EventEmitter) {
|
|
585
586
|
// TODO: keep track of all handlers and close them if closeConnections=true
|
586
587
|
if (this.server) {
|
587
588
|
var server = this.server;
|
589
|
+
|
588
590
|
this.server = null;
|
589
591
|
return _bluebird2.default.promisify(server.close).bind(server)().nodeify(callback);
|
590
592
|
}
|
data/lib/proxy_chain_rb/node_js/proxy-chain-server/node_modules/proxy-chain/build/tcp_tunnel.js
CHANGED
@@ -4,135 +4,265 @@ Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
5
5
|
});
|
6
6
|
|
7
|
-
var
|
7
|
+
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
8
8
|
|
9
|
-
var
|
9
|
+
var _http = require('http');
|
10
10
|
|
11
|
-
|
12
|
-
exports.closeTunnel = closeTunnel;
|
11
|
+
var _http2 = _interopRequireDefault(_http);
|
13
12
|
|
14
|
-
var
|
13
|
+
var _tools = require('./tools');
|
15
14
|
|
16
|
-
|
15
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
17
16
|
|
18
|
-
|
17
|
+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
19
18
|
|
20
|
-
|
19
|
+
/**
|
20
|
+
* Represents a connection from source client to an external proxy using HTTP CONNECT tunnel, allows TCP connection.
|
21
|
+
*/
|
22
|
+
var TcpTunnel = function () {
|
23
|
+
function TcpTunnel(_ref) {
|
24
|
+
var srcSocket = _ref.srcSocket,
|
25
|
+
trgParsed = _ref.trgParsed,
|
26
|
+
upstreamProxyUrlParsed = _ref.upstreamProxyUrlParsed,
|
27
|
+
log = _ref.log;
|
21
28
|
|
22
|
-
|
29
|
+
_classCallCheck(this, TcpTunnel);
|
23
30
|
|
24
|
-
|
31
|
+
this.log = log;
|
25
32
|
|
26
|
-
|
33
|
+
// Bind all event handlers to this instance
|
34
|
+
this.bindHandlersToThis(['onSrcSocketClose', 'onSrcSocketEnd', 'onSrcSocketError', 'onTrgSocket', 'onTrgSocketClose', 'onTrgSocketEnd', 'onTrgSocketError', 'onTrgRequestConnect', 'onTrgRequestAbort', 'onTrgRequestError']);
|
27
35
|
|
28
|
-
|
36
|
+
if (!trgParsed.hostname) throw new Error('The "trgParsed.hostname" option is required');
|
37
|
+
if (!trgParsed.port) throw new Error('The "trgParsed.port" option is required');
|
29
38
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
var callback = arguments[3];
|
35
|
-
|
36
|
-
// TODO: More and better validations - yeah, make sure targetHost is really a hostname
|
37
|
-
var _targetHost$split = targetHost.split(':'),
|
38
|
-
_targetHost$split2 = _slicedToArray(_targetHost$split, 2),
|
39
|
-
trgHostname = _targetHost$split2[0],
|
40
|
-
trgPort = _targetHost$split2[1];
|
41
|
-
|
42
|
-
if (!trgHostname || !trgPort) throw new Error('target needs to include both hostname and port.');
|
43
|
-
|
44
|
-
var parsedProxyUrl = (0, _tools.parseUrl)(proxyUrl);
|
45
|
-
if (!parsedProxyUrl.hostname) throw new Error('proxyUrl needs to include atleast hostname');
|
46
|
-
if (parsedProxyUrl.scheme !== 'http') throw new Error('Currently only "http" scheme is supported');
|
47
|
-
|
48
|
-
var options = _extends({
|
49
|
-
verbose: false,
|
50
|
-
hostname: 'localhost',
|
51
|
-
port: null
|
52
|
-
}, providedOptions);
|
53
|
-
|
54
|
-
return new _bluebird2.default(function (resolve, reject) {
|
55
|
-
if (options.port) return resolve(options.port);
|
56
|
-
(0, _tools.findFreePort)().then(resolve).catch(reject);
|
57
|
-
}).then(function (port) {
|
58
|
-
var server = _net2.default.createServer();
|
59
|
-
|
60
|
-
var log = function log() {
|
61
|
-
var _console;
|
62
|
-
|
63
|
-
if (options.verbose) (_console = console).log.apply(_console, arguments);
|
64
|
-
};
|
65
|
-
|
66
|
-
server.on('connection', function (srcSocket) {
|
67
|
-
runningServers[port].connections = srcSocket;
|
68
|
-
var remoteAddress = srcSocket.remoteAddress + ':' + srcSocket.remotePort;
|
69
|
-
log('new client connection from %s', remoteAddress);
|
70
|
-
|
71
|
-
srcSocket.pause();
|
72
|
-
|
73
|
-
var tunnel = new _handler_tunnel_tcp_chain2.default({
|
74
|
-
srcSocket: srcSocket,
|
75
|
-
upstreamProxyUrlParsed: parsedProxyUrl,
|
76
|
-
trgParsed: {
|
77
|
-
hostname: trgHostname,
|
78
|
-
port: trgPort
|
79
|
-
},
|
80
|
-
log: log
|
81
|
-
});
|
39
|
+
this.trgRequest = null;
|
40
|
+
this.trgSocket = null;
|
41
|
+
this.trgParsed = trgParsed;
|
42
|
+
this.trgParsed.port = this.trgParsed.port || DEFAULT_TARGET_PORT;
|
82
43
|
|
83
|
-
|
44
|
+
this.srcSocket = srcSocket;
|
45
|
+
this.srcSocket.once('close', this.onSrcSocketClose);
|
46
|
+
this.srcSocket.once('end', this.onSrcSocketEnd);
|
47
|
+
this.srcSocket.on('error', this.onSrcSocketError);
|
84
48
|
|
85
|
-
|
86
|
-
srcSocket.once('close', onConnClose);
|
87
|
-
srcSocket.on('error', onConnError);
|
49
|
+
this.upstreamProxyUrlParsed = upstreamProxyUrlParsed;
|
88
50
|
|
89
|
-
|
90
|
-
|
91
|
-
}
|
51
|
+
this.isClosed = false;
|
52
|
+
}
|
92
53
|
|
93
|
-
|
94
|
-
|
95
|
-
|
54
|
+
_createClass(TcpTunnel, [{
|
55
|
+
key: 'bindHandlersToThis',
|
56
|
+
value: function bindHandlersToThis(handlerNames) {
|
57
|
+
var _this = this;
|
96
58
|
|
97
|
-
function
|
98
|
-
|
99
|
-
}
|
100
|
-
});
|
101
|
-
|
102
|
-
return new _bluebird2.default(function (resolve) {
|
103
|
-
server.listen(port, function (err) {
|
104
|
-
if (err) return reject(err);
|
105
|
-
log('server listening to ', server.address());
|
106
|
-
runningServers[port] = { server: server, connections: [] };
|
107
|
-
resolve(options.hostname + ':' + port);
|
108
|
-
});
|
109
|
-
});
|
110
|
-
}).nodeify(callback);
|
111
|
-
}
|
112
|
-
|
113
|
-
function closeTunnel(serverPath, closeConnections, callback) {
|
114
|
-
var _serverPath$split = serverPath.split(':'),
|
115
|
-
_serverPath$split2 = _slicedToArray(_serverPath$split, 2),
|
116
|
-
hostname = _serverPath$split2[0],
|
117
|
-
port = _serverPath$split2[1];
|
118
|
-
|
119
|
-
if (!hostname) throw new Error('serverPath must contain hostname');
|
120
|
-
if (!port) throw new Error('serverPath must contain port');
|
121
|
-
|
122
|
-
return new _bluebird2.default(function (resolve) {
|
123
|
-
if (!runningServers[port]) return resolve(false);
|
124
|
-
if (!closeConnections) return resolve();
|
125
|
-
runningServers[port].connections.forEach(function (connection) {
|
126
|
-
return connection.destroy();
|
127
|
-
});
|
128
|
-
resolve();
|
129
|
-
}).then(function (serverExists) {
|
130
|
-
return new _bluebird2.default(function (resolve) {
|
131
|
-
if (!serverExists) return resolve(false);
|
132
|
-
runningServers[port].close(function () {
|
133
|
-
delete runningServers[port];
|
134
|
-
resolve(true);
|
59
|
+
handlerNames.forEach(function (evt) {
|
60
|
+
_this[evt] = _this[evt].bind(_this);
|
135
61
|
});
|
136
|
-
}
|
137
|
-
}
|
138
|
-
|
62
|
+
}
|
63
|
+
}, {
|
64
|
+
key: 'run',
|
65
|
+
value: function run() {
|
66
|
+
this.log('Connecting to upstream proxy...');
|
67
|
+
|
68
|
+
var options = {
|
69
|
+
method: 'CONNECT',
|
70
|
+
hostname: this.upstreamProxyUrlParsed.hostname,
|
71
|
+
port: this.upstreamProxyUrlParsed.port,
|
72
|
+
path: this.trgParsed.hostname + ':' + this.trgParsed.port,
|
73
|
+
headers: {}
|
74
|
+
};
|
75
|
+
|
76
|
+
(0, _tools.maybeAddProxyAuthorizationHeader)(this.upstreamProxyUrlParsed, options.headers);
|
77
|
+
|
78
|
+
this.trgRequest = _http2.default.request(options);
|
79
|
+
|
80
|
+
this.trgRequest.once('connect', this.onTrgRequestConnect);
|
81
|
+
this.trgRequest.once('abort', this.onTrgRequestAbort);
|
82
|
+
this.trgRequest.once('socket', this.onTrgSocket);
|
83
|
+
this.trgRequest.on('error', this.onTrgRequestError);
|
84
|
+
|
85
|
+
// Send the data
|
86
|
+
this.trgRequest.end();
|
87
|
+
}
|
88
|
+
|
89
|
+
// If the client closes the connection prematurely,
|
90
|
+
// then immediately destroy the upstream socket, there's nothing we can do with it
|
91
|
+
|
92
|
+
}, {
|
93
|
+
key: 'onSrcSocketClose',
|
94
|
+
value: function onSrcSocketClose() {
|
95
|
+
if (this.isClosed) return;
|
96
|
+
this.log('Source socket closed');
|
97
|
+
this.close();
|
98
|
+
}
|
99
|
+
}, {
|
100
|
+
key: 'onSrcSocketEnd',
|
101
|
+
value: function onSrcSocketEnd() {
|
102
|
+
if (this.isClosed) return;
|
103
|
+
this.log('Source socket ended');
|
104
|
+
this.close();
|
105
|
+
}
|
106
|
+
}, {
|
107
|
+
key: 'onSrcSocketError',
|
108
|
+
value: function onSrcSocketError(err) {
|
109
|
+
if (this.isClosed) return;
|
110
|
+
this.log('Source socket failed: ' + (err.stack || err));
|
111
|
+
this.close();
|
112
|
+
}
|
113
|
+
}, {
|
114
|
+
key: 'onTrgSocket',
|
115
|
+
value: function onTrgSocket(socket) {
|
116
|
+
if (this.isClosed) return;
|
117
|
+
|
118
|
+
this.log('Target socket assigned');
|
119
|
+
|
120
|
+
this.trgSocket = socket;
|
121
|
+
|
122
|
+
socket.once('close', this.onTrgSocketClose);
|
123
|
+
socket.once('end', this.onTrgSocketEnd);
|
124
|
+
socket.on('error', this.onTrgSocketError);
|
125
|
+
}
|
126
|
+
|
127
|
+
// Once target socket closes, we need to give time
|
128
|
+
// to source socket to receive pending data, so we only call end()
|
129
|
+
|
130
|
+
}, {
|
131
|
+
key: 'onTrgSocketClose',
|
132
|
+
value: function onTrgSocketClose() {
|
133
|
+
var _this2 = this;
|
134
|
+
|
135
|
+
if (this.isClosed) return;
|
136
|
+
this.log('Target socket closed');
|
137
|
+
setTimeout(function () {
|
138
|
+
if (_this2.srcSocket) _this2.srcSocket.end();
|
139
|
+
}, 100);
|
140
|
+
}
|
141
|
+
}, {
|
142
|
+
key: 'onTrgSocketEnd',
|
143
|
+
value: function onTrgSocketEnd() {
|
144
|
+
var _this3 = this;
|
145
|
+
|
146
|
+
if (this.isClosed) return;
|
147
|
+
this.log('Target socket ended');
|
148
|
+
setTimeout(function () {
|
149
|
+
if (_this3.srcSocket) _this3.srcSocket.end();
|
150
|
+
}, 100);
|
151
|
+
}
|
152
|
+
}, {
|
153
|
+
key: 'onTrgSocketError',
|
154
|
+
value: function onTrgSocketError(err) {
|
155
|
+
if (this.isClosed) return;
|
156
|
+
this.log('Target socket failed: ' + (err.stack || err));
|
157
|
+
this.fail(err);
|
158
|
+
}
|
159
|
+
}, {
|
160
|
+
key: 'onTrgRequestConnect',
|
161
|
+
value: function onTrgRequestConnect(response) {
|
162
|
+
if (this.isClosed) return;
|
163
|
+
this.log('Connected to upstream proxy');
|
164
|
+
|
165
|
+
if (this.checkUpstreamProxy407(response)) return;
|
166
|
+
|
167
|
+
// Setup bi-directional tunnel
|
168
|
+
this.trgSocket.pipe(this.srcSocket);
|
169
|
+
this.srcSocket.pipe(this.trgSocket);
|
170
|
+
|
171
|
+
this.srcSocket.resume();
|
172
|
+
}
|
173
|
+
}, {
|
174
|
+
key: 'onTrgRequestAbort',
|
175
|
+
value: function onTrgRequestAbort() {
|
176
|
+
if (this.isClosed) return;
|
177
|
+
this.log('Target aborted');
|
178
|
+
this.close();
|
179
|
+
}
|
180
|
+
}, {
|
181
|
+
key: 'onTrgRequestError',
|
182
|
+
value: function onTrgRequestError(err) {
|
183
|
+
if (this.isClosed) return;
|
184
|
+
this.log('Target request failed: ' + (err.stack || err));
|
185
|
+
this.fail(err);
|
186
|
+
}
|
187
|
+
|
188
|
+
/**
|
189
|
+
* Checks whether response from upstream proxy is 407 Proxy Authentication Required
|
190
|
+
* and if so, responds 502 Bad Gateway to client.
|
191
|
+
* @param response
|
192
|
+
* @return {boolean}
|
193
|
+
*/
|
194
|
+
|
195
|
+
}, {
|
196
|
+
key: 'checkUpstreamProxy407',
|
197
|
+
value: function checkUpstreamProxy407(response) {
|
198
|
+
if (this.upstreamProxyUrlParsed && response.statusCode === 407) {
|
199
|
+
this.fail('Invalid credentials provided for the upstream proxy.', 502);
|
200
|
+
return true;
|
201
|
+
}
|
202
|
+
return false;
|
203
|
+
}
|
204
|
+
}, {
|
205
|
+
key: 'fail',
|
206
|
+
value: function fail(err, statusCode) {
|
207
|
+
if (this.srcGotResponse) {
|
208
|
+
this.log('Source already received a response, just destroying the socket...');
|
209
|
+
this.close();
|
210
|
+
} else if (statusCode) {
|
211
|
+
// Manual error
|
212
|
+
this.log(err + ', responding with custom status code ' + statusCode + ' to client');
|
213
|
+
} else if (err.code === 'ENOTFOUND' && !this.upstreamProxyUrlParsed) {
|
214
|
+
this.log('Target server not found, sending 404 to client');
|
215
|
+
} else if (err.code === 'ENOTFOUND' && this.upstreamProxyUrlParsed) {
|
216
|
+
this.log('Upstream proxy not found, sending 502 to client');
|
217
|
+
} else if (err.code === 'ECONNREFUSED') {
|
218
|
+
this.log('Upstream proxy refused connection, sending 502 to client');
|
219
|
+
} else if (err.code === 'ETIMEDOUT') {
|
220
|
+
this.log('Connection timed out, sending 502 to client');
|
221
|
+
} else if (err.code === 'ECONNRESET') {
|
222
|
+
this.log('Connection lost, sending 502 to client');
|
223
|
+
} else if (err.code === 'EPIPE') {
|
224
|
+
this.log('Socket closed before write, sending 502 to client');
|
225
|
+
} else {
|
226
|
+
this.log('Unknown error, sending 500 to client');
|
227
|
+
}
|
228
|
+
}
|
229
|
+
|
230
|
+
/**
|
231
|
+
* Detaches all listeners and destroys all sockets.
|
232
|
+
*/
|
233
|
+
|
234
|
+
}, {
|
235
|
+
key: 'close',
|
236
|
+
value: function close() {
|
237
|
+
if (!this.isClosed) {
|
238
|
+
this.log('Closing handler');
|
239
|
+
|
240
|
+
if (this.srcRequest) {
|
241
|
+
this.srcRequest.destroy();
|
242
|
+
this.srcRequest = null;
|
243
|
+
}
|
244
|
+
|
245
|
+
if (this.srcSocket) {
|
246
|
+
this.srcSocket.destroy();
|
247
|
+
this.srcSocket = null;
|
248
|
+
}
|
249
|
+
|
250
|
+
if (this.trgRequest) {
|
251
|
+
this.trgRequest.abort();
|
252
|
+
this.trgRequest = null;
|
253
|
+
}
|
254
|
+
|
255
|
+
if (this.trgSocket) {
|
256
|
+
this.trgSocket.destroy();
|
257
|
+
this.trgSocket = null;
|
258
|
+
}
|
259
|
+
|
260
|
+
this.isClosed = true;
|
261
|
+
}
|
262
|
+
}
|
263
|
+
}]);
|
264
|
+
|
265
|
+
return TcpTunnel;
|
266
|
+
}();
|
267
|
+
|
268
|
+
exports.default = TcpTunnel;
|