From 60110b8bd9b40c5eb55d03fffbb3e83327439b9a Mon Sep 17 00:00:00 2001 From: Chance Dickson Date: Mon, 23 Jul 2018 19:59:35 -0500 Subject: [PATCH 1/2] Adding support for no_proxy env variable * Adds support for the no_proxy environment variable commonly available with programs supporting the http_proxy/https_proxy environment variables. * Adds tests to test the no_proxy environment variable. --- lib/adapters/http.js | 48 +++++++++++++++++++----- test/unit/adapters/http.js | 77 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 10 deletions(-) diff --git a/lib/adapters/http.js b/lib/adapters/http.js index 8225f0067b..00dedc4c3f 100755 --- a/lib/adapters/http.js +++ b/lib/adapters/http.js @@ -102,17 +102,45 @@ module.exports = function httpAdapter(config) { var proxyUrl = process.env[proxyEnv] || process.env[proxyEnv.toUpperCase()]; if (proxyUrl) { var parsedProxyUrl = url.parse(proxyUrl); - proxy = { - host: parsedProxyUrl.hostname, - port: parsedProxyUrl.port - }; - - if (parsedProxyUrl.auth) { - var proxyUrlAuth = parsedProxyUrl.auth.split(':'); - proxy.auth = { - username: proxyUrlAuth[0], - password: proxyUrlAuth[1] + var noProxyEnv = process.env.no_proxy || process.env.NO_PROXY; + var shouldProxy = true; + + if (noProxyEnv) { + var noProxy = noProxyEnv.split(',').map(function trim(s) { + return s.trim(); + }); + + shouldProxy = !noProxy.some(function proxyMatch(proxyElement) { + if (!proxyElement) { + return false; + } + if (proxyElement === '*') { + return true; + } + if (proxyElement[0] === '.' && + parsed.hostname.substr(parsed.hostname.length - proxyElement.length) === proxyElement && + proxyElement.match(/\./g).length === parsed.hostname.match(/\./g).length) { + return true; + } + + return parsed.hostname === proxyElement; + }); + } + + + if (shouldProxy) { + proxy = { + host: parsedProxyUrl.hostname, + port: parsedProxyUrl.port }; + + if (parsedProxyUrl.auth) { + var proxyUrlAuth = parsedProxyUrl.auth.split(':'); + proxy.auth = { + username: proxyUrlAuth[0], + password: proxyUrlAuth[1] + }; + } } } } diff --git a/test/unit/adapters/http.js b/test/unit/adapters/http.js index 0dc4c6eb6c..8aca1cf8b3 100644 --- a/test/unit/adapters/http.js +++ b/test/unit/adapters/http.js @@ -21,6 +21,9 @@ describe('supports http with nodejs', function () { if (process.env.http_proxy) { delete process.env.http_proxy; } + if (process.env.no_proxy) { + delete process.env.no_proxy; + } }); it('should respect the timeout property', function (done) { @@ -403,6 +406,80 @@ describe('supports http with nodejs', function () { }); }); + it('should not use proxy for domains in no_proxy', function (done) { + server = http.createServer(function (req, res) { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end('4567'); + }).listen(4444, function () { + proxy = http.createServer(function (request, response) { + var parsed = url.parse(request.url); + var opts = { + host: parsed.hostname, + port: parsed.port, + path: parsed.path + }; + + http.get(opts, function (res) { + var body = ''; + res.on('data', function (data) { + body += data; + }); + res.on('end', function () { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(body + '1234'); + }); + }); + + }).listen(4000, function () { + // set the env variable + process.env.http_proxy = 'http://localhost:4000/'; + process.env.no_proxy = 'foo.com, localhost,bar.net , , quix.co'; + + axios.get('http://localhost:4444/').then(function (res) { + assert.equal(res.data, '4567', 'should not use proxy for domains in no_proxy'); + done(); + }); + }); + }); + }); + + it('should use proxy for domains not in no_proxy', function (done) { + server = http.createServer(function (req, res) { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end('4567'); + }).listen(4444, function () { + proxy = http.createServer(function (request, response) { + var parsed = url.parse(request.url); + var opts = { + host: parsed.hostname, + port: parsed.port, + path: parsed.path + }; + + http.get(opts, function (res) { + var body = ''; + res.on('data', function (data) { + body += data; + }); + res.on('end', function () { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(body + '1234'); + }); + }); + + }).listen(4000, function () { + // set the env variable + process.env.http_proxy = 'http://localhost:4000/'; + process.env.no_proxy = 'foo.com, ,bar.net , quix.co'; + + axios.get('http://localhost:4444/').then(function (res) { + assert.equal(res.data, '45671234', 'should use proxy for domains not in no_proxy'); + done(); + }); + }); + }); + }); + it('should support HTTP proxy auth', function (done) { server = http.createServer(function (req, res) { res.end(); From 0e808f4d4a6030c02a5baf625a0ae1e5cdfb4053 Mon Sep 17 00:00:00 2001 From: Chance Dickson Date: Tue, 7 Aug 2018 09:53:02 -0500 Subject: [PATCH 2/2] Adding documentation for the proxy env variables * Adds documentation to README.md for the supported, conventional http_proxy, https_proxy, and no_proxy environment variables. --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4612584554..ee99033ab2 100755 --- a/README.md +++ b/README.md @@ -353,7 +353,11 @@ These are the available config options for making requests. Only the `url` is re httpAgent: new http.Agent({ keepAlive: true }), httpsAgent: new https.Agent({ keepAlive: true }), - // 'proxy' defines the hostname and port of the proxy server + // 'proxy' defines the hostname and port of the proxy server. + // You can also define your proxy using the conventional `http_proxy` and + // `https_proxy` environment variables. If you are using environment variables + // for your proxy configuration, you can also define a `no_proxy` environment + // variable as a comma-separated list of domains that should not be proxied. // Use `false` to disable proxies, ignoring environment variables. // `auth` indicates that HTTP Basic auth should be used to connect to the proxy, and // supplies credentials.