• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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