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

agent: Fix NO_PROXY not respected for HTTPS urls #4309

Merged
merged 3 commits into from
Jun 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/network/lib/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ class HttpsAgent extends https.Agent {
if (process.env.HTTPS_PROXY) {
const proxy = getProxyForUrl(options.href)

if (typeof proxy === "string") {
if (proxy) {
options.proxy = <string>proxy

return this.createUpstreamProxyConnection(<RequestOptionsWithProxy>options, cb)
Expand Down
87 changes: 73 additions & 14 deletions packages/network/test/unit/agent_spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import Bluebird from 'bluebird'
import chai from 'chai'
import { EventEmitter } from 'events'
import http from 'http'
import https from 'https'
import net from 'net'
Expand All @@ -26,12 +25,11 @@ const HTTPS_PORT = 31443

describe('lib/agent', function() {
beforeEach(function() {
this.oldEnv = Object.assign({}, process.env)
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
})

afterEach(function() {
process.env = this.oldEnv
process.env.NO_PROXY = process.env.HTTP_PROXY = process.env.HTTPS_PROXY = ''
sinon.restore()
})

Expand Down Expand Up @@ -207,8 +205,40 @@ describe('lib/agent', function() {
})

context('HttpsAgent', function() {
beforeEach(function() {
this.agent = new CombinedAgent()

this.request = request.defaults({
agent: <any>this.agent,
proxy: null
})
})

it("#createUpstreamProxyConnection does not go to proxy if domain in NO_PROXY", function () {
const spy = sinon.spy(this.agent.httpsAgent, 'createUpstreamProxyConnection')

process.env.HTTP_PROXY = process.env.HTTPS_PROXY = 'http://0.0.0.0:0'
process.env.NO_PROXY = 'mtgox.info,example.com,homestarrunner.com,'

return this.request({
url: 'https://example.com/',
})
.then(() => {
expect(spy).to.not.be.called

return this.request({
url: 'https://example.org/'
})
.then(() => {
throw new Error('should not be able to connect')
})
.catch({ message: 'Error: A connection to the upstream proxy could not be established: connect ECONNREFUSED 0.0.0.0'}, () => {
expect(spy).to.be.calledOnce
})
})
})

it("#createUpstreamProxyConnection calls to super for caching, TLS-ifying", function() {
const combinedAgent = new CombinedAgent()
const spy = sinon.spy(https.Agent.prototype, 'createConnection')

const proxy = new DebuggingProxy()
Expand All @@ -219,26 +249,22 @@ describe('lib/agent', function() {

return proxy.start(proxyPort)
.then(() => {
return request({
return this.request({
url: `https://localhost:${HTTPS_PORT}/get`,
agent: <any>combinedAgent,
proxy: null
})
})
.then(() => {
const options = spy.getCall(0).args[0]
const session = combinedAgent.httpsAgent._sessionCache.map[options._agentKey]
const session = this.agent.httpsAgent._sessionCache.map[options._agentKey]
expect(spy).to.be.calledOnce
expect(combinedAgent.httpsAgent._sessionCache.list).to.have.length(1)
expect(this.agent.httpsAgent._sessionCache.list).to.have.length(1)
expect(session).to.not.be.undefined

return proxy.stop()
})
})

it("#createUpstreamProxyConnection throws when connection is accepted then closed", function() {
const combinedAgent = new CombinedAgent()

const proxy = Bluebird.promisifyAll(
net.createServer((socket) => {
socket.end()
Expand All @@ -252,10 +278,8 @@ describe('lib/agent', function() {

return proxy.listenAsync(proxyPort)
.then(() => {
return request({
return this.request({
url: `https://localhost:${HTTPS_PORT}/get`,
agent: <any>combinedAgent,
proxy: null
})
})
.then(() => {
Expand All @@ -268,6 +292,41 @@ describe('lib/agent', function() {
})
})
})

context('HttpAgent', function() {
beforeEach(function() {
this.agent = new CombinedAgent()

this.request = request.defaults({
agent: <any>this.agent,
proxy: null
})
})

it("#createSocket does not go to proxy if domain in NO_PROXY", function () {
const spy = sinon.spy(this.agent.httpAgent, '_createProxiedSocket')

process.env.HTTP_PROXY = process.env.HTTPS_PROXY = 'http://0.0.0.0:0'
process.env.NO_PROXY = 'mtgox.info,example.com,homestarrunner.com,'

return this.request({
url: 'http://example.com/',
})
.then(() => {
expect(spy).to.not.be.called

return this.request({
url: 'http://example.org/'
})
.then(() => {
throw new Error('should not be able to connect')
})
.catch({ message: 'Error: connect ECONNREFUSED 0.0.0.0'}, () => {
expect(spy).to.be.calledOnce
})
})
})
})
})

context(".buildConnectReqHead", function() {
Expand Down