1 2/** 3 * Module dependencies. 4 */ 5 6var fs = require('fs'); 7var url = require('url'); 8var http = require('http'); 9var https = require('https'); 10var assert = require('assert'); 11var Proxy = require('proxy'); 12var HttpProxyAgent = require('../'); 13 14describe('HttpProxyAgent', function () { 15 16 var server; 17 var serverPort; 18 19 var proxy; 20 var proxyPort; 21 22 var sslProxy; 23 var sslProxyPort; 24 25 before(function (done) { 26 // setup HTTP proxy server 27 proxy = Proxy(); 28 proxy.listen(function () { 29 proxyPort = proxy.address().port; 30 done(); 31 }); 32 }); 33 34 before(function (done) { 35 // setup target HTTP server 36 server = http.createServer(); 37 server.listen(function () { 38 serverPort = server.address().port; 39 done(); 40 }); 41 }); 42 43 before(function (done) { 44 // setup SSL HTTP proxy server 45 var options = { 46 key: fs.readFileSync(__dirname + '/ssl-cert-snakeoil.key'), 47 cert: fs.readFileSync(__dirname + '/ssl-cert-snakeoil.pem') 48 }; 49 sslProxy = Proxy(https.createServer(options)); 50 sslProxy.listen(function () { 51 sslProxyPort = sslProxy.address().port; 52 done(); 53 }); 54 }); 55 56 // shut down test HTTP server 57 after(function (done) { 58 proxy.once('close', function () { done(); }); 59 proxy.close(); 60 }); 61 62 after(function (done) { 63 server.once('close', function () { done(); }); 64 server.close(); 65 }); 66 67 after(function (done) { 68 sslProxy.once('close', function () { done(); }); 69 sslProxy.close(); 70 }); 71 72 describe('constructor', function () { 73 it('should throw an Error if no "proxy" argument is given', function () { 74 assert.throws(function () { 75 new HttpProxyAgent(); 76 }); 77 }); 78 it('should accept a "string" proxy argument', function () { 79 var agent = new HttpProxyAgent('http://127.0.0.1:' + proxyPort); 80 assert.equal('127.0.0.1', agent.proxy.host); 81 assert.equal(proxyPort, agent.proxy.port); 82 }); 83 it('should accept a `url.parse()` result object argument', function () { 84 var opts = url.parse('http://127.0.0.1:' + proxyPort); 85 var agent = new HttpProxyAgent(opts); 86 assert.equal('127.0.0.1', agent.proxy.host); 87 assert.equal(proxyPort, agent.proxy.port); 88 }); 89 describe('secureProxy', function () { 90 it('should default to `false`', function () { 91 var agent = new HttpProxyAgent({ port: proxyPort }); 92 assert.equal(false, agent.secureProxy); 93 }); 94 it('should be `false` when "http:" protocol is used', function () { 95 var agent = new HttpProxyAgent({ port: proxyPort, protocol: 'http:' }); 96 assert.equal(false, agent.secureProxy); 97 }); 98 it('should be `true` when "https:" protocol is used', function () { 99 var agent = new HttpProxyAgent({ port: proxyPort, protocol: 'https:' }); 100 assert.equal(true, agent.secureProxy); 101 }); 102 it('should be `true` when "https" protocol is used', function () { 103 var agent = new HttpProxyAgent({ port: proxyPort, protocol: 'https' }); 104 assert.equal(true, agent.secureProxy); 105 }); 106 }); 107 }); 108 109 describe('"http" module', function () { 110 it('should work over an HTTP proxy', function (done) { 111 // set HTTP "request" event handler for this test 112 server.once('request', function (req, res) { 113 res.end(JSON.stringify(req.headers)); 114 }); 115 116 var proxy = process.env.HTTP_PROXY || process.env.http_proxy || 'http://127.0.0.1:' + proxyPort; 117 var agent = new HttpProxyAgent(proxy); 118 119 var opts = url.parse('http://127.0.0.1:' + serverPort); 120 opts.agent = agent; 121 122 http.get(opts, function (res) { 123 var data = ''; 124 res.setEncoding('utf8'); 125 res.on('data', function (b) { 126 data += b; 127 }); 128 res.on('end', function () { 129 data = JSON.parse(data); 130 assert.equal('127.0.0.1:' + serverPort, data.host); 131 assert('via' in data); 132 done(); 133 }); 134 }); 135 }); 136 it('should work over an HTTPS proxy', function (done) { 137 // set HTTP "request" event handler for this test 138 server.once('request', function (req, res) { 139 res.end(JSON.stringify(req.headers)); 140 }); 141 142 var proxy = process.env.HTTPS_PROXY || process.env.https_proxy || 'https://127.0.0.1:' + sslProxyPort; 143 proxy = url.parse(proxy); 144 proxy.rejectUnauthorized = false; 145 var agent = new HttpProxyAgent(proxy); 146 assert.equal(true, agent.secureProxy); 147 148 var opts = url.parse('http://127.0.0.1:' + serverPort); 149 opts.agent = agent; 150 151 http.get(opts, function (res) { 152 var data = ''; 153 res.setEncoding('utf8'); 154 res.on('data', function (b) { 155 data += b; 156 }); 157 res.on('end', function () { 158 data = JSON.parse(data); 159 assert.equal('127.0.0.1:' + serverPort, data.host); 160 assert('via' in data); 161 done(); 162 }); 163 }); 164 }); 165 it('should proxy the query string of the request path', function (done) { 166 // set HTTP "request" event handler for this test 167 server.once('request', function (req, res) { 168 res.end(JSON.stringify({ 169 url: req.url 170 })); 171 }); 172 173 var proxy = process.env.HTTP_PROXY || process.env.http_proxy || 'http://127.0.0.1:' + proxyPort; 174 var agent = new HttpProxyAgent(proxy); 175 176 var opts = url.parse('http://127.0.0.1:' + serverPort + '/test?foo=bar&1=2'); 177 opts.agent = agent; 178 179 http.get(opts, function (res) { 180 var data = ''; 181 res.setEncoding('utf8'); 182 res.on('data', function (b) { 183 data += b; 184 }); 185 res.on('end', function () { 186 data = JSON.parse(data); 187 assert.equal('/test?foo=bar&1=2', data.url); 188 done(); 189 }); 190 }); 191 }); 192 it('should receive the 407 authorization code on the `http.ClientResponse`', function (done) { 193 // set a proxy authentication function for this test 194 proxy.authenticate = function (req, fn) { 195 // reject all requests 196 fn(null, false); 197 }; 198 199 var proxyUri = process.env.HTTP_PROXY || process.env.http_proxy || 'http://127.0.0.1:' + proxyPort; 200 var agent = new HttpProxyAgent(proxyUri); 201 202 var opts = {}; 203 // `host` and `port` don't really matter since the proxy will reject anyways 204 opts.host = '127.0.0.1'; 205 opts.port = 80; 206 opts.agent = agent; 207 208 http.get(opts, function (res) { 209 assert.equal(407, res.statusCode); 210 assert('proxy-authenticate' in res.headers); 211 delete proxy.authenticate; 212 done(); 213 }); 214 }); 215 it('should send the "Proxy-Authorization" request header', function (done) { 216 // set a proxy authentication function for this test 217 proxy.authenticate = function (req, fn) { 218 // username:password is "foo:bar" 219 fn(null, req.headers['proxy-authorization'] == 'Basic Zm9vOmJhcg=='); 220 }; 221 222 // set HTTP "request" event handler for this test 223 server.once('request', function (req, res) { 224 res.end(JSON.stringify(req.headers)); 225 }); 226 227 var proxyUri = process.env.HTTP_PROXY || process.env.http_proxy || 'http://127.0.0.1:' + proxyPort; 228 var proxyOpts = url.parse(proxyUri); 229 proxyOpts.auth = 'foo:bar'; 230 var agent = new HttpProxyAgent(proxyOpts); 231 232 var opts = url.parse('http://127.0.0.1:' + serverPort); 233 opts.agent = agent; 234 235 http.get(opts, function (res) { 236 var data = ''; 237 res.setEncoding('utf8'); 238 res.on('data', function (b) { 239 data += b; 240 }); 241 res.on('end', function () { 242 data = JSON.parse(data); 243 assert.equal('127.0.0.1:' + serverPort, data.host); 244 assert('via' in data); 245 delete proxy.authenticate; 246 done(); 247 }); 248 }); 249 }); 250 it('should emit an "error" event on the `http.ClientRequest` if the proxy does not exist', function (done) { 251 // port 4 is a reserved, but "unassigned" port 252 var proxyUri = 'http://127.0.0.1:4'; 253 var agent = new HttpProxyAgent(proxyUri); 254 255 var opts = url.parse('http://nodejs.org'); 256 opts.agent = agent; 257 258 var req = http.get(opts); 259 req.once('error', function (err) { 260 assert.equal('ECONNREFUSED', err.code); 261 req.abort(); 262 done(); 263 }); 264 }); 265 it('should work after the first tick of the `http.ClientRequest` instance', function (done) { 266 // set HTTP "request" event handler for this test 267 server.once('request', function (req, res) { 268 res.end(JSON.stringify(req.url)); 269 }); 270 271 var proxy = process.env.HTTP_PROXY || process.env.http_proxy || 'http://127.0.0.1:' + proxyPort; 272 var agent = new HttpProxyAgent(proxy); 273 274 var opts = url.parse('http://127.0.0.1:' + serverPort + '/test'); 275 opts.agent = agent; 276 277 // defer the "connect()" function logic, since calling .end() before the 278 // "socket" event can cause weirdness since the HTTP header will have been 279 // cached and the HttpProxyAgent `req.path` patches won't be respected 280 var callback = agent.callback; 281 agent.callback = function (req, opts, fn) { 282 setTimeout(function () { 283 agent.callback = callback; 284 agent.callback(req, opts, fn); 285 }, 10); 286 }; 287 288 http.get(opts, function (res) { 289 var data = ''; 290 res.setEncoding('utf8'); 291 res.on('data', function (b) { 292 data += b; 293 }); 294 res.on('end', function () { 295 data = JSON.parse(data); 296 assert.equal('/test', data); 297 done(); 298 }); 299 }); 300 }); 301 }); 302 303}); 304