Skip to content
This repository was archived by the owner on May 5, 2023. It is now read-only.

Commit 787ede0

Browse files
jackjocrossTooTallNate
authored andcommitted
Add support for env vars by default (#11) (#16)
* Add support for env vars by default (#11) * Use global agents for no proxy
1 parent c007ea1 commit 787ede0

File tree

3 files changed

+134
-41
lines changed

3 files changed

+134
-41
lines changed

index.js

Lines changed: 83 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ var LRU = require('lru-cache');
99
var Agent = require('agent-base');
1010
var inherits = require('util').inherits;
1111
var debug = require('debug')('proxy-agent');
12+
var getProxyForUrl = require('proxy-from-env').getProxyForUrl;
1213

14+
var http = require('http');
15+
var https = require('https');
1316
var PacProxyAgent = require('pac-proxy-agent');
1417
var HttpProxyAgent = require('http-proxy-agent');
1518
var HttpsProxyAgent = require('https-proxy-agent');
@@ -53,7 +56,17 @@ PacProxyAgent.protocols.forEach(function (protocol) {
5356
exports.proxies['pac+' + protocol] = PacProxyAgent;
5457
});
5558

56-
function httpOrHttpsProxy (opts, secureEndpoint) {
59+
function httpOrHttps(opts, secureEndpoint) {
60+
if (secureEndpoint) {
61+
// HTTPS
62+
return https.globalAgent;
63+
} else {
64+
// HTTP
65+
return http.globalAgent;
66+
}
67+
}
68+
69+
function httpOrHttpsProxy(opts, secureEndpoint) {
5770
if (secureEndpoint) {
5871
// HTTPS
5972
return new HttpsProxyAgent(opts);
@@ -63,25 +76,16 @@ function httpOrHttpsProxy (opts, secureEndpoint) {
6376
}
6477
}
6578

66-
/**
67-
* Attempts to get an `http.Agent` instance based off of the given proxy URI
68-
* information, and the `secure` flag.
69-
*
70-
* An LRU cache is used, to prevent unnecessary creation of proxy
71-
* `http.Agent` instances.
72-
*
73-
* @param {String} uri proxy url
74-
* @param {Boolean} secure true if this is for an HTTPS request, false for HTTP
75-
* @return {http.Agent}
76-
* @api public
77-
*/
79+
function mapOptsToProxy(opts) {
80+
// NO_PROXY case
81+
if (!opts) {
82+
return {
83+
uri: 'no proxy',
84+
fn: httpOrHttps
85+
};
86+
}
7887

79-
function ProxyAgent (opts) {
80-
if (!(this instanceof ProxyAgent)) return new ProxyAgent(opts);
8188
if ('string' == typeof opts) opts = url.parse(opts);
82-
if (!opts) throw new TypeError('an HTTP(S) proxy server `host` and `protocol` must be specified!');
83-
debug('creating new ProxyAgent instance: %o', opts);
84-
Agent.call(this, connect);
8589

8690
var proxies;
8791
if (opts.proxies) {
@@ -108,41 +112,87 @@ function ProxyAgent (opts) {
108112
throw new TypeError('unsupported proxy protocol: "' + protocol + '"');
109113
}
110114

111-
this.proxy = opts;
112115
// format the proxy info back into a URI, since an opts object
113-
// could have been passed in originally. This generated URI is
114-
// used as part of the "key" for the LRU cache
115-
this.proxyUri = url.format({
116-
protocol: protocol + ':',
117-
slashes: true,
118-
auth:opts.auth,
119-
hostname: opts.hostname || opts.host,
120-
port: opts.port
121-
});
122-
this.proxyFn = proxyFn;
116+
// could have been passed in originally. This generated URI is used
117+
// as part of the "key" for the LRU cache
118+
return {
119+
opts: opts,
120+
uri: url.format({
121+
protocol: protocol + ':',
122+
slashes: true,
123+
auth: opts.auth,
124+
hostname: opts.hostname || opts.host,
125+
port: opts.port
126+
}),
127+
fn: proxyFn,
128+
}
129+
}
130+
131+
/**
132+
* Attempts to get an `http.Agent` instance based off of the given proxy URI
133+
* information, and the `secure` flag.
134+
*
135+
* An LRU cache is used, to prevent unnecessary creation of proxy
136+
* `http.Agent` instances.
137+
*
138+
* @param {String} uri proxy url
139+
* @param {Boolean} secure true if this is for an HTTPS request, false for HTTP
140+
* @return {http.Agent}
141+
* @api public
142+
*/
143+
144+
function ProxyAgent (opts) {
145+
if (!(this instanceof ProxyAgent)) return new ProxyAgent(opts);
146+
debug('creating new ProxyAgent instance: %o', opts);
147+
Agent.call(this, connect);
148+
149+
if (opts) {
150+
var proxy = mapOptsToProxy(opts);
151+
this.proxy = proxy.opts;
152+
this.proxyUri = proxy.uri;
153+
this.proxyFn = proxy.fn;
154+
}
123155
}
124156
inherits(ProxyAgent, Agent);
125157

126158
/**
127159
*
128160
*/
129161

130-
function connect (req, opts) {
162+
function connect (req, opts, fn) {
163+
var proxyOpts = this.proxy;
164+
var proxyUri = this.proxyUri;
165+
var proxyFn = this.proxyFn;
166+
167+
// if we did not instantiate with a proxy, set one per request
168+
if (!proxyOpts) {
169+
var urlOpts = getProxyForUrl(opts);
170+
var proxy = mapOptsToProxy(urlOpts, opts);
171+
proxyOpts = proxy.opts;
172+
proxyUri = proxy.uri;
173+
proxyFn = proxy.fn;
174+
}
175+
131176
// create the "key" for the LRU cache
132-
var key = this.proxyUri;
177+
var key = proxyUri;
133178
if (opts.secureEndpoint) key += ' secure';
134179

135180
// attempt to get a cached `http.Agent` instance first
136181
var agent = exports.cache.get(key);
137182
if (!agent) {
138183
// get an `http.Agent` instance from protocol-specific agent function
139-
agent = this.proxyFn(this.proxy, opts.secureEndpoint);
184+
agent = proxyFn(proxyOpts, opts.secureEndpoint);
140185
if (agent) {
141186
exports.cache.set(key, agent);
142187
}
143188
} else {
144189
debug('cache hit with key: %o', key);
145190
}
146191

147-
return agent;
192+
if (!proxyOpts) {
193+
agent.addRequest(req, opts);
194+
} else {
195+
// XXX: agent.callback() is an agent-base-ism
196+
agent.callback(req, opts, fn);
197+
}
148198
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"https-proxy-agent": "^1.0.0",
3333
"lru-cache": "^2.6.5",
3434
"pac-proxy-agent": "^2.0.0",
35+
"proxy-from-env": "^1.0.0",
3536
"socks-proxy-agent": "^3.0.0"
3637
},
3738
"devDependencies": {

test/test.js

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,6 @@ describe('ProxyAgent', function () {
110110
});
111111

112112
describe('constructor', function () {
113-
it('should throw a TypeError if no "proxy" argument is given', function () {
114-
assert.throws(function () {
115-
new ProxyAgent();
116-
}, TypeError);
117-
});
118113
it('should throw a TypeError if no "protocol" is given', function () {
119114
assert.throws(function () {
120115
ProxyAgent({ host: 'foo.com', port: 3128 });
@@ -163,6 +158,56 @@ describe('ProxyAgent', function () {
163158
});
164159
});
165160

161+
describe('over "http" proxy from env', function () {
162+
it('should work', function (done) {
163+
httpServer.once('request', function (req, res) {
164+
res.end(JSON.stringify(req.headers));
165+
});
166+
167+
process.env.HTTP_PROXY = 'http://127.0.0.1:' + proxyPort;
168+
var agent = new ProxyAgent();
169+
170+
var opts = url.parse('http://127.0.0.1:' + httpPort + '/test');
171+
opts.agent = agent;
172+
173+
var req = http.get(opts, function (res) {
174+
toBuffer(res, function (err, buf) {
175+
if (err) return done(err);
176+
var data = JSON.parse(buf.toString('utf8'));
177+
assert.equal('127.0.0.1:' + httpPort, data.host);
178+
assert('via' in data);
179+
done();
180+
});
181+
});
182+
req.once('error', done);
183+
});
184+
});
185+
186+
describe('with no proxy from env', function () {
187+
it('should work', function (done) {
188+
httpServer.once('request', function (req, res) {
189+
res.end(JSON.stringify(req.headers));
190+
});
191+
192+
process.env.NO_PROXY = '*';
193+
var agent = new ProxyAgent();
194+
195+
var opts = url.parse('http://127.0.0.1:' + httpPort + '/test');
196+
opts.agent = agent;
197+
198+
var req = http.get(opts, function (res) {
199+
toBuffer(res, function (err, buf) {
200+
if (err) return done(err);
201+
var data = JSON.parse(buf.toString('utf8'));
202+
assert.equal('127.0.0.1:' + httpPort, data.host);
203+
assert(!('via' in data));
204+
done();
205+
});
206+
});
207+
req.once('error', done);
208+
});
209+
});
210+
166211
describe('over "https" proxy', function () {
167212
it('should work', function (done) {
168213
httpServer.once('request', function (req, res) {
@@ -213,10 +258,8 @@ describe('ProxyAgent', function () {
213258
req.once('error', done);
214259
});
215260
});
216-
217261
});
218262

219-
220263
describe('"https" module', function () {
221264
describe('over "http" proxy', function () {
222265
it('should work', function (done) {
@@ -303,5 +346,4 @@ describe('ProxyAgent', function () {
303346
});
304347
});
305348
});
306-
307349
});

0 commit comments

Comments
 (0)