Skip to content

Commit 0daee32

Browse files
committed
Use the configured proxy host and port for the download
#14
1 parent a89874d commit 0daee32

File tree

3 files changed

+143
-5
lines changed

3 files changed

+143
-5
lines changed

lib/HttpsProxyAgent.js

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
var util = require('util'),
2+
https = require('https'),
3+
http = require('http'),
4+
lls = require('tls');
5+
6+
function HttpsProxyAgent(options){
7+
https.Agent.call(this, options);
8+
9+
this.proxyHost = options.proxyHost;
10+
this.proxyPort = options.proxyPort;
11+
12+
this.createConnection = function (opts, callback){
13+
// do a CONNECT request
14+
var req = http.request({
15+
host: options.proxyHost,
16+
port: options.proxyPort,
17+
method: 'CONNECT',
18+
path: opts.host + ':' + opts.port,
19+
headers: {
20+
host: opts.host
21+
}
22+
});
23+
24+
req.on('connect', function (res, socket, head){
25+
var cts = lls.connect({
26+
host: opts.host,
27+
socket: socket
28+
}, function () {
29+
callback(false, cts);
30+
});
31+
});
32+
33+
req.on('error', function (err) {
34+
callback(err, null);
35+
});
36+
37+
req.end();
38+
}
39+
}
40+
41+
util.inherits(HttpsProxyAgent, https.Agent);
42+
43+
// Almost verbatim copy of http.Agent.addRequest
44+
HttpsProxyAgent.prototype.addRequest = function (req, options){
45+
var name = options.host + ':' + options.port;
46+
if(options.path) name += ':' + options.path;
47+
48+
if(!this.sockets[name]) this.sockets[name] = [];
49+
50+
if(this.sockets[name].length < this.maxSockets){
51+
// if we are under maxSockets create a new one.
52+
this.createSocket(name, options.host, options.port, options.path, req, function (socket){
53+
req.onSocket(socket);
54+
});
55+
}else{
56+
// we are over limit so we'll add it to the queue.
57+
if(!this.requests[name])
58+
this.requests[name] = [];
59+
this.requests[name].push(req);
60+
}
61+
};
62+
63+
// Almost verbatim copy of http.Agent.createSocket
64+
HttpsProxyAgent.prototype.createSocket = function (name, host, port, localAddress, req, callback){
65+
var self = this;
66+
var options = util._extend({}, self.options);
67+
options.port = port;
68+
options.host = host;
69+
options.localAddress = localAddress;
70+
71+
options.servername = host;
72+
if(req){
73+
var hostHeader = req.getHeader('host');
74+
if(hostHeader)
75+
options.servername = hostHeader.replace(/:.*$/, '');
76+
}
77+
78+
self.createConnection(options, function (err, s) {
79+
if(err) {
80+
err.message += ' while connecting to HTTP(S) proxy server ' + self.proxyHost + ':' + self.proxyPort;
81+
82+
if (req)
83+
req.emit('error', err);
84+
else
85+
throw err;
86+
87+
return;
88+
}
89+
90+
if(!self.sockets[name]) self.sockets[name] = [];
91+
92+
self.sockets[name].push(s);
93+
94+
var onFree = function (){
95+
self.emit('free', s, host, port, localAddress);
96+
};
97+
98+
var onClose = function (err){
99+
// this is the only place where sockets get removed from the Agent.
100+
// if you want to remove a socket from the pool, just close it.
101+
// all socket errors end in a close event anyway.
102+
self.removeSocket(s, name, host, port, localAddress);
103+
};
104+
105+
var onRemove = function (){
106+
// we need this function for cases like HTTP 'upgrade'
107+
// (defined by WebSockets) where we need to remove a socket from the pool
108+
// because it'll be locked up indefinitely
109+
self.removeSocket(s, name, host, port, localAddress);
110+
s.removeListener('close', onClose);
111+
s.removeListener('free', onFree);
112+
s.removeListener('agentRemove', onRemove);
113+
};
114+
115+
s.on('free', onFree);
116+
s.on('close', onClose);
117+
s.on('agentRemove', onRemove);
118+
119+
callback(s);
120+
});
121+
};
122+
123+
module.exports = HttpsProxyAgent;

lib/Local.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,12 @@ function Local(){
199199
this.getBinaryPath = function(callback){
200200
if(typeof(this.binaryPath) == 'undefined'){
201201
this.binary = new LocalBinary();
202-
this.binary.binaryPath(callback);
202+
var conf = {};
203+
if(this.proxyHost && this.proxyPort){
204+
conf.proxyHost = this.proxyHost;
205+
conf.proxyPort = this.proxyPort;
206+
}
207+
this.binary.binaryPath(conf, callback);
203208
} else {
204209
callback(this.binaryPath);
205210
}

lib/LocalBinary.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
var https = require('https'),
2+
url = require('url'),
23
fs = require('fs'),
34
path = require('path'),
45
os = require('os'),
6+
HttpsProxyAgent = require('./HttpsProxyAgent'),
57
LocalError = require('./LocalError');
68

79
function LocalBinary(){
@@ -20,15 +22,23 @@ function LocalBinary(){
2022
this.httpPath = 'https://s3.amazonaws.com/browserStack/browserstack-local/BrowserStackLocal-linux-ia32';
2123
}
2224

23-
this.download = function(destParentDir, callback){
25+
this.download = function(conf, destParentDir, callback){
2426
if(!this.checkPath(destParentDir))
2527
fs.mkdirSync(destParentDir);
2628

2729
var destBinaryName = (this.windows) ? 'BrowserStackLocal.exe' : 'BrowserStackLocal';
2830
var binaryPath = path.join(destParentDir, destBinaryName);
2931
var file = fs.createWriteStream(binaryPath);
3032

31-
https.get(this.httpPath, function (response) {
33+
var options = url.parse(this.httpPath);
34+
if(conf.proxyHost && conf.proxyPort){
35+
options.agent = new HttpsProxyAgent({
36+
proxyHost: conf.proxyHost,
37+
proxyPort: conf.proxyPort
38+
});
39+
}
40+
41+
https.get(options, function (response) {
3242
response.on('end', function () {
3343
fs.chmod(binaryPath, '0755', function() {
3444
callback(binaryPath);
@@ -38,14 +48,14 @@ function LocalBinary(){
3848
});
3949
};
4050

41-
this.binaryPath = function(callback){
51+
this.binaryPath = function(conf, callback){
4252
var destParentDir = this.getAvailableDirs();
4353
var destBinaryName = (this.windows) ? 'BrowserStackLocal.exe' : 'BrowserStackLocal';
4454
var binaryPath = path.join(destParentDir, destBinaryName);
4555
if(this.checkPath(binaryPath, fs.X_OK)){
4656
callback(binaryPath);
4757
} else {
48-
this.download(destParentDir, callback);
58+
this.download(conf, destParentDir, callback);
4959
}
5060
};
5161

0 commit comments

Comments
 (0)