diff --git a/lib/install.js b/lib/install.js index fa2e1c5430..76fe4b9f46 100644 --- a/lib/install.js +++ b/lib/install.js @@ -22,6 +22,7 @@ var fs = require('graceful-fs') , request = require('request') , minimatch = require('minimatch') , mkdir = require('mkdirp') + , url = require('url') , processRelease = require('./process-release') , win = process.platform == 'win32' @@ -423,6 +424,44 @@ function install (gyp, argv, callback) { } +function formatHostname (hostname) { + // canonicalize the hostname, so that 'oogle.com' won't match 'google.com' + return hostname.replace(/^\.*/, '.').toLowerCase() +} + +function parseNoProxyZone (zone) { + zone = zone.trim().toLowerCase() + + var zoneParts = zone.split(':', 2) + var zoneHost = formatHostname(zoneParts[0]) + var zonePort = zoneParts[1] + var hasPort = zone.indexOf(':') > -1 + + return {hostname: zoneHost, port: zonePort, hasPort: hasPort} +} + +function uriInNoProxy (uri, noProxy) { + var parsedUri = url.parse(uri); + var port = parsedUri.port || (parsedUri.protocol === 'https:' ? '443' : '80') + var hostname = formatHostname(parsedUri.hostname) + var noProxyList = noProxy.split(',') + + // iterate through the noProxyList until it finds a match. + return noProxyList.map(parseNoProxyZone).some(function (noProxyZone) { + var isMatchedAt = hostname.indexOf(noProxyZone.hostname) + var hostnameMatched = ( + isMatchedAt > -1 && + (isMatchedAt === hostname.length - noProxyZone.hostname.length) + ) + + if (noProxyZone.hasPort) { + return (port === noProxyZone.port) && hostnameMatched + } + + return hostnameMatched + }) +} + function download (gyp, env, url) { log.http('GET', url) @@ -438,18 +477,32 @@ function download (gyp, env, url) { requestOpts.ca = readCAFile(cafile) } - // basic support for a proxy server - var proxyUrl = gyp.opts.proxy - || env.http_proxy - || env.HTTP_PROXY - || env.npm_config_proxy - if (proxyUrl) { - if (/^https?:\/\//i.test(proxyUrl)) { - log.verbose('download', 'using proxy url: "%s"', proxyUrl) - requestOpts.proxy = proxyUrl - } else { - log.warn('download', 'ignoring invalid "proxy" config setting: "%s"', proxyUrl) + var noProxyUrl = gyp.opts.no_proxy + || env.no_proxy + || env.NO_PROXY + || env.npm_config_no_proxy + || '' + + if (noProxyUrl === '*' || (noProxyUrl !== '' && uriInNoProxy(url, noProxyUrl))) { + log.warn('download', 'ignoring proxy for url: "%s"', url) + } else { + + // basic support for a proxy server + var proxyUrl = gyp.opts.proxy + || env.http_proxy + || env.HTTP_PROXY + || env.npm_config_proxy + + if (proxyUrl) { + if (/^https?:\/\//i.test(proxyUrl)) { + log.verbose('download', 'using proxy url: "%s"', proxyUrl) + requestOpts.proxy = proxyUrl + } else { + log.warn('download', 'ignoring invalid "proxy" config setting: "%s"', proxyUrl) + } } + + } var req = request(requestOpts) diff --git a/test/test-download-options.js b/test/test-download-options.js new file mode 100644 index 0000000000..44daec5335 --- /dev/null +++ b/test/test-download-options.js @@ -0,0 +1,63 @@ +var test = require('tape') +var requireInject = require('require-inject'); +var install = requireInject('../lib/install', { + 'request': function(opts) { + return { + opts: opts, + on: function () {} + }; + } +}) + +test('add proxy property when proxy is specified', function (t) { + t.plan(2) + + var url = 'http://www.xyz.com'; + var gyp = { + opts: { + proxy: 'http://www.test.com' + } + } + + var req = install.test.download(gyp, {}, url) + + t.equal(req.opts.proxy, gyp.opts.proxy) + t.equal(req.opts.uri, url) + +}) + +test('when no_proxy = * omit proxy property', function (t) { + t.plan(2) + + var url = 'http://www.xyz.com'; + var gyp = { + opts: { + proxy: 'http://www.test.com', + no_proxy: '*' + } + } + + var req = install.test.download(gyp, {}, url) + + t.equal(req.opts.proxy, undefined) + t.equal(req.opts.uri, url) + +}) + +test('when no_proxy matches url omit proxy property', function (t) { + t.plan(2) + + var url = 'http://www.xyz.com'; + var gyp = { + opts: { + proxy: 'http://www.test.com', + no_proxy: 'xyz.com' + } + } + + var req = install.test.download(gyp, {}, url) + + t.equal(req.opts.proxy, undefined) + t.equal(req.opts.uri, url) + +})