proxy_spec.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. var helpers = require('./helpers'),
  2. should = require('should'),
  3. sinon = require('sinon'),
  4. http = require('http'),
  5. needle = require('./../');
  6. var port = 7707;
  7. var url = 'localhost:' + port;
  8. var nonexisting_host = 'awepfokawepofawe.com';
  9. describe('proxy option', function() {
  10. var spy, opts;
  11. function send_request(opts, done) {
  12. if (spy) spy.restore();
  13. spy = sinon.spy(http, 'request');
  14. needle.get(url, opts, done);
  15. }
  16. //////////////////////
  17. // proxy opts helpers
  18. function not_proxied(done) {
  19. return function(err, resp) {
  20. var path = spy.args[0][0].path;
  21. path.should.eql('/'); // not the full original URI
  22. spy.restore();
  23. done();
  24. }
  25. }
  26. function proxied(host, port, done) {
  27. return function(err, resp) {
  28. var path = spy.args[0][0].path;
  29. path.should.eql('http://' + url); // the full original URI
  30. var http_host = spy.args[0][0].host;
  31. if (http_host) http_host.should.eql(host);
  32. var http_port = spy.args[0][0].port;
  33. if (http_port) http_port.should.eql(port);
  34. spy.restore();
  35. done();
  36. }
  37. }
  38. //////////////////////
  39. // auth helpers
  40. function get_auth(header) {
  41. var token = header.split(/\s+/).pop();
  42. return token && Buffer.from(token, 'base64').toString().split(':');
  43. }
  44. function no_proxy_auth(done) {
  45. return function(err, resp) {
  46. var headers = spy.args[0][0].headers;
  47. Object.keys(headers).should.not.containEql('proxy-authorization');
  48. done();
  49. }
  50. }
  51. function header_set(name, user, pass, done) {
  52. return function(err, resp) {
  53. var headers = spy.args[0][0].headers;
  54. var auth = get_auth(headers[name]);
  55. auth[0].should.eql(user);
  56. auth[1].should.eql(pass);
  57. done();
  58. }
  59. }
  60. function proxy_auth_set(user, pass, done) {
  61. return header_set('proxy-authorization', user, pass, done);
  62. }
  63. function basic_auth_set(user, pass, done) {
  64. return header_set('authorization', user, pass, done);
  65. }
  66. after(function() {
  67. spy.restore();
  68. })
  69. describe('when null proxy is passed', function() {
  70. it('does not proxy', function(done) {
  71. send_request({ proxy: null }, not_proxied(done))
  72. })
  73. describe('but defaults has been set', function() {
  74. before(function() {
  75. needle.defaults({ proxy: 'foobar' });
  76. })
  77. after(function() {
  78. needle.defaults({ proxy: null });
  79. })
  80. it('tries to proxy anyway', function(done) {
  81. send_request({}, proxied('foobar', 80, done))
  82. })
  83. })
  84. })
  85. describe('when weird string is passed', function() {
  86. it('tries to proxy anyway', function(done) {
  87. send_request({ proxy: 'alfalfa' }, proxied('alfalfa', 80, done))
  88. })
  89. })
  90. describe('when valid url is passed', function() {
  91. describe('without NO_PROXY env var set', function() {
  92. it('proxies request', function(done) {
  93. send_request({ proxy: nonexisting_host + ':123/done' }, proxied(nonexisting_host, '123', done))
  94. })
  95. it('does not set a Proxy-Authorization header', function(done) {
  96. send_request({ proxy: nonexisting_host + ':123/done' }, no_proxy_auth(done));
  97. })
  98. })
  99. describe('with NO_PROXY env var set', function() {
  100. it('proxies request if matching host not found in list', function(done) {
  101. process.env.NO_PROXY = 'foo';
  102. send_request({ proxy: nonexisting_host + ':123/done' }, proxied(nonexisting_host, '123', function() {
  103. delete process.env.NO_PROXY;
  104. done();
  105. }))
  106. })
  107. it('does not proxy request if matching host in list and just has a different port', function(done) {
  108. process.env.NO_PROXY = 'localhost';
  109. send_request({ proxy: nonexisting_host + ':123/done' }, not_proxied(function() {
  110. delete process.env.NO_PROXY;
  111. done();
  112. }))
  113. })
  114. it('does not proxy if matching host found in list', function(done) {
  115. process.env.NO_PROXY = 'foo,' + url;
  116. send_request({ proxy: nonexisting_host + ':123/done' }, not_proxied(function() {
  117. delete process.env.NO_PROXY;
  118. done();
  119. }))
  120. })
  121. })
  122. describe('and proxy url contains user:pass', function() {
  123. before(function() {
  124. opts = {
  125. proxy: 'http://mj:x@' + nonexisting_host + ':123/done'
  126. }
  127. })
  128. it('proxies request', function(done) {
  129. send_request(opts, proxied(nonexisting_host, '123', done))
  130. })
  131. it('sets Proxy-Authorization header', function(done) {
  132. send_request(opts, proxy_auth_set('mj', 'x', done));
  133. })
  134. })
  135. describe('and a proxy_user is passed', function() {
  136. before(function() {
  137. opts = {
  138. proxy: nonexisting_host + ':123',
  139. proxy_user: 'someone',
  140. proxy_pass: 'else'
  141. }
  142. })
  143. it('proxies request', function(done) {
  144. send_request(opts, proxied(nonexisting_host, '123', done))
  145. })
  146. it('sets Proxy-Authorization header', function(done) {
  147. send_request(opts, proxy_auth_set('someone', 'else', done));
  148. })
  149. describe('and url also contains user:pass', function() {
  150. it('url user:pass wins', function(done) {
  151. var opts = {
  152. proxy: 'http://xxx:yyy@' + nonexisting_host + ':123',
  153. proxy_user: 'someone',
  154. proxy_pass: 'else'
  155. }
  156. send_request(opts, proxy_auth_set('xxx', 'yyy', done));
  157. })
  158. })
  159. describe('and options.username is also present', function() {
  160. before(function() {
  161. opts = { proxy_user: 'foobar', username: 'someone' };
  162. })
  163. it('a separate Authorization header is set', function(done) {
  164. var opts = {
  165. proxy: nonexisting_host + ':123',
  166. proxy_user: 'someone',
  167. proxy_pass: 'else',
  168. username: 'test',
  169. password: 'X'
  170. }
  171. send_request(opts, basic_auth_set('test', 'X', done));
  172. })
  173. })
  174. })
  175. })
  176. describe('when environment variable is set', function() {
  177. describe('and default is unchanged', function() {
  178. before(function() {
  179. process.env.HTTP_PROXY = 'foobar';
  180. })
  181. after(function() {
  182. delete process.env.HTTP_PROXY;
  183. })
  184. it('tries to proxy', function(done) {
  185. send_request({}, proxied('foobar', 80, done))
  186. })
  187. })
  188. describe('and functionality is disabled', function() {
  189. before(function() {
  190. process.env.HTTP_PROXY = 'foobar';
  191. })
  192. after(function() {
  193. delete process.env.HTTP_PROXY;
  194. })
  195. it('ignores proxy', function(done) {
  196. send_request({
  197. use_proxy_from_env_var: false
  198. }, not_proxied(done))
  199. })
  200. })
  201. })
  202. })