Skip to content

Commit d93c442

Browse files
authored
Merge pull request #382 from tomas/env-http-proxy
Use HTTP_PROXY and HTTPS_PROXY from env, if set
2 parents 67ad8a4 + 933fd79 commit d93c442

File tree

2 files changed

+86
-13
lines changed

2 files changed

+86
-13
lines changed

lib/needle.js

+53-9
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,17 @@ Object.keys(aliased.options).map(function(k) {
126126
//////////////////////////////////////////
127127
// helpers
128128

129+
function get_env_var(keys, try_lower) {
130+
var val, i = -1, env = process.env;
131+
while (!val && i < keys.length-1) {
132+
val = env[keys[++i]];
133+
if (!val && try_lower) {
134+
val = env[keys[i].toLowerCase()];
135+
}
136+
}
137+
return val;
138+
}
139+
129140
function keys_by_type(type) {
130141
return Object.keys(defaults).map(function(el) {
131142
if (defaults[el] !== null && defaults[el].constructor == type)
@@ -168,6 +179,32 @@ function resolve_url(href, base) {
168179
return url.resolve(base, href);
169180
}
170181

182+
function host_and_ports_match(url1, url2) {
183+
if (url1.indexOf('http') < 0) url1 = 'http://' + url1;
184+
if (url2.indexOf('http') < 0) url2 = 'http://' + url2;
185+
var a = url.parse(url1), b = url.parse(url2);
186+
187+
return a.host == b.host
188+
&& String(a.port || (a.protocol == 'https:' ? 443 : 80))
189+
== String(b.port || (b.protocol == 'https:' ? 443 : 80));
190+
}
191+
192+
// returns false if a no_proxy host matches given url
193+
function should_proxy_to(url) {
194+
var no_proxy = get_env_var(['NO_PROXY'], true);
195+
if (!no_proxy) return true;
196+
197+
var host, hosts = no_proxy.split(',');
198+
for (var i in hosts) {
199+
host = hosts[i];
200+
if (host_and_ports_match(host, url)) {
201+
return false;
202+
}
203+
}
204+
205+
return true;
206+
}
207+
171208
function pump_streams(streams, cb) {
172209
if (stream.pipeline)
173210
return stream.pipeline.apply(null, streams.concat(cb));
@@ -299,19 +336,26 @@ Needle.prototype.setup = function(uri, options) {
299336
}
300337
}
301338

339+
var env_proxy = get_env_var(['HTTP_PROXY', 'HTTPS_PROXY'], true);
340+
if (!config.proxy && env_proxy) config.proxy = env_proxy;
341+
302342
// if proxy is present, set auth header from either url or proxy_user option.
303343
if (config.proxy) {
304-
if (config.proxy.indexOf('http') === -1)
305-
config.proxy = 'http://' + config.proxy;
344+
if (should_proxy_to(uri)) {
345+
if (config.proxy.indexOf('http') === -1)
346+
config.proxy = 'http://' + config.proxy;
347+
348+
if (config.proxy.indexOf('@') !== -1) {
349+
var proxy = (url.parse(config.proxy).auth || '').split(':');
350+
options.proxy_user = proxy[0];
351+
options.proxy_pass = proxy[1];
352+
}
306353

307-
if (config.proxy.indexOf('@') !== -1) {
308-
var proxy = (url.parse(config.proxy).auth || '').split(':');
309-
options.proxy_user = proxy[0];
310-
options.proxy_pass = proxy[1];
354+
if (options.proxy_user)
355+
config.headers['proxy-authorization'] = auth.basic(options.proxy_user, options.proxy_pass);
356+
} else {
357+
delete config.proxy;
311358
}
312-
313-
if (options.proxy_user)
314-
config.headers['proxy-authorization'] = auth.basic(options.proxy_user, options.proxy_pass);
315359
}
316360

317361
// now that all our headers are set, overwrite them if instructed.

test/proxy_spec.js

+33-4
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,41 @@ describe('proxy option', function() {
117117

118118
describe('when valid url is passed', function() {
119119

120-
it('proxies request', function(done) {
121-
send_request({ proxy: nonexisting_host + ':123/done' }, proxied(nonexisting_host, '123', done))
120+
describe('without NO_PROXY env var set', function() {
121+
it('proxies request', function(done) {
122+
send_request({ proxy: nonexisting_host + ':123/done' }, proxied(nonexisting_host, '123', done))
123+
})
124+
125+
it('does not set a Proxy-Authorization header', function(done) {
126+
send_request({ proxy: nonexisting_host + ':123/done' }, no_proxy_auth(done));
127+
})
122128
})
123129

124-
it('does not set a Proxy-Authorization header', function(done) {
125-
send_request({ proxy: nonexisting_host + ':123/done' }, no_proxy_auth(done));
130+
describe('with NO_PROXY env var set', function() {
131+
132+
it('proxies request if matching host not found in list', function(done) {
133+
process.env.NO_PROXY = 'foo';
134+
send_request({ proxy: nonexisting_host + ':123/done' }, proxied(nonexisting_host, '123', function() {
135+
delete process.env.NO_PROXY;
136+
done();
137+
}))
138+
})
139+
140+
it('proxies request if matching host in list but different port', function(done) {
141+
process.env.NO_PROXY = 'localhost';
142+
send_request({ proxy: nonexisting_host + ':123/done' }, proxied(nonexisting_host, '123', function() {
143+
delete process.env.NO_PROXY;
144+
done();
145+
}))
146+
})
147+
148+
it('does not proxy if matching host found in list', function(done) {
149+
process.env.NO_PROXY = 'foo,' + url;
150+
send_request({ proxy: nonexisting_host + ':123/done' }, not_proxied(function() {
151+
delete process.env.NO_PROXY;
152+
done();
153+
}))
154+
})
126155
})
127156

128157
describe('and proxy url contains user:pass', function() {

0 commit comments

Comments
 (0)