From ed47ef8b568018928e4560f7380d1752573a5e32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emanuel=20Inderm=C3=BChle?= Date: Thu, 1 Dec 2016 22:28:21 +0100 Subject: [PATCH 1/4] Adding interpretation of no_proxy as suggested by #434 --- lib/adapters/http.js | 23 +++++++++++ test/unit/adapters/http.js | 80 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 100 insertions(+), 3 deletions(-) diff --git a/lib/adapters/http.js b/lib/adapters/http.js index 8a2fc57dac..d68a4b8ea4 100644 --- a/lib/adapters/http.js +++ b/lib/adapters/http.js @@ -14,6 +14,23 @@ var Buffer = require('buffer').Buffer; var createError = require('../core/createError'); var enhanceError = require('../core/enhanceError'); + +function isANoProxyHost(host) { + var noProxy = process.env.no_proxy || process.env.NO_PROXY; + if (!noProxy) { + return false; + } + var isANoProxyProxy = false; + noProxy.split(',') + .forEach(function noProxyMatchProxy(np) { + var npTrimmed = np.trim(); + if (host.lastIndexOf(npTrimmed) === host.length - npTrimmed.length) { + isANoProxyProxy = true; + } + }); + return isANoProxyProxy; +} + /*eslint consistent-return:0*/ module.exports = function httpAdapter(config) { return new Promise(function dispatchHttpRequest(resolve, reject) { @@ -99,6 +116,9 @@ module.exports = function httpAdapter(config) { password: proxyUrlAuth[1] }; } + if (isANoProxyHost(proxy.host)) { + proxy = undefined; + } } } @@ -224,3 +244,6 @@ module.exports = function httpAdapter(config) { } }); }; + + +module.exports._isANoProxyHost = isANoProxyHost; diff --git a/test/unit/adapters/http.js b/test/unit/adapters/http.js index 131bce0032..d5a66102ef 100644 --- a/test/unit/adapters/http.js +++ b/test/unit/adapters/http.js @@ -3,14 +3,17 @@ var http = require('http'); var url = require('url'); var zlib = require('zlib'); var fs = require('fs'); +var adapter = require('../../../lib/adapters/http.js'); var server, proxy; module.exports = { tearDown: function (callback) { - server.close(); - server = null; + if (server) { + server.close(); + server = null; + } if (proxy) { - proxy.close() + proxy.close(); proxy = null; } @@ -18,6 +21,9 @@ module.exports = { delete process.env.http_proxy; } + delete process.env.no_proxy; + delete process.env.NO_PROXY; + callback(); }, @@ -313,6 +319,7 @@ module.exports = { }).listen(4000, function() { // set the env variable process.env.http_proxy = 'http://localhost:4000/'; + process.env.no_proxy = 'my.corp.com'; axios.get('http://localhost:4444/').then(function(res) { test.equal(res.data, '45671234', 'should use proxy set by process.env.http_proxy'); @@ -322,6 +329,73 @@ module.exports = { }); }, + testIsANoProxyHost: function(test) { + [ + {h: 'bliss.mit.edu', no_p: undefined, res: false}, + {h: 'bliss.mit.edu', no_p: 'localhost', res: false}, + {h: 'bliss.mit.edu', no_p: 'localhost, my.corp.com', res: false}, + {h: 'bliss.mit.edu', no_p: 'mit.edu', res: true}, + {h: 'bliss.mit.edu', no_p: 'mit.edu,localhost', res: true}, + {h: 'bliss.mit.edu', no_p: ' mit.edu', res: true}, + {h: 'bliss.mit.edu', no_p: 'mit.edu ', res: true}, + {h: 'bliss.mit.edu', no_p: 'localhost, mit.edu', res: true}, + {h: 'bliss.mit.edu', no_p: 'u', res: true}, + {h: '127.0.0.1', no_p: '0.0.1', res: true}, + {h: '127.0.0.1', no_p: 'localhost', res: false} + ].forEach(function(data) { + process.env.no_proxy = data.no_p; + test.equal(adapter._isANoProxyHost(data.h), data.res, + 'When no_proxy="' + data.no_p + '", then host "' + data.h + '" must ' + (data.res ? 'not ' : '') + 'be proxied'); + delete process.env.no_proxy; + + process.env.NO_PROXY = data.no_p; + test.equal(adapter._isANoProxyHost(data.h), data.res, + 'When NO_PROXY="' + data.no_p + '", then host "' + data.h + '" must ' + (data.res ? 'not ' : '') + 'be proxied'); + delete process.env.NO_PROXY; + }); + + test.done(); + }, + + testHTTPNoProxyEnv: function(test) { + 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 = 'localhost'; + + axios.get('http://localhost:4444/').then(function(res) { + test.equal(res.data, '4567', 'should not use proxy set by process.env.http_proxy as of process.env.no_proxy'); + test.done(); + }, function() { + test.ok(false, 'error occured during request with no_proxy'); + test.done(); + }); + }); + }); + }, + testHTTPProxyAuth: function(test) { server = http.createServer(function(req, res) { res.end(); From 24ecb51227b516fc903b3fe5b518f2fbccdb36e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emanuel=20Inderm=C3=BChle?= Date: Thu, 20 Jul 2017 23:05:48 +0200 Subject: [PATCH 2/4] Fixing interpretation of no_proxy by checking correct hostname as suggested by #434 --- lib/adapters/http.js | 2 +- test/unit/adapters/http.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/adapters/http.js b/lib/adapters/http.js index d68a4b8ea4..757a13490f 100644 --- a/lib/adapters/http.js +++ b/lib/adapters/http.js @@ -116,7 +116,7 @@ module.exports = function httpAdapter(config) { password: proxyUrlAuth[1] }; } - if (isANoProxyHost(proxy.host)) { + if (isANoProxyHost(parsed.hostname)) { proxy = undefined; } } diff --git a/test/unit/adapters/http.js b/test/unit/adapters/http.js index d5a66102ef..84bc75976e 100644 --- a/test/unit/adapters/http.js +++ b/test/unit/adapters/http.js @@ -382,7 +382,7 @@ module.exports = { }); }).listen(4000, function() { // set the env variable - process.env.http_proxy = 'http://localhost:4000/'; + process.env.http_proxy = 'http://127.0.0.1:4000/'; process.env.no_proxy = 'localhost'; axios.get('http://localhost:4444/').then(function(res) { From afbb7b0414683d7f852eb83c4e6832487d9f8e46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emanuel=20Inderm=C3=BChle?= Date: Sun, 20 Aug 2017 23:46:41 +0200 Subject: [PATCH 3/4] rewrite reading proxy from env using proxy-from-env --- lib/adapters/http.js | 45 +-------- lib/adapters/http.proxy.js | 42 ++++++++ package.json | 3 +- test/unit/adapters/http.js | 28 ------ test/unit/adapters/proxy.js | 196 ++++++++++++++++++++++++++++++++++++ 5 files changed, 242 insertions(+), 72 deletions(-) create mode 100644 lib/adapters/http.proxy.js create mode 100644 test/unit/adapters/proxy.js diff --git a/lib/adapters/http.js b/lib/adapters/http.js index 5780993043..b013b1496d 100644 --- a/lib/adapters/http.js +++ b/lib/adapters/http.js @@ -12,23 +12,7 @@ var zlib = require('zlib'); var pkg = require('./../../package.json'); var createError = require('../core/createError'); var enhanceError = require('../core/enhanceError'); - - -function isANoProxyHost(host) { - var noProxy = process.env.no_proxy || process.env.NO_PROXY; - if (!noProxy) { - return false; - } - var isANoProxyProxy = false; - noProxy.split(',') - .forEach(function noProxyMatchProxy(np) { - var npTrimmed = np.trim(); - if (host.lastIndexOf(npTrimmed) === host.length - npTrimmed.length) { - isANoProxyProxy = true; - } - }); - return isANoProxyProxy; -} +var getProxy = require('./http.proxy'); /*eslint consistent-return:0*/ module.exports = function httpAdapter(config) { @@ -98,29 +82,7 @@ module.exports = function httpAdapter(config) { auth: auth }; - var proxy = config.proxy; - if (!proxy) { - var proxyEnv = protocol.slice(0, -1) + '_proxy'; - 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] - }; - } - if (isANoProxyHost(parsed.hostname)) { - proxy = undefined; - } - } - } + var proxy = getProxy(config); if (proxy) { options.hostname = proxy.host; @@ -244,6 +206,3 @@ module.exports = function httpAdapter(config) { } }); }; - - -module.exports._isANoProxyHost = isANoProxyHost; diff --git a/lib/adapters/http.proxy.js b/lib/adapters/http.proxy.js new file mode 100644 index 0000000000..d2ba2d12d5 --- /dev/null +++ b/lib/adapters/http.proxy.js @@ -0,0 +1,42 @@ +'use strict'; + +var url = require('url'); + +var getProxyForUrl = require('proxy-from-env').getProxyForUrl; + +/** + * + * @param {Object} config + * @param {string} config.url + * @param {Object=) config.proxy + * @param {string} config.proxy.host + * @param {number} config.proxy.port + * @return {object | undefined} proxy + * @return {string} proxy.host + * @return {number} proxy.number + * @return {object | undefined} proxy.auth + * @return {string} proxy.auth.username + * @return {string} proxy.auth.password + */ +module.exports = function getProxy(config) { + var proxy = config.proxy; + if (!proxy) { + var envProxy = getProxyForUrl(config.url); + if (envProxy) { + var parsedProxyUrl = url.parse(envProxy); + proxy = { + host: parsedProxyUrl.hostname, + port: parsedProxyUrl.port + }; + + if (parsedProxyUrl.auth) { + var proxyUrlAuth = parsedProxyUrl.auth.split(':'); + proxy.auth = { + username: proxyUrlAuth[0], + password: proxyUrlAuth[1] + }; + } + } + } + return proxy; +}; diff --git a/package.json b/package.json index a8b3baa4c6..70e09b2eb4 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,7 @@ "typings": "./index.d.ts", "dependencies": { "follow-redirects": "^1.2.3", - "is-buffer": "^1.1.5" + "is-buffer": "^1.1.5", + "proxy-from-env": "^1.0.0" } } diff --git a/test/unit/adapters/http.js b/test/unit/adapters/http.js index 1e036bb52a..eae7a7b900 100644 --- a/test/unit/adapters/http.js +++ b/test/unit/adapters/http.js @@ -354,34 +354,6 @@ module.exports = { }); }, - testIsANoProxyHost: function(test) { - [ - {h: 'bliss.mit.edu', no_p: undefined, res: false}, - {h: 'bliss.mit.edu', no_p: 'localhost', res: false}, - {h: 'bliss.mit.edu', no_p: 'localhost, my.corp.com', res: false}, - {h: 'bliss.mit.edu', no_p: 'mit.edu', res: true}, - {h: 'bliss.mit.edu', no_p: 'mit.edu,localhost', res: true}, - {h: 'bliss.mit.edu', no_p: ' mit.edu', res: true}, - {h: 'bliss.mit.edu', no_p: 'mit.edu ', res: true}, - {h: 'bliss.mit.edu', no_p: 'localhost, mit.edu', res: true}, - {h: 'bliss.mit.edu', no_p: 'u', res: true}, - {h: '127.0.0.1', no_p: '0.0.1', res: true}, - {h: '127.0.0.1', no_p: 'localhost', res: false} - ].forEach(function(data) { - process.env.no_proxy = data.no_p; - test.equal(adapter._isANoProxyHost(data.h), data.res, - 'When no_proxy="' + data.no_p + '", then host "' + data.h + '" must ' + (data.res ? 'not ' : '') + 'be proxied'); - delete process.env.no_proxy; - - process.env.NO_PROXY = data.no_p; - test.equal(adapter._isANoProxyHost(data.h), data.res, - 'When NO_PROXY="' + data.no_p + '", then host "' + data.h + '" must ' + (data.res ? 'not ' : '') + 'be proxied'); - delete process.env.NO_PROXY; - }); - - test.done(); - }, - testHTTPNoProxyEnv: function(test) { server = http.createServer(function(req, res) { res.setHeader('Content-Type', 'text/html; charset=UTF-8'); diff --git a/test/unit/adapters/proxy.js b/test/unit/adapters/proxy.js new file mode 100644 index 0000000000..528dede68f --- /dev/null +++ b/test/unit/adapters/proxy.js @@ -0,0 +1,196 @@ +'use strict'; + +var getProxy = require('../../../lib/adapters/http.proxy'); + +function config(def) { + var cfg = {}; + cfg.url = def && def.url || 'http://google.com'; + cfg.proxy = def && def.proxy; + return cfg; +} + + +module.exports = { + + setUp: function(done) { + delete process.env.http_proxy; + delete process.env.https_proxy; + delete process.env.no_proxy; + delete process.env.HTTP_PROXY; + delete process.env.HTTPS_PROXY; + delete process.env.NO_PROXY; + done(); + }, + + isEmptyIfNotConfigured: function(test) { + test.equal(getProxy(config()), undefined); + test.done(); + }, + + canReadProxyHostFromConfig: function(test) { + var cfg = config({proxy: {host: 'corpproxy.com'}}); + var proxy = getProxy(cfg); + test.equal(proxy.host, 'corpproxy.com'); + test.equal(proxy.port, undefined); + test.equal(proxy.auth, undefined); + test.done(); + }, + + canReadProxyAndPortHostFromConfig: function(test) { + var cfg = config({proxy: {host: 'corpproxy.com', port: 80}}); + var proxy = getProxy(cfg); + test.equal(proxy.host, 'corpproxy.com'); + test.equal(proxy.port, 80); + test.equal(proxy.auth, undefined); + test.done(); + }, + + + canReadProxyAndAuthHostFromConfig: function(test) { + var cfg = config({proxy: {host: 'corpproxy.com', auth: {password: 'secret', username: 'bob'}}}); + var proxy = getProxy(cfg); + test.equal(proxy.host, 'corpproxy.com'); + test.equal(proxy.port, undefined); + test.deepEqual(proxy.auth, {password: 'secret', username: 'bob'}); + test.done(); + }, + + canReadProxyHostFromEnv: function(test) { + process.env.http_proxy = 'http://corpproxy.com/'; + var proxy = getProxy(config()); + test.equal(proxy.host, 'corpproxy.com'); + test.equal(proxy.port, undefined); + test.equal(proxy.auth, undefined); + test.done(); + }, + + canReadProxyHostAndPortFromEnv: function(test) { + process.env.http_proxy = 'http://corpproxy.com:77/'; + var proxy = getProxy(config()); + test.equal(proxy.host, 'corpproxy.com'); + test.equal(proxy.port, 77); + test.equal(proxy.auth, undefined); + test.done(); + }, + + canReadProxyHostAndPortAndAuthFromEnv: function(test) { + process.env.http_proxy = 'http://bob:secret@corpproxy.com:77/'; + var proxy = getProxy(config()); + test.equal(proxy.host, 'corpproxy.com'); + test.equal(proxy.port, 77); + test.deepEqual(proxy.auth, {username: 'bob', password: 'secret'}); + test.done(); + }, + + proxyFromConfigOverridesProxyFromEnv: function(test) { + process.env.http_proxy = 'http://bob:secret@corpproxy.com:77/'; + var proxy = getProxy(config({proxy: {host: 'other-host.com'}})); + test.equal(proxy.host, 'other-host.com'); + test.equal(proxy.port, undefined); + test.equal(proxy.auth, undefined); + test.done(); + }, + + readProxyFromCorrectEnv: function(test) { + process.env.https_proxy = 'http://corpproxy.com/'; + test.equal(getProxy(config()), undefined); + process.env.http_proxy = 'http://other-proxy.com/'; + test.equal(getProxy(config()).host, 'other-proxy.com'); + test.equal(getProxy(config({url: 'https://google.com/'})).host, 'corpproxy.com'); + delete process.env.https_proxy; + test.equal(getProxy(config({url: 'https://google.com/'})), undefined); + test.done(); + }, + + canHandleCasingInProxyEnv: function(test) { + process.env.HTTPS_PROXY = 'http://corpproxy.com/'; + test.equal(getProxy(config()), undefined); + process.env.HTTP_PROXY = 'http://other-proxy.com/'; + test.equal(getProxy(config()).host, 'other-proxy.com'); + test.equal(getProxy(config({url: 'https://google.com/'})).host, 'corpproxy.com'); + delete process.env.HTTPS_PROXY; + test.equal(getProxy(config({url: 'https://google.com/'})), undefined); + test.done(); + }, + + canHandleNoProxy: function(test) { + process.env.HTTPS_PROXY = 'http://corpproxy.com/'; + process.env.NO_PROXY = 'google.com'; + test.equal(getProxy(config({url: 'https://google.com'})), undefined); + test.equal(getProxy(config({url: 'https://google.com/page.php'})), undefined); + test.done(); + }, + + canHandleNoNoProxy: function(test) { + process.env.HTTPS_PROXY = 'http://cc.com/'; + process.env.NO_PROXY = 'google.com'; + test.equal(getProxy(config({url: 'https://sbb.com'})).host, 'cc.com'); + test.equal(getProxy(config({url: 'https://www.google.com/page.php'})).host, 'cc.com'); + test.done(); + }, + + canHandleMultipleNoProxy: function(test) { + process.env.HTTPS_PROXY = 'http://corpproxy.com/'; + process.env.NO_PROXY = 'google.com, .amazon.de nzz.ch '; + test.equal(getProxy(config({url: 'https://google.com'})), undefined); + test.equal(getProxy(config({url: 'https://www.amazon.de/index.html'})), undefined); + test.equal(getProxy(config({url: 'https://nzz.ch/index.html'})), undefined); + test.done(); + }, + + canHandlePortsInNoProxy: function(test) { + process.env.HTTPS_PROXY = 'http://cc.com/'; + process.env.NO_PROXY = '*google.com:8080'; + test.equal(getProxy(config({url: 'https://www2.google.com:8080/index.html'})), undefined); + test.equal(getProxy(config({url: 'https://google.com/index.html'})).host, 'cc.com'); + test.equal(getProxy(config({url: 'https://nzz.ch/index.html'})).host, 'cc.com'); + test.done(); + }, + + canHandleStarInNoProxy: function(test) { + process.env.HTTPS_PROXY = 'http://cc.com/'; + process.env.NO_PROXY = '*'; + test.equal(getProxy(config({url: 'https://www2.google.com:8080/index.html'})), undefined); + test.equal(getProxy(config({url: 'https://google.com/index.html'})), undefined); + test.equal(getProxy(config({url: 'https://nzz.ch/index.html'})), undefined); + test.done(); + }, + + testIsANoProxyHost: function(test) { + process.env.HTTPS_PROXY = 'http://cc.com/'; + [ + {h: 'bliss.mit.edu', no_p: undefined, res: false}, + {h: 'bliss.mit.edu', no_p: 'localhost', res: false}, + {h: 'bliss.mit.edu', no_p: 'localhost, my.corp.com', res: false}, + {h: 'bliss.mit.edu', no_p: '.mit.edu', res: true}, + {h: 'bliss.mit.edu', no_p: '.mit.edu,localhost', res: true}, + {h: 'bliss.mit.edu', no_p: ' .mit.edu', res: true}, + {h: 'bliss.mit.edu', no_p: '.mit.edu ', res: true}, + {h: 'bliss.mit.edu', no_p: 'localhost, .mit.edu', res: true}, + {h: 'bliss.mit.edu', no_p: '.edu', res: true}, + {h: '127.0.0.1', no_p: '.0.0.1', res: true}, + {h: '127.0.0.1', no_p: 'localhost', res: false} + ].forEach(function(data) { + process.env.no_proxy = data.no_p; + var proxy = getProxy(config({url: 'https://' + data.h + '/index.html'})); + if (data.res) { + test.equal(proxy, undefined); + } else { + test.equal(proxy.host, 'cc.com'); + } + delete process.env.no_proxy; + + process.env.NO_PROXY = data.no_p; + var proxy2 = getProxy(config({url: 'https://' + data.h + '/index.html'})); + if (data.res) { + test.equal(proxy2, undefined); + } else { + test.equal(proxy2.host, 'cc.com'); + } + delete process.env.NO_PROXY; + }); + + test.done(); + } +}; + From 44967bf9510b884c4580419ba95bfd91713dfadb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emanuel=20Inderm=C3=BChle?= Date: Sun, 20 Aug 2017 23:56:59 +0200 Subject: [PATCH 4/4] Adding a way to disable all proxy processing (#691) again --- lib/adapters/http.proxy.js | 4 ++-- test/unit/adapters/proxy.js | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/adapters/http.proxy.js b/lib/adapters/http.proxy.js index d2ba2d12d5..4f8ccd22b1 100644 --- a/lib/adapters/http.proxy.js +++ b/lib/adapters/http.proxy.js @@ -20,7 +20,7 @@ var getProxyForUrl = require('proxy-from-env').getProxyForUrl; */ module.exports = function getProxy(config) { var proxy = config.proxy; - if (!proxy) { + if (!proxy && proxy !== false) { var envProxy = getProxyForUrl(config.url); if (envProxy) { var parsedProxyUrl = url.parse(envProxy); @@ -38,5 +38,5 @@ module.exports = function getProxy(config) { } } } - return proxy; + return proxy || undefined; }; diff --git a/test/unit/adapters/proxy.js b/test/unit/adapters/proxy.js index 528dede68f..878d96471a 100644 --- a/test/unit/adapters/proxy.js +++ b/test/unit/adapters/proxy.js @@ -91,6 +91,13 @@ module.exports = { test.done(); }, + proxyUnsetFromConfigOverridesProxyFromEnv: function(test) { + process.env.http_proxy = 'http://bob:secret@corpproxy.com:77/'; + var proxy = getProxy(config({proxy: false})); + test.equal(proxy, undefined); + test.done(); + }, + readProxyFromCorrectEnv: function(test) { process.env.https_proxy = 'http://corpproxy.com/'; test.equal(getProxy(config()), undefined);