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

Add the noProxy option. Will be usefull for yarn to support the noProxy in the .npmrc #3158

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,7 @@ The first argument can be either a `url` or an `options` object. The only requir

- `localAddress` - local interface to bind for network connections.
- `proxy` - an HTTP proxy to be used. Supports proxy Auth with Basic Auth, identical to support for the `url` parameter (by embedding the auth info in the `uri`)
- `noProxy` - no_proxy option
- `strictSSL` - if `true`, requires SSL certificates be valid. **Note:** to use your own certificate authority, you need to specify an agent that was created with that CA as an option.
- `tunnel` - controls the behavior of
[HTTP `CONNECT` tunneling](https://en.wikipedia.org/wiki/HTTP_tunnel#HTTP_CONNECT_tunneling)
Expand Down
47 changes: 3 additions & 44 deletions lib/getProxyFromURI.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,6 @@
'use strict'

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 port = uri.port || (uri.protocol === 'https:' ? '443' : '80')
var hostname = formatHostname(uri.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
})
}
var uriInNoProxy = require('./uriInNoProxy')

function getProxyFromURI (uri) {
// Decide the proper request proxy to use based on the request URI object and the
Expand All @@ -44,15 +9,9 @@ function getProxyFromURI (uri) {

var noProxy = process.env.NO_PROXY || process.env.no_proxy || ''

// if the noProxy is a wildcard then return null

if (noProxy === '*') {
return null
}

// if the noProxy is not empty and the uri is found return null
// if the uri uri is found in the noProxy return null

if (noProxy !== '' && uriInNoProxy(uri, noProxy)) {
if (uriInNoProxy(uri, noProxy)) {
return null
}

Expand Down
52 changes: 52 additions & 0 deletions lib/uriInNoProxy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
'use strict'

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) {
// if noProxy is empty, null of undefined, return false

if (!noProxy) {
return false
}

// if the noProxy is a wildcard then return true

if (noProxy === '*') {
return true
}

var port = uri.port || (uri.protocol === 'https:' ? '443' : '80')
var hostname = formatHostname(uri.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
})
}

module.exports = uriInNoProxy
4 changes: 4 additions & 0 deletions request.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ var isTypedArray = require('is-typedarray').strict
var helpers = require('./lib/helpers')
var cookies = require('./lib/cookies')
var getProxyFromURI = require('./lib/getProxyFromURI')
var uriInNoProxy = require('./lib/uriInNoProxy')
var Querystring = require('./lib/querystring').Querystring
var Har = require('./lib/har').Har
var Auth = require('./lib/auth').Auth
Expand Down Expand Up @@ -275,6 +276,9 @@ Request.prototype.init = function (options) {

if (!self.hasOwnProperty('proxy')) {
self.proxy = getProxyFromURI(self.uri)
} else if (uriInNoProxy(self.uri, self.noProxy)) {
// noProxy option only operate over the proxy option, not over env vars
self.proxy = null
}

self.tunnel = self._tunnel.isEnabled()
Expand Down
10 changes: 10 additions & 0 deletions tests/test-proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,16 @@ function addTests () {
}
}, true)

runTest('noProxy used with explicit proxy passed', {
proxy: s.url,
noProxy: '*'
}, false)

runTest('noProxy used with explicit proxy passed', {
proxy: s.url,
noProxy: 'google.com'
}, false)

// misc

// this fails if the check 'isMatchedAt > -1' in lib/getProxyFromURI.js is
Expand Down