Skip to content

Commit

Permalink
fix: no_proxy issue
Browse files Browse the repository at this point in the history
  • Loading branch information
Avishagp committed Aug 25, 2022
1 parent e5dee92 commit 41e7049
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 13 deletions.
43 changes: 32 additions & 11 deletions lib/needle.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ var fs = require('fs'),
auth = require('./auth'),
cookies = require('./cookies'),
parsers = require('./parsers'),
decoder = require('./decoder');
decoder = require('./decoder'),
micromatch = require('micromatch');

//////////////////////////////////////////
// variabilia
Expand Down Expand Up @@ -191,19 +192,36 @@ function host_and_ports_match(url1, url2) {
}

// 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;
function should_proxy_to(uri) {
const noProxy = get_env_var(["NO_PROXY"], true);
if (!noProxy) {
return true;
}

let 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) {
const patternNoDot = pattern.replace(/^\./, "*")
const match = patternNoDot.match(/^(?<host>.+?)(?::(?<port>\d+))?$/);

if (!match || !match.groups || !match.groups.host) {
// given pattern is invalid, go to next
continue;
}

const hostnameMatches = micromatch.isMatch( requestUrl.hostname, match.groups.host );
const portMatches = (!match.groups.port || (requestUrl.port && (requestUrl.port === match.groups.port)));
if ( hostnameMatches && portMatches) {
// hostname + port of the request URL match a given NO_PROXY pattern
urlMatchedNoProxyPattern = true
break;
}
}

return true;
return !urlMatchedNoProxyPattern;
}

function pump_streams(streams, cb) {
Expand Down Expand Up @@ -914,3 +932,6 @@ module.exports.defaults = function(obj) {
module.exports.request = function(method, uri, data, opts, callback) {
return new Needle(method, uri, data, opts, callback).start();
};

// Exporting for testing
module.exports.should_proxy_to = should_proxy_to;
43 changes: 43 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"dependencies": {
"debug": "^3.2.6",
"iconv-lite": "^0.6.3",
"micromatch": "^4.0.5",
"sax": "^1.2.4"
},
"devDependencies": {
Expand Down
101 changes: 99 additions & 2 deletions test/proxy_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,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 +152,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;
needle.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 = "";
needle.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 (URI doesn't have port specified)", function(done) {
process.env.NO_PROXY = noProxyWithPorts;
needle.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;
needle.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;
needle.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;
needle.should_proxy_to(URI).should.false()
delete process.env.NO_PROXY;
done();
});

it("shall return false if host matches", function(done) {
process.env.NO_PROXY = noProxy;
needle.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;
needle.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;
needle.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;
needle.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,/, " ");
needle.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,/, " ");
needle.should_proxy_to(URIip).should.false()
delete process.env.NO_PROXY;
done();
});

})

})

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

0 comments on commit 41e7049

Please sign in to comment.