var helpers = require('./helpers'), should = require('should'), sinon = require('sinon'), http = require('http'), needle = require('./../'); var port = 7707; var url = 'localhost:' + port; var nonexisting_host = 'awepfokawepofawe.com'; describe('proxy option', function() { var spy, opts; function send_request(opts, done) { if (spy) spy.restore(); spy = sinon.spy(http, 'request'); needle.get(url, opts, done); } ////////////////////// // proxy opts helpers function not_proxied(done) { return function(err, resp) { var path = spy.args[0][0].path; path.should.eql('/'); // not the full original URI spy.restore(); done(); } } function proxied(host, port, done) { return function(err, resp) { var path = spy.args[0][0].path; path.should.eql('http://' + url); // the full original URI var http_host = spy.args[0][0].host; if (http_host) http_host.should.eql(host); var http_port = spy.args[0][0].port; if (http_port) http_port.should.eql(port); spy.restore(); done(); } } ////////////////////// // auth helpers function get_auth(header) { var token = header.split(/\s+/).pop(); return token && Buffer.from(token, 'base64').toString().split(':'); } function no_proxy_auth(done) { return function(err, resp) { var headers = spy.args[0][0].headers; Object.keys(headers).should.not.containEql('proxy-authorization'); done(); } } function header_set(name, user, pass, done) { return function(err, resp) { var headers = spy.args[0][0].headers; var auth = get_auth(headers[name]); auth[0].should.eql(user); auth[1].should.eql(pass); done(); } } function proxy_auth_set(user, pass, done) { return header_set('proxy-authorization', user, pass, done); } function basic_auth_set(user, pass, done) { return header_set('authorization', user, pass, done); } after(function() { spy.restore(); }) describe('when null proxy is passed', function() { it('does not proxy', function(done) { send_request({ proxy: null }, not_proxied(done)) }) describe('but defaults has been set', function() { before(function() { needle.defaults({ proxy: 'foobar' }); }) after(function() { needle.defaults({ proxy: null }); }) it('tries to proxy anyway', function(done) { send_request({}, proxied('foobar', 80, done)) }) }) }) describe('when weird string is passed', function() { it('tries to proxy anyway', function(done) { send_request({ proxy: 'alfalfa' }, proxied('alfalfa', 80, done)) }) }) describe('when valid url is passed', function() { describe('without NO_PROXY env var set', function() { it('proxies request', function(done) { send_request({ proxy: nonexisting_host + ':123/done' }, proxied(nonexisting_host, '123', done)) }) it('does not set a Proxy-Authorization header', function(done) { send_request({ proxy: nonexisting_host + ':123/done' }, no_proxy_auth(done)); }) }) describe('with NO_PROXY env var set', function() { it('proxies request if matching host not found in list', function(done) { process.env.NO_PROXY = 'foo'; send_request({ proxy: nonexisting_host + ':123/done' }, proxied(nonexisting_host, '123', function() { delete process.env.NO_PROXY; done(); })) }) it('does not proxy request if matching host in list and just has a different port', function(done) { process.env.NO_PROXY = 'localhost'; send_request({ proxy: nonexisting_host + ':123/done' }, not_proxied(function() { delete process.env.NO_PROXY; done(); })) }) it('does not proxy if matching host found in list', function(done) { process.env.NO_PROXY = 'foo,' + url; send_request({ proxy: nonexisting_host + ':123/done' }, not_proxied(function() { delete process.env.NO_PROXY; done(); })) }) }) describe('and proxy url contains user:pass', function() { before(function() { opts = { proxy: 'http://mj:x@' + nonexisting_host + ':123/done' } }) it('proxies request', function(done) { send_request(opts, proxied(nonexisting_host, '123', done)) }) it('sets Proxy-Authorization header', function(done) { send_request(opts, proxy_auth_set('mj', 'x', done)); }) }) describe('and a proxy_user is passed', function() { before(function() { opts = { proxy: nonexisting_host + ':123', proxy_user: 'someone', proxy_pass: 'else' } }) it('proxies request', function(done) { send_request(opts, proxied(nonexisting_host, '123', done)) }) it('sets Proxy-Authorization header', function(done) { send_request(opts, proxy_auth_set('someone', 'else', done)); }) describe('and url also contains user:pass', function() { it('url user:pass wins', function(done) { var opts = { proxy: 'http://xxx:yyy@' + nonexisting_host + ':123', proxy_user: 'someone', proxy_pass: 'else' } send_request(opts, proxy_auth_set('xxx', 'yyy', done)); }) }) describe('and options.username is also present', function() { before(function() { opts = { proxy_user: 'foobar', username: 'someone' }; }) it('a separate Authorization header is set', function(done) { var opts = { proxy: nonexisting_host + ':123', proxy_user: 'someone', proxy_pass: 'else', username: 'test', password: 'X' } send_request(opts, basic_auth_set('test', 'X', done)); }) }) }) }) describe('when environment variable is set', function() { describe('and default is unchanged', function() { before(function() { process.env.HTTP_PROXY = 'foobar'; }) after(function() { delete process.env.HTTP_PROXY; }) it('tries to proxy', function(done) { send_request({}, proxied('foobar', 80, done)) }) }) describe('and functionality is disabled', function() { before(function() { process.env.HTTP_PROXY = 'foobar'; }) after(function() { delete process.env.HTTP_PROXY; }) it('ignores proxy', function(done) { send_request({ use_proxy_from_env_var: false }, not_proxied(done)) }) }) }) })