Skip to content

Commit 4e1f511

Browse files
committed
Fixed proxy for U.request() + U.download().
1 parent 74f938c commit 4e1f511

1 file changed

Lines changed: 120 additions & 54 deletions

File tree

utils.js

Lines changed: 120 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ const Fs = require('fs');
3636
const Events = require('events');
3737
const Crypto = require('crypto');
3838
const Zlib = require('zlib');
39+
const Tls = require('tls');
3940

4041
const CONCAT = [null, null];
4142
const COMPARER = global.Intl ? global.Intl.Collator().compare : function(a, b) {
@@ -81,6 +82,8 @@ const CT = 'Content-Type';
8182
const CRC32TABLE = '00000000,77073096,EE0E612C,990951BA,076DC419,706AF48F,E963A535,9E6495A3,0EDB8832,79DCB8A4,E0D5E91E,97D2D988,09B64C2B,7EB17CBD,E7B82D07,90BF1D91,1DB71064,6AB020F2,F3B97148,84BE41DE,1ADAD47D,6DDDE4EB,F4D4B551,83D385C7,136C9856,646BA8C0,FD62F97A,8A65C9EC,14015C4F,63066CD9,FA0F3D63,8D080DF5,3B6E20C8,4C69105E,D56041E4,A2677172,3C03E4D1,4B04D447,D20D85FD,A50AB56B,35B5A8FA,42B2986C,DBBBC9D6,ACBCF940,32D86CE3,45DF5C75,DCD60DCF,ABD13D59,26D930AC,51DE003A,C8D75180,BFD06116,21B4F4B5,56B3C423,CFBA9599,B8BDA50F,2802B89E,5F058808,C60CD9B2,B10BE924,2F6F7C87,58684C11,C1611DAB,B6662D3D,76DC4190,01DB7106,98D220BC,EFD5102A,71B18589,06B6B51F,9FBFE4A5,E8B8D433,7807C9A2,0F00F934,9609A88E,E10E9818,7F6A0DBB,086D3D2D,91646C97,E6635C01,6B6B51F4,1C6C6162,856530D8,F262004E,6C0695ED,1B01A57B,8208F4C1,F50FC457,65B0D9C6,12B7E950,8BBEB8EA,FCB9887C,62DD1DDF,15DA2D49,8CD37CF3,FBD44C65,4DB26158,3AB551CE,A3BC0074,D4BB30E2,4ADFA541,3DD895D7,A4D1C46D,D3D6F4FB,4369E96A,346ED9FC,AD678846,DA60B8D0,44042D73,33031DE5,AA0A4C5F,DD0D7CC9,5005713C,270241AA,BE0B1010,C90C2086,5768B525,206F85B3,B966D409,CE61E49F,5EDEF90E,29D9C998,B0D09822,C7D7A8B4,59B33D17,2EB40D81,B7BD5C3B,C0BA6CAD,EDB88320,9ABFB3B6,03B6E20C,74B1D29A,EAD54739,9DD277AF,04DB2615,73DC1683,E3630B12,94643B84,0D6D6A3E,7A6A5AA8,E40ECF0B,9309FF9D,0A00AE27,7D079EB1,F00F9344,8708A3D2,1E01F268,6906C2FE,F762575D,806567CB,196C3671,6E6B06E7,FED41B76,89D32BE0,10DA7A5A,67DD4ACC,F9B9DF6F,8EBEEFF9,17B7BE43,60B08ED5,D6D6A3E8,A1D1937E,38D8C2C4,4FDFF252,D1BB67F1,A6BC5767,3FB506DD,48B2364B,D80D2BDA,AF0A1B4C,36034AF6,41047A60,DF60EFC3,A867DF55,316E8EEF,4669BE79,CB61B38C,BC66831A,256FD2A0,5268E236,CC0C7795,BB0B4703,220216B9,5505262F,C5BA3BBE,B2BD0B28,2BB45A92,5CB36A04,C2D7FFA7,B5D0CF31,2CD99E8B,5BDEAE1D,9B64C2B0,EC63F226,756AA39C,026D930A,9C0906A9,EB0E363F,72076785,05005713,95BF4A82,E2B87A14,7BB12BAE,0CB61B38,92D28E9B,E5D5BE0D,7CDCEFB7,0BDBDF21,86D3D2D4,F1D4E242,68DDB3F8,1FDA836E,81BE16CD,F6B9265B,6FB077E1,18B74777,88085AE6,FF0F6A70,66063BCA,11010B5C,8F659EFF,F862AE69,616BFFD3,166CCF45,A00AE278,D70DD2EE,4E048354,3903B3C2,A7672661,D06016F7,4969474D,3E6E77DB,AED16A4A,D9D65ADC,40DF0B66,37D83BF0,A9BCAE53,DEBB9EC5,47B2CF7F,30B5FFE9,BDBDF21C,CABAC28A,53B39330,24B4A3A6,BAD03605,CDD70693,54DE5729,23D967BF,B3667A2E,C4614AB8,5D681B02,2A6F2B94,B40BBE37,C30C8EA1,5A05DF1B,2D02EF8D'.split(',').map(s => parseInt(s, 16));
8283
const REGISARR = /\[\d+\]$/;
8384
const PROXYBLACKLIST = { 'localhost': 1, '127.0.0.1': 1, '0.0.0.0': 1 };
85+
const PROXYOPTIONS = {};
86+
const PROXYHEADERS = {};
8487

8588
exports.MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
8689
exports.DAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
@@ -413,40 +416,19 @@ exports.keywords = function(content, forSearch, alternative, max_count, max_leng
413416
};
414417

415418
function parseProxy(p) {
416-
417419
var key = 'proxy_' + p;
418-
419420
if (F.temporary.other[key])
420421
return F.temporary.other[key];
421422

422-
var proxy = {};
423-
424-
proxy.protocol = p.substring(0, 7);
425-
426-
if (proxy.protocol === 'http://') {
427-
proxy.protocol = 'http:';
428-
p = p.substring(7);
429-
} else if (proxy.protocol === 'https:') {
430-
proxy.protocol = 'https:';
431-
p = p.substring(8);
432-
} else
433-
proxy.protocol = 'http:';
423+
if (p.indexOf('://') === -1)
424+
p = 'http://' + p;
434425

435-
var index = p.indexOf('@');
436-
if (index !== -1) {
437-
// auth
438-
var t = p.substring(0, index).split(':');
439-
proxy.username = t[0];
440-
proxy.password = t[1];
441-
p = p.substring(index + 1);
442-
}
426+
var obj = Url.parse(p);
443427

444-
index = p.lastIndexOf(':');
445-
proxy.hostname = p.substring(0, index);
446-
proxy.port = p.substring(index + 1);
447-
proxy.method = 'CONNECT';
428+
if (obj.auth)
429+
obj._auth = 'Basic ' + U.createBuffer(obj.auth).toString('base64');
448430

449-
return F.temporary.other[key] = proxy;
431+
return F.temporary.other[key] = obj;
450432
}
451433

452434
/**
@@ -617,7 +599,6 @@ global.REQUEST = exports.request = function(url, flags, data, callback, cookies,
617599

618600
var uri = Url.parse(url);
619601
uri.method = method;
620-
// uri.agent = false;
621602
uri.headers = headers;
622603
options.uri = uri;
623604

@@ -626,7 +607,10 @@ global.REQUEST = exports.request = function(url, flags, data, callback, cookies,
626607

627608
if (proxy) {
628609
options.proxy = proxy;
629-
request_proxy(options, request_call);
610+
if (uri.protocol === 'http:')
611+
request_call(uri, options);
612+
else
613+
request_proxy(options, request_call);
630614
} else if (options.resolve) {
631615
exports.resolve(url, function(err, u) {
632616
!err && (uri.host = u.host);
@@ -640,14 +624,17 @@ global.REQUEST = exports.request = function(url, flags, data, callback, cookies,
640624

641625
function request_proxy(options, callback) {
642626

627+
PROXYHEADERS.host = options.uri.hostname;
628+
643629
var proxy = options.proxy;
644-
proxy.path = options.uri.hostname;
645-
proxy.headers = { host: options.uri.hostname };
630+
proxy.path = options.uri.hostname + ':443';
631+
proxy.headers = PROXYHEADERS;
632+
proxy.method = 'CONNECT';
646633

647-
if (proxy.username && proxy.password)
648-
proxy.headers.authorization = 'Basic ' + U.createBuffer(proxy.username + ':' + proxy.password).toString('base64');
634+
if (proxy._auth)
635+
proxy.headers['Proxy-Authorization'] = proxy._auth;
649636

650-
var req = proxy.protocol === 'http:' ? Http.request(proxy) : Https.request(proxy);
637+
var req = Http.request(proxy);
651638

652639
req.on('error', function(e) {
653640
options.callback(new Error('Proxy error: ' + e.toString()), '', 0, EMPTYOBJECT, proxy.hostname, EMPTYOBJECT);
@@ -656,10 +643,17 @@ function request_proxy(options, callback) {
656643

657644
req.on('connect', function(res, socket) {
658645
if (res.statusCode === 200) {
659-
options.uri.agent = options.uri.protocol === 'http:' ? new Http.Agent() : new Https.Agent();
660-
options.uri.agent.reuseSocket(socket, req);
661-
options.socket = socket;
662-
callback(options.uri, options);
646+
var tls = Tls.connect(0, { servername: options.uri.hostname, headers: options.uri.headers, socket: socket });
647+
648+
tls.on('secureConnect', function() {
649+
options.uri.agent = options.uri.protocol === 'http:' ? new Http.Agent() : new Https.Agent();
650+
options.uri.agent.reuseSocket(tls, req);
651+
//req.onSocket(tls);
652+
options.socket = tls;
653+
options.proxy.tls = tls;
654+
callback(options.uri, options);
655+
});
656+
663657
} else {
664658
options.callback(new Error((res.statusMessage || 'Proxy error') + ': ' + res.statusCode), '', res.statusCode, res.headers, proxy.hostname, EMPTYOBJECT);
665659
options.callback = null;
@@ -672,7 +666,23 @@ function request_proxy(options, callback) {
672666
function request_call(uri, options) {
673667

674668
var connection = uri.protocol === 'https:' ? Https : Http;
675-
var req = options.post ? connection.request(uri, (res) => request_response(res, uri, options)) : connection.get(uri, (res) => request_response(res, uri, options));
669+
var opt;
670+
671+
if (options.proxy && !options.proxy.tls) {
672+
opt = PROXYOPTIONS;
673+
opt.port = options.proxy.port;
674+
opt.host = options.proxy.hostname;
675+
opt.path = uri.href;
676+
opt.headers = uri.headers;
677+
opt.method = uri.method;
678+
679+
if (options.proxy._auth)
680+
opt.headers['Proxy-Authorization'] = options.proxy._auth;
681+
682+
} else
683+
opt = uri;
684+
685+
var req = options.post ? connection.request(opt, (res) => request_response(res, uri, options)) : connection.get(opt, (res) => request_response(res, uri, options));
676686

677687
if (!options.callback) {
678688
req.on('error', NOOP);
@@ -702,7 +712,6 @@ function request_call(uri, options) {
702712
if (options.upload) {
703713
options.first = true;
704714
options.files.wait(function(file, next) {
705-
// next();
706715
request_writefile(req, options, file, next);
707716
}, function() {
708717

@@ -799,6 +808,13 @@ function request_response(res, uri, options) {
799808
res.req.removeAllListeners();
800809
res.req = null;
801810

811+
if (options.proxy && tmp.protocol === 'https:') {
812+
// TLS?
813+
options.uri = tmp;
814+
request_proxy(options, request_call);
815+
return
816+
}
817+
802818
if (!options.resolve) {
803819
res.removeAllListeners();
804820
res = null;
@@ -1065,7 +1081,10 @@ exports.download = function(url, flags, data, callback, cookies, headers, encodi
10651081

10661082
if (proxy) {
10671083
options.proxy = proxy;
1068-
request_proxy(options, download_call);
1084+
if (uri.protocol === 'http:')
1085+
download_call(uri, options);
1086+
else
1087+
request_proxy(options, download_call);
10691088
} else if (options.resolve) {
10701089
exports.resolve(url, function(err, u) {
10711090
!err && (uri.host = u.host);
@@ -1079,32 +1098,46 @@ exports.download = function(url, flags, data, callback, cookies, headers, encodi
10791098

10801099
function download_call(uri, options) {
10811100

1101+
var opt;
10821102
options.length = 0;
10831103

1104+
if (options.proxy && !options.proxy.tls) {
1105+
opt = PROXYOPTIONS;
1106+
opt.port = options.proxy.port;
1107+
opt.host = options.proxy.hostname;
1108+
opt.path = uri.href;
1109+
opt.headers = uri.headers;
1110+
opt.method = uri.method;
1111+
1112+
if (options.proxy._auth)
1113+
opt.headers['Proxy-Authorization'] = options.proxy._auth;
1114+
} else
1115+
opt = uri;
1116+
10841117
var connection = uri.protocol === 'https:' ? Https : Http;
1085-
var req = options.post ? connection.request(uri, (res) => download_response(res, uri, options)) : connection.get(uri, (res) => download_response(res, uri, options));
1118+
var req = options.post ? connection.request(opt, (res) => download_response(res, uri, options)) : connection.get(opt, (res) => download_response(res, uri, options));
10861119

10871120
if (!options.callback) {
10881121
req.on('error', NOOP);
10891122
return;
10901123
}
10911124

10921125
req.on('error', function(err) {
1093-
if (!options.callback)
1094-
return;
1095-
options.callback(err);
1096-
options.callback = null;
1097-
options.evt.removeAllListeners();
1098-
options.evt = null;
1126+
if (options.callback) {
1127+
options.callback(err);
1128+
options.callback = null;
1129+
options.evt.removeAllListeners();
1130+
options.evt = null;
1131+
}
10991132
});
11001133

11011134
req.setTimeout(options.timeout, function() {
1102-
if (!options.callback)
1103-
return;
1104-
options.callback(new Error(exports.httpStatus(408)));
1105-
options.callback = null;
1106-
options.evt.removeAllListeners();
1107-
options.evt = null;
1135+
if (options.callback) {
1136+
options.callback(new Error(exports.httpStatus(408)));
1137+
options.callback = null;
1138+
options.evt.removeAllListeners();
1139+
options.evt = null;
1140+
}
11081141
});
11091142

11101143
req.on('response', function(response) {
@@ -1141,6 +1174,13 @@ function download_response(res, uri, options) {
11411174
res.req.removeAllListeners();
11421175
res.req = null;
11431176

1177+
if (options.proxy && tmp.protocol === 'https:') {
1178+
// TLS?
1179+
options.uri = tmp;
1180+
download_call(options, request_call);
1181+
return
1182+
}
1183+
11441184
if (!options.resolve) {
11451185
res.removeAllListeners();
11461186
res = null;
@@ -5877,5 +5917,31 @@ if (NODEVERSION > 699) {
58775917
exports.createBuffer = (val, type) => new Buffer(val || '', type);
58785918
}
58795919

5920+
function Callback(count, callback) {
5921+
this.pending = count;
5922+
this.$callback = callback;
5923+
}
5924+
5925+
Callback.prototype.done = function(callback) {
5926+
this.$callback = callback;
5927+
return this;
5928+
};
5929+
5930+
Callback.prototype.next = function() {
5931+
var self = this;
5932+
self.pending--;
5933+
if (!self.pending && self.$callback) {
5934+
self.$callback();
5935+
self.$callback = null;
5936+
}
5937+
return self;
5938+
};
5939+
5940+
global.Callback = Callback;
5941+
5942+
exports.Callback = function(count, callback) {
5943+
return new Callback(count, callback);
5944+
};
5945+
58805946
global.WAIT = exports.wait;
58815947
!global.F && require('./index');

0 commit comments

Comments
 (0)