Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: no_proxy issue #411

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 14 additions & 39 deletions lib/needle.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,20 @@
// MIT Licensed
//////////////////////////////////////////

var fs = require('fs'),
http = require('http'),
https = require('https'),
url = require('url'),
stream = require('stream'),
debug = require('debug')('needle'),
stringify = require('./querystring').build,
multipart = require('./multipart'),
auth = require('./auth'),
cookies = require('./cookies'),
parsers = require('./parsers'),
decoder = require('./decoder');
var fs = require('fs'),
http = require('http'),
https = require('https'),
url = require('url'),
stream = require('stream'),
debug = require('debug')('needle'),
stringify = require('./querystring').build,
multipart = require('./multipart'),
auth = require('./auth'),
cookies = require('./cookies'),
parsers = require('./parsers'),
decoder = require('./decoder'),
should_proxy_to = require('./proxy').should_proxy_to,
get_env_var = require('./proxy').get_env_var;

//////////////////////////////////////////
// variabilia
Expand Down Expand Up @@ -127,17 +129,6 @@ Object.keys(aliased.options).map(function(k) {
//////////////////////////////////////////
// helpers

function get_env_var(keys, try_lower) {
var val, i = -1, env = process.env;
while (!val && i < keys.length-1) {
val = env[keys[++i]];
if (!val && try_lower) {
val = env[keys[i].toLowerCase()];
}
}
return val;
}

function keys_by_type(type) {
return Object.keys(defaults).map(function(el) {
if (defaults[el] !== null && defaults[el].constructor == type)
Expand Down Expand Up @@ -190,22 +181,6 @@ function host_and_ports_match(url1, url2) {
== String(b.port || (b.protocol == 'https:' ? 443 : 80));
}

// returns false if a no_proxy host matches given url
function should_proxy_to(url) {
var no_proxy = get_env_var(['NO_PROXY'], true);
if (!no_proxy) return true;

var host, hosts = no_proxy.split(',');
for (var i in hosts) {
host = hosts[i];
if (host_and_ports_match(host, url)) {
return false;
}
}

return true;
}

function pump_streams(streams, cb) {
if (stream.pipeline)
return stream.pipeline.apply(null, streams.concat(cb));
Expand Down
47 changes: 47 additions & 0 deletions lib/proxy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
function get_env_var(keys, try_lower) {
var val, i = -1, env = process.env;
while (!val && i < keys.length-1) {
val = env[keys[++i]];
if (!val && try_lower) {
val = env[keys[i].toLowerCase()];
}
}
return val;
}

// returns false if a no_proxy host matches given url
function should_proxy_to(uri) {
const noProxy = get_env_var(["NO_PROXY"], true);
if (!noProxy) {
return true;
}

var urlMatchedNoProxyPattern = false;
const requestUrl = new URL(uri);
const patternList = noProxy.split(/[\s,]+/);

// iterate over all NO_PROXY patterns and determine whether the given URL matches any of them
for (const pattern of patternList) {
if(pattern.trim().length == 0) {
continue;
}

// replace leading dot by asterisk, escape dots and finally replace asterisk by .*
const preparedPattern = pattern.replace(/^\./, "*").replace(/[.]/g, '\\$&').replace(/\*/g, '.*')
const regex = new RegExp(preparedPattern)
const isRegexExists = uri.match(regex);
if (isRegexExists) {
const matches = (isRegexExists.length > 0);
if (matches) {
// hostname + port of the request URL match a given NO_PROXY pattern
urlMatchedNoProxyPattern = true;
break;
}
}
}

return !urlMatchedNoProxyPattern;
}

module.exports.should_proxy_to = should_proxy_to;
module.exports.get_env_var = get_env_var;
104 changes: 101 additions & 3 deletions test/proxy_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ var helpers = require('./helpers'),
should = require('should'),
sinon = require('sinon'),
http = require('http'),
needle = require('./../');
needle = require('./../'),
should_proxy_to = require('./../lib/proxy').should_proxy_to;

var port = 7707;
var url = 'localhost:' + port;
Expand Down Expand Up @@ -137,9 +138,9 @@ describe('proxy option', function() {
}))
})

it('proxies request if matching host in list but different port', function(done) {
it('does not proxy request if matching host in list and just has a different port', function(done) {
process.env.NO_PROXY = 'localhost';
send_request({ proxy: nonexisting_host + ':123/done' }, proxied(nonexisting_host, '123', function() {
send_request({ proxy: nonexisting_host + ':123/done' }, not_proxied(function() {
delete process.env.NO_PROXY;
done();
}))
Expand All @@ -152,6 +153,103 @@ describe('proxy option', function() {
done();
}))
})

describe('should_proxy_to()', function() {

const noProxy = ".ic1.mycorp,localhost,127.0.0.1,*.mycorp.org";
const noProxyWithPorts = " ,.mycorp.org:1234,.ic1.mycorp,localhost,127.0.0.1";
const URI = "http://registry.random.opr.mycorp.org";
const URIWithPort = "http://registry.random.opr.mycorp.org:9874";
const URIWithPort1234 = "http://registry.random.opr.mycorp.org:1234";
const URIlocalhost = "http://localhost";
const URIip = "http://127.0.0.1";

it("shall return true if NO_PROXY is undefined", function(done) {
process.env.NO_PROXY = undefined;
should_proxy_to(URI).should.true()
delete process.env.NO_PROXY;
done();
});

it("shall return true if NO_PROXY is empty", function(done) {
process.env.NO_PROXY = "";
should_proxy_to(URI).should.true()
delete process.env.NO_PROXY;
done();
});

it("shall return false if NO_PROXY is a wildcard", function(done) {
process.env.NO_PROXY = "*";
should_proxy_to(URI).should.false()
delete process.env.NO_PROXY;
done();
});

it("shall return true if the host matches and the ports don't (URI doesn't have port specified)", function(done) {
process.env.NO_PROXY = noProxyWithPorts;
should_proxy_to(URI).should.true()
delete process.env.NO_PROXY;
done();
});

it("shall return true if the host matches and the ports don't (both have a port specified but just different values)", function(done) {
process.env.NO_PROXY = noProxyWithPorts;
should_proxy_to(URIWithPort).should.true()
delete process.env.NO_PROXY;
done();
});

it("shall return false if the host matches and the ports don't (no_proxy pattern doesn't have a port)", function(done) {
process.env.NO_PROXY = noProxy;
should_proxy_to(URIWithPort).should.false()
delete process.env.NO_PROXY;
done();
});

it("shall return false if host matches", function(done) {
process.env.NO_PROXY = noProxy;
should_proxy_to(URI).should.false()
delete process.env.NO_PROXY;
done();
});

it("shall return false if the host and port matches", function(done) {
process.env.NO_PROXY = noProxyWithPorts;
should_proxy_to(URIWithPort1234).should.false()
delete process.env.NO_PROXY;
done();
});

it("shall return false if the host matches (localhost)", function(done) {
process.env.NO_PROXY = noProxy;
should_proxy_to(URIlocalhost).should.false()
delete process.env.NO_PROXY;
done();
});

it("shall return false if the host matches (ip)", function(done) {
process.env.NO_PROXY = noProxy;
should_proxy_to(URIip).should.false()
delete process.env.NO_PROXY;
done();
});

it("shall return false if the host matches (ip)", function(done) {
process.env.NO_PROXY = noProxy.replace(/,g/, " ");
should_proxy_to(URIip).should.false()
delete process.env.NO_PROXY;
done();
});

it("shall return false if the host matches (ip)", function(done) {
process.env.NO_PROXY = noProxy.replace(/,g/, " ");
should_proxy_to(URIip).should.false()
delete process.env.NO_PROXY;
done();
});

})

})

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