proxy_chain_rb 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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;
|