pac-proxy-agent
Advanced tools
Comparing version 0.2.0 to 1.0.0
1.0.0 / 2015-07-10 | ||
================== | ||
* package: update "extend" to v3 | ||
* refactor to use proxy agent classes directly | ||
* upgrade to `agent-base` v2 API | ||
* use "stream-to-buffer" | ||
* use %o formatter for debug() calls | ||
* package: update "get-uri" to v1 | ||
* package: update "mocha" to v2 | ||
* travis: test node v0.8, v0.10, and v0.12 | ||
* test: add initial test cases | ||
* test: add basic "https" module tests | ||
* README: use SVG for Travis-CI badge | ||
0.2.0 / 2014-11-10 | ||
================== | ||
* index: add reference link for Chrome's "HTTPS" support | ||
* index: throw an error for unknown proxy types (#2, @michaelansel) | ||
* index: support HTTPS proxies (#2, @michaelansel) | ||
* package: alloy any "debug" v2 | ||
* index: add reference link for Chrome's "HTTPS" support | ||
* index: throw an error for unknown proxy types (#2, @michaelansel) | ||
* index: support HTTPS proxies (#2, @michaelansel) | ||
* package: allow any "debug" v2 | ||
@@ -10,0 +25,0 @@ 0.1.2 / 2014-04-04 |
84
index.js
/** | ||
* Module exports. | ||
* | ||
* XXX: exports going first here so that the circular require with | ||
* `proxy-agent` doesn't result in an empty `exports` object for | ||
* this module when `proxy-agent` requires us. | ||
*/ | ||
@@ -34,5 +30,7 @@ | ||
var Agent = require('agent-base'); | ||
var ProxyAgent = require('proxy-agent'); | ||
var HttpProxyAgent = require('http-proxy-agent'); | ||
var HttpsProxyAgent = require('https-proxy-agent'); | ||
var SocksProxyAgent = require('socks-proxy-agent'); | ||
var PacResolver = require('pac-resolver'); | ||
var toArray = require('stream-to-array'); | ||
var toBuffer = require('stream-to-buffer'); | ||
var inherits = require('util').inherits; | ||
@@ -56,20 +54,27 @@ var debug = require('debug')('pac-proxy-agent'); | ||
function PacProxyAgent (opts) { | ||
if (!(this instanceof PacProxyAgent)) return new PacProxyAgent(opts); | ||
var uri; | ||
if ('string' == typeof opts) { | ||
uri = opts; | ||
} else { | ||
if (opts.path && !opts.pathname) { | ||
opts.pathname = opts.path; | ||
function PacProxyAgent (uri, opts) { | ||
if (!(this instanceof PacProxyAgent)) return new PacProxyAgent(uri, opts); | ||
// was an options object passed in first? | ||
if ('object' === typeof uri) { | ||
opts = uri; | ||
// result of a url.parse() call? | ||
if (opts.href) { | ||
if (opts.path && !opts.pathname) { | ||
opts.pathname = opts.path; | ||
} | ||
opts.slashes = true; | ||
uri = format(opts); | ||
} else { | ||
uri = opts.uri; | ||
} | ||
opts.slashes = true; | ||
uri = format(opts); | ||
} | ||
if (!uri) throw new Error('a PAC file location must be specified!'); | ||
if (!opts) opts = {}; | ||
if (!uri) throw new Error('a PAC file URI must be specified!'); | ||
debug('creating PacProxyAgent with URI %o and options %o', uri, opts); | ||
Agent.call(this, connect); | ||
// if `true`, then connect to the destination endpoint over TLS, defaults to `false` | ||
this.secureEndpoint = Boolean(opts.secureEndpoint); | ||
// strip the "pac+" prefix | ||
@@ -80,2 +85,4 @@ this.uri = uri.replace(/^pac\+/i, ''); | ||
this.proxy = opts; | ||
this.cache = this._resolver = null; | ||
@@ -143,3 +150,3 @@ } | ||
PacProxyAgent.prototype.loadPacFile = function (fn) { | ||
debug('loading PAC file: %j', this.uri); | ||
debug('loading PAC file: %o', this.uri); | ||
var self = this; | ||
@@ -158,9 +165,8 @@ | ||
self.cache = rs; | ||
toArray(rs, onarray); | ||
toBuffer(rs, onbuffer); | ||
} | ||
function onarray (err, arr) { | ||
function onbuffer (err, buf) { | ||
if (err) return fn(err); | ||
var buf = Buffer.concat(arr); | ||
debug('read %d byte PAC file from URI', buf.length); | ||
debug('read %o byte PAC file from URI', buf.length); | ||
fn(null, buf.toString('utf8')); | ||
@@ -180,2 +186,3 @@ } | ||
var self = this; | ||
var secure = Boolean(opts.secureEndpoint); | ||
@@ -191,3 +198,2 @@ // first we need get a generated FindProxyForURL() function, | ||
// calculate the `url` parameter | ||
var secure = self.secureEndpoint; | ||
var defaultPort = secure ? 443 : 80; | ||
@@ -217,3 +223,3 @@ var path = req.path; | ||
debug('url: %j, host: %j', url, host); | ||
debug('url: %o, host: %o', url, host); | ||
FindProxyForURL(url, host, onproxy); | ||
@@ -229,7 +235,7 @@ } | ||
var proxies = String(proxy).trim().split(/\b\s*;\s*?\b/); | ||
var proxies = String(proxy).trim().split(/\s*;\s*/g).filter(Boolean); | ||
// XXX: right now, only the first proxy specified will be used | ||
var first = proxies[0]; | ||
debug('using proxy: "%s"', first); | ||
debug('using proxy: %o', first); | ||
@@ -239,3 +245,2 @@ var agent; | ||
var type = parts[0]; | ||
var secure = self.secureEndpoint; | ||
@@ -251,12 +256,15 @@ if ('DIRECT' == type) { | ||
return fn(null, socket); | ||
} else if ('PROXY' == type) { | ||
// use an HTTP proxy | ||
agent = ProxyAgent('http://' + parts[1], secure); | ||
} else if ('HTTPS' == type) { | ||
// use an HTTPS proxy | ||
// http://dev.chromium.org/developers/design-documents/secure-web-proxy | ||
agent = ProxyAgent('https://' + parts[1], secure); | ||
} else if ('SOCKS' == type) { | ||
// use a SOCKS proxy | ||
agent = ProxyAgent('socks://' + parts[1], secure); | ||
agent = new SocksProxyAgent('socks://' + parts[1]); | ||
} else if ('PROXY' == type || 'HTTPS' == type) { | ||
// use an HTTP or HTTPS proxy | ||
// http://dev.chromium.org/developers/design-documents/secure-web-proxy | ||
var proxyURL = ('HTTPS' === type ? 'https' : 'http') + '://' + parts[1]; | ||
var proxy = extend({}, self.proxy, parse(proxyURL)); | ||
if (secure) { | ||
agent = new HttpsProxyAgent(proxy); | ||
} else { | ||
agent = new HttpProxyAgent(proxy); | ||
} | ||
} else { | ||
@@ -263,0 +271,0 @@ throw new Error('Unknown proxy type: ' + type); |
{ | ||
"name": "pac-proxy-agent", | ||
"version": "0.2.0", | ||
"version": "1.0.0", | ||
"description": "A PAC file proxy `http.Agent` implementation for HTTP", | ||
@@ -30,13 +30,17 @@ "main": "index.js", | ||
"dependencies": { | ||
"agent-base": "~1.0.1", | ||
"extend": "~1.2.1", | ||
"agent-base": "2", | ||
"debug": "2", | ||
"extend": "3", | ||
"get-uri": "1", | ||
"http-proxy-agent": "1", | ||
"https-proxy-agent": "1", | ||
"pac-resolver": "~1.2.1", | ||
"proxy-agent": "1", | ||
"get-uri": "~0.1.0", | ||
"stream-to-array": "~1.0.0", | ||
"debug": "2" | ||
"socks-proxy-agent": "2", | ||
"stream-to-buffer": "0.1.0" | ||
}, | ||
"devDependencies": { | ||
"mocha": "~1.16.2" | ||
"mocha": "2", | ||
"proxy": "0.2.3", | ||
"socksv5": "0.0.6" | ||
} | ||
} |
pac-proxy-agent | ||
=============== | ||
### A [PAC file][pac-wikipedia] proxy `http.Agent` implementation for HTTP and HTTPS | ||
[![Build Status](https://travis-ci.org/TooTallNate/node-pac-proxy-agent.png?branch=master)](https://travis-ci.org/TooTallNate/node-pac-proxy-agent) | ||
[![Build Status](https://travis-ci.org/TooTallNate/node-pac-proxy-agent.svg?branch=master)](https://travis-ci.org/TooTallNate/node-pac-proxy-agent) | ||
@@ -6,0 +6,0 @@ This module provides an `http.Agent` implementation that retreives the specified |
292
test/test.js
@@ -6,25 +6,303 @@ | ||
var fs = require('fs'); | ||
var url = require('url'); | ||
var http = require('http'); | ||
var https = require('https'); | ||
var assert = require('assert'); | ||
var toBuffer = require('stream-to-buffer'); | ||
var Proxy = require('proxy'); | ||
var socks = require('socksv5'); | ||
var PacProxyAgent = require('../'); | ||
describe('PacProxyAgent', function () { | ||
// target servers | ||
var httpServer, httpPort; | ||
var httpsServer, httpsPort; | ||
describe('"file" transport', function () { | ||
it('should work', function () { | ||
// proxy servers | ||
var socksServer, socksPort; | ||
var proxyServer, proxyPort; | ||
var proxyHttpsServer, proxyHttpsPort; | ||
before(function (done) { | ||
// setup target HTTP server | ||
httpServer = http.createServer(); | ||
httpServer.listen(function () { | ||
httpPort = httpServer.address().port; | ||
done(); | ||
}); | ||
}); | ||
describe('"http" transport', function () { | ||
it('should work', function () { | ||
before(function (done) { | ||
// setup target SSL HTTPS server | ||
var options = { | ||
key: fs.readFileSync(__dirname + '/ssl-cert-snakeoil.key'), | ||
cert: fs.readFileSync(__dirname + '/ssl-cert-snakeoil.pem') | ||
}; | ||
httpsServer = https.createServer(options); | ||
httpsServer.listen(function () { | ||
httpsPort = httpsServer.address().port; | ||
done(); | ||
}); | ||
}); | ||
describe('"https" transport', function () { | ||
it('should work', function () { | ||
before(function (done) { | ||
// setup SOCKS proxy server | ||
socksServer = socks.createServer(function(info, accept, deny) { | ||
accept(); | ||
}); | ||
socksServer.listen(function() { | ||
socksPort = socksServer.address().port; | ||
done(); | ||
}); | ||
socksServer.useAuth(socks.auth.None()); | ||
}); | ||
before(function (done) { | ||
// setup HTTP proxy server | ||
proxyServer = Proxy(); | ||
proxyServer.listen(function () { | ||
proxyPort = proxyServer.address().port; | ||
done(); | ||
}); | ||
}); | ||
before(function (done) { | ||
// setup SSL HTTPS proxy server | ||
var options = { | ||
key: fs.readFileSync(__dirname + '/ssl-cert-snakeoil.key'), | ||
cert: fs.readFileSync(__dirname + '/ssl-cert-snakeoil.pem') | ||
}; | ||
proxyHttpsServer = Proxy(https.createServer(options)); | ||
proxyHttpsServer.listen(function () { | ||
proxyHttpsPort = proxyHttpsServer.address().port; | ||
done(); | ||
}); | ||
}); | ||
after(function (done) { | ||
socksServer.once('close', function () { done(); }); | ||
socksServer.close(); | ||
}); | ||
after(function (done) { | ||
httpServer.once('close', function () { done(); }); | ||
httpServer.close(); | ||
}); | ||
after(function (done) { | ||
httpsServer.once('close', function () { done(); }); | ||
httpsServer.close(); | ||
}); | ||
after(function (done) { | ||
proxyServer.once('close', function () { done(); }); | ||
proxyServer.close(); | ||
}); | ||
after(function (done) { | ||
proxyHttpsServer.once('close', function () { done(); }); | ||
proxyHttpsServer.close(); | ||
}); | ||
describe('constructor', function () { | ||
it('should throw an Error if no "proxy" argument is given', function () { | ||
assert.throws(function () { | ||
new PacProxyAgent(); | ||
}); | ||
}); | ||
it('should accept a "string" proxy argument', function () { | ||
var agent = new PacProxyAgent('pac+ftp://example.com/proxy.pac'); | ||
assert.equal('ftp://example.com/proxy.pac', agent.uri); | ||
}); | ||
it('should accept a `url.parse()` result object argument', function () { | ||
var opts = url.parse('pac+ftp://example.com/proxy.pac'); | ||
var agent = new PacProxyAgent(opts); | ||
assert.equal('ftp://example.com/proxy.pac', agent.uri); | ||
}); | ||
it('should accept a `uri` on the options object', function () { | ||
var agent = new PacProxyAgent({ uri: 'pac+ftp://example.com/proxy.pac' }); | ||
assert.equal('ftp://example.com/proxy.pac', agent.uri); | ||
}); | ||
}); | ||
describe('"http" module', function () { | ||
it('should work over an HTTP proxy', function (done) { | ||
httpServer.once('request', function (req, res) { | ||
res.end(JSON.stringify(req.headers)); | ||
}); | ||
function FindProxyForURL(url, host) { | ||
return "PROXY 127.0.0.1:PORT;" | ||
} | ||
var uri = 'data:,' + encodeURIComponent(FindProxyForURL.toString().replace('PORT', proxyPort)); | ||
var agent = new PacProxyAgent(uri); | ||
var opts = url.parse('http://127.0.0.1:' + httpPort + '/test'); | ||
opts.agent = agent; | ||
var req = http.get(opts, function (res) { | ||
toBuffer(res, function (err, buf) { | ||
if (err) return done(err); | ||
var data = JSON.parse(buf.toString('utf8')); | ||
assert.equal('127.0.0.1:' + httpPort, data.host); | ||
assert('via' in data); | ||
done(); | ||
}); | ||
}); | ||
req.once('error', done); | ||
}); | ||
it('should work over an HTTPS proxy', function (done) { | ||
httpServer.once('request', function (req, res) { | ||
res.end(JSON.stringify(req.headers)); | ||
}); | ||
function FindProxyForURL(url, host) { | ||
return "HTTPS 127.0.0.1:PORT;" | ||
} | ||
var uri = 'data:,' + encodeURIComponent(FindProxyForURL.toString().replace('PORT', proxyHttpsPort)); | ||
var proxy = url.parse(uri); | ||
proxy.rejectUnauthorized = false; | ||
var agent = new PacProxyAgent(proxy); | ||
var opts = url.parse('http://127.0.0.1:' + httpPort + '/test'); | ||
opts.agent = agent; | ||
var req = http.get(opts, function (res) { | ||
toBuffer(res, function (err, buf) { | ||
if (err) return done(err); | ||
var data = JSON.parse(buf.toString('utf8')); | ||
assert.equal('127.0.0.1:' + httpPort, data.host); | ||
assert('via' in data); | ||
done(); | ||
}); | ||
}); | ||
req.once('error', done); | ||
}); | ||
it('should work over a SOCKS proxy', function (done) { | ||
httpServer.once('request', function (req, res) { | ||
res.end(JSON.stringify(req.headers)); | ||
}); | ||
function FindProxyForURL(url, host) { | ||
return "SOCKS 127.0.0.1:PORT;" | ||
} | ||
var uri = 'data:,' + encodeURIComponent(FindProxyForURL.toString().replace('PORT', socksPort)); | ||
var agent = new PacProxyAgent(uri); | ||
var opts = url.parse('http://127.0.0.1:' + httpPort + '/test'); | ||
opts.agent = agent; | ||
var req = http.get(opts, function (res) { | ||
toBuffer(res, function (err, buf) { | ||
if (err) return done(err); | ||
var data = JSON.parse(buf.toString('utf8')); | ||
assert.equal('127.0.0.1:' + httpPort, data.host); | ||
done(); | ||
}); | ||
}); | ||
req.once('error', done); | ||
}); | ||
}); | ||
describe('"https" module', function () { | ||
it('should work over an HTTP proxy', function (done) { | ||
httpsServer.once('request', function (req, res) { | ||
res.end(JSON.stringify(req.headers)); | ||
}); | ||
function FindProxyForURL(url, host) { | ||
return "PROXY 127.0.0.1:PORT;" | ||
} | ||
var uri = 'data:,' + encodeURIComponent(FindProxyForURL.toString().replace('PORT', proxyPort)); | ||
var agent = new PacProxyAgent(uri); | ||
var opts = url.parse('https://127.0.0.1:' + httpsPort + '/test'); | ||
opts.agent = agent; | ||
opts.rejectUnauthorized = false; | ||
var req = https.get(opts, function (res) { | ||
toBuffer(res, function (err, buf) { | ||
if (err) return done(err); | ||
var data = JSON.parse(buf.toString('utf8')); | ||
assert.equal('127.0.0.1:' + httpsPort, data.host); | ||
done(); | ||
}); | ||
}); | ||
req.once('error', done); | ||
}); | ||
it('should work over an HTTPS proxy', function (done) { | ||
var gotReq = false; | ||
httpsServer.once('request', function (req, res) { | ||
gotReq = true; | ||
res.end(JSON.stringify(req.headers)); | ||
}); | ||
function FindProxyForURL(url, host) { | ||
return "HTTPS 127.0.0.1:PORT;" | ||
} | ||
var uri = 'data:,' + encodeURIComponent(FindProxyForURL.toString().replace('PORT', proxyHttpsPort)); | ||
var agent = new PacProxyAgent(uri, { | ||
rejectUnauthorized: false | ||
}); | ||
var opts = url.parse('https://127.0.0.1:' + httpsPort + '/test'); | ||
opts.agent = agent; | ||
opts.rejectUnauthorized = false; | ||
var req = https.get(opts, function (res) { | ||
toBuffer(res, function (err, buf) { | ||
if (err) return done(err); | ||
var data = JSON.parse(buf.toString('utf8')); | ||
assert.equal('127.0.0.1:' + httpsPort, data.host); | ||
assert(gotReq); | ||
done(); | ||
}); | ||
}); | ||
req.once('error', done); | ||
}); | ||
it('should work over a SOCKS proxy', function (done) { | ||
var gotReq = false; | ||
httpsServer.once('request', function (req, res) { | ||
gotReq = true; | ||
res.end(JSON.stringify(req.headers)); | ||
}); | ||
function FindProxyForURL(url, host) { | ||
return "SOCKS 127.0.0.1:PORT;" | ||
} | ||
var uri = 'data:,' + encodeURIComponent(FindProxyForURL.toString().replace('PORT', socksPort)); | ||
var agent = new PacProxyAgent(uri); | ||
var opts = url.parse('https://127.0.0.1:' + httpsPort + '/test'); | ||
opts.agent = agent; | ||
opts.rejectUnauthorized = false; | ||
var req = https.get(opts, function (res) { | ||
toBuffer(res, function (err, buf) { | ||
if (err) return done(err); | ||
var data = JSON.parse(buf.toString('utf8')); | ||
assert.equal('127.0.0.1:' + httpsPort, data.host); | ||
assert(gotReq); | ||
done(); | ||
}); | ||
}); | ||
req.once('error', done); | ||
}); | ||
}); | ||
}); |
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
23363
9
476
0
9
3
1
6
+ Addedhttp-proxy-agent@1
+ Addedhttps-proxy-agent@1
+ Addedsocks-proxy-agent@2
+ Addedstream-to-buffer@0.1.0
+ Addedagent-base@2.1.1(transitive)
+ Addedget-uri@1.1.0(transitive)
+ Addedhttp-proxy-agent@1.0.0(transitive)
+ Addedhttps-proxy-agent@1.0.0(transitive)
+ Addedsemver@5.0.3(transitive)
+ Addedsocks-proxy-agent@2.1.1(transitive)
+ Addedstream-to@0.2.2(transitive)
+ Addedstream-to-buffer@0.1.0(transitive)
- Removedproxy-agent@1
- Removedstream-to-array@~1.0.0
- Removedagent-base@1.0.2(transitive)
- Removedextend@1.2.1(transitive)
- Removedget-uri@0.1.4(transitive)
- Removedhttp-proxy-agent@0.2.7(transitive)
- Removedhttps-proxy-agent@0.3.6(transitive)
- Removedlru-cache@2.5.2(transitive)
- Removedproxy-agent@1.1.1(transitive)
- Removedsocks-proxy-agent@1.0.2(transitive)
- Removedstream-to-array@1.0.0(transitive)
Updatedagent-base@2
Updatedextend@3
Updatedget-uri@1