test.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. /* eslint max-statements:0 */
  2. 'use strict';
  3. var assert = require('assert');
  4. var parseUrl = require('url').parse;
  5. var getProxyForUrl = require('./').getProxyForUrl;
  6. // Runs the callback with process.env temporarily set to env.
  7. function runWithEnv(env, callback) {
  8. var originalEnv = process.env;
  9. process.env = env;
  10. try {
  11. callback();
  12. } finally {
  13. process.env = originalEnv;
  14. }
  15. }
  16. // Defines a test case that checks whether getProxyForUrl(input) === expected.
  17. function testProxyUrl(env, expected, input) {
  18. assert(typeof env === 'object' && env !== null);
  19. // Copy object to make sure that the in param does not get modified between
  20. // the call of this function and the use of it below.
  21. env = JSON.parse(JSON.stringify(env));
  22. var title = 'getProxyForUrl(' + JSON.stringify(input) + ')' +
  23. ' === ' + JSON.stringify(expected);
  24. // Save call stack for later use.
  25. var stack = {};
  26. Error.captureStackTrace(stack, testProxyUrl);
  27. // Only use the last stack frame because that shows where this function is
  28. // called, and that is sufficient for our purpose. No need to flood the logs
  29. // with an uninteresting stack trace.
  30. stack = stack.stack.split('\n', 2)[1];
  31. it(title, function() {
  32. var actual;
  33. runWithEnv(env, function() {
  34. actual = getProxyForUrl(input);
  35. });
  36. if (expected === actual) {
  37. return; // Good!
  38. }
  39. try {
  40. assert.strictEqual(expected, actual); // Create a formatted error message.
  41. // Should not happen because previously we determined expected !== actual.
  42. throw new Error('assert.strictEqual passed. This is impossible!');
  43. } catch (e) {
  44. // Use the original stack trace, so we can see a helpful line number.
  45. e.stack = e.message + stack;
  46. throw e;
  47. }
  48. });
  49. }
  50. describe('getProxyForUrl', function() {
  51. describe('No proxy variables', function() {
  52. var env = {};
  53. testProxyUrl(env, '', 'http://example.com');
  54. testProxyUrl(env, '', 'https://example.com');
  55. testProxyUrl(env, '', 'ftp://example.com');
  56. });
  57. describe('Invalid URLs', function() {
  58. var env = {};
  59. env.ALL_PROXY = 'http://unexpected.proxy';
  60. testProxyUrl(env, '', 'bogus');
  61. testProxyUrl(env, '', '//example.com');
  62. testProxyUrl(env, '', '://example.com');
  63. testProxyUrl(env, '', '://');
  64. testProxyUrl(env, '', '/path');
  65. testProxyUrl(env, '', '');
  66. testProxyUrl(env, '', 'http:');
  67. testProxyUrl(env, '', 'http:/');
  68. testProxyUrl(env, '', 'http://');
  69. testProxyUrl(env, '', 'prototype://');
  70. testProxyUrl(env, '', 'hasOwnProperty://');
  71. testProxyUrl(env, '', '__proto__://');
  72. testProxyUrl(env, '', undefined);
  73. testProxyUrl(env, '', null);
  74. testProxyUrl(env, '', {});
  75. testProxyUrl(env, '', {host: 'x', protocol: 1});
  76. testProxyUrl(env, '', {host: 1, protocol: 'x'});
  77. });
  78. describe('http_proxy and HTTP_PROXY', function() {
  79. var env = {};
  80. env.HTTP_PROXY = 'http://http-proxy';
  81. testProxyUrl(env, '', 'https://example');
  82. testProxyUrl(env, 'http://http-proxy', 'http://example');
  83. testProxyUrl(env, 'http://http-proxy', parseUrl('http://example'));
  84. // eslint-disable-next-line camelcase
  85. env.http_proxy = 'http://priority';
  86. testProxyUrl(env, 'http://priority', 'http://example');
  87. });
  88. describe('http_proxy with non-sensical value', function() {
  89. var env = {};
  90. // Crazy values should be passed as-is. It is the responsibility of the
  91. // one who launches the application that the value makes sense.
  92. // TODO: Should we be stricter and perform validation?
  93. env.HTTP_PROXY = 'Crazy \n!() { ::// }';
  94. testProxyUrl(env, 'Crazy \n!() { ::// }', 'http://wow');
  95. // The implementation assumes that the HTTP_PROXY environment variable is
  96. // somewhat reasonable, and if the scheme is missing, it is added.
  97. // Garbage in, garbage out some would say...
  98. env.HTTP_PROXY = 'crazy without colon slash slash';
  99. testProxyUrl(env, 'http://crazy without colon slash slash', 'http://wow');
  100. });
  101. describe('https_proxy and HTTPS_PROXY', function() {
  102. var env = {};
  103. // Assert that there is no fall back to http_proxy
  104. env.HTTP_PROXY = 'http://unexpected.proxy';
  105. testProxyUrl(env, '', 'https://example');
  106. env.HTTPS_PROXY = 'http://https-proxy';
  107. testProxyUrl(env, 'http://https-proxy', 'https://example');
  108. // eslint-disable-next-line camelcase
  109. env.https_proxy = 'http://priority';
  110. testProxyUrl(env, 'http://priority', 'https://example');
  111. });
  112. describe('ftp_proxy', function() {
  113. var env = {};
  114. // Something else than http_proxy / https, as a sanity check.
  115. env.FTP_PROXY = 'http://ftp-proxy';
  116. testProxyUrl(env, 'http://ftp-proxy', 'ftp://example');
  117. testProxyUrl(env, '', 'ftps://example');
  118. });
  119. describe('all_proxy', function() {
  120. var env = {};
  121. env.ALL_PROXY = 'http://catch-all';
  122. testProxyUrl(env, 'http://catch-all', 'https://example');
  123. // eslint-disable-next-line camelcase
  124. env.all_proxy = 'http://priority';
  125. testProxyUrl(env, 'http://priority', 'https://example');
  126. });
  127. describe('all_proxy without scheme', function() {
  128. var env = {};
  129. env.ALL_PROXY = 'noscheme';
  130. testProxyUrl(env, 'http://noscheme', 'http://example');
  131. testProxyUrl(env, 'https://noscheme', 'https://example');
  132. // The module does not impose restrictions on the scheme.
  133. testProxyUrl(env, 'bogus-scheme://noscheme', 'bogus-scheme://example');
  134. // But the URL should still be valid.
  135. testProxyUrl(env, '', 'bogus');
  136. });
  137. describe('no_proxy empty', function() {
  138. var env = {};
  139. env.HTTPS_PROXY = 'http://proxy';
  140. // NO_PROXY set but empty.
  141. env.NO_PROXY = '';
  142. testProxyUrl(env, 'http://proxy', 'https://example');
  143. // No entries in NO_PROXY (comma).
  144. env.NO_PROXY = ',';
  145. testProxyUrl(env, 'http://proxy', 'https://example');
  146. // No entries in NO_PROXY (whitespace).
  147. env.NO_PROXY = ' ';
  148. testProxyUrl(env, 'http://proxy', 'https://example');
  149. // No entries in NO_PROXY (multiple whitespace / commas).
  150. env.NO_PROXY = ',\t,,,\n, ,\r';
  151. testProxyUrl(env, 'http://proxy', 'https://example');
  152. });
  153. describe('no_proxy=example (single host)', function() {
  154. var env = {};
  155. env.HTTP_PROXY = 'http://proxy';
  156. env.NO_PROXY = 'example';
  157. testProxyUrl(env, '', 'http://example');
  158. testProxyUrl(env, '', 'http://example:80');
  159. testProxyUrl(env, '', 'http://example:0');
  160. testProxyUrl(env, '', 'http://example:1337');
  161. testProxyUrl(env, 'http://proxy', 'http://sub.example');
  162. testProxyUrl(env, 'http://proxy', 'http://prefexample');
  163. testProxyUrl(env, 'http://proxy', 'http://example.no');
  164. testProxyUrl(env, 'http://proxy', 'http://a.b.example');
  165. testProxyUrl(env, 'http://proxy', 'http://host/example');
  166. });
  167. describe('no_proxy=sub.example (subdomain)', function() {
  168. var env = {};
  169. env.HTTP_PROXY = 'http://proxy';
  170. env.NO_PROXY = 'sub.example';
  171. testProxyUrl(env, 'http://proxy', 'http://example');
  172. testProxyUrl(env, 'http://proxy', 'http://example:80');
  173. testProxyUrl(env, 'http://proxy', 'http://example:0');
  174. testProxyUrl(env, 'http://proxy', 'http://example:1337');
  175. testProxyUrl(env, '', 'http://sub.example');
  176. testProxyUrl(env, 'http://proxy', 'http://no.sub.example');
  177. testProxyUrl(env, 'http://proxy', 'http://sub-example');
  178. testProxyUrl(env, 'http://proxy', 'http://example.sub');
  179. });
  180. describe('no_proxy=example:80 (host + port)', function() {
  181. var env = {};
  182. env.HTTP_PROXY = 'http://proxy';
  183. env.NO_PROXY = 'example:80';
  184. testProxyUrl(env, '', 'http://example');
  185. testProxyUrl(env, '', 'http://example:80');
  186. testProxyUrl(env, '', 'http://example:0');
  187. testProxyUrl(env, 'http://proxy', 'http://example:1337');
  188. testProxyUrl(env, 'http://proxy', 'http://sub.example');
  189. testProxyUrl(env, 'http://proxy', 'http://prefexample');
  190. testProxyUrl(env, 'http://proxy', 'http://example.no');
  191. testProxyUrl(env, 'http://proxy', 'http://a.b.example');
  192. });
  193. describe('no_proxy=.example (host suffix)', function() {
  194. var env = {};
  195. env.HTTP_PROXY = 'http://proxy';
  196. env.NO_PROXY = '.example';
  197. testProxyUrl(env, 'http://proxy', 'http://example');
  198. testProxyUrl(env, 'http://proxy', 'http://example:80');
  199. testProxyUrl(env, 'http://proxy', 'http://example:1337');
  200. testProxyUrl(env, '', 'http://sub.example');
  201. testProxyUrl(env, '', 'http://sub.example:80');
  202. testProxyUrl(env, '', 'http://sub.example:1337');
  203. testProxyUrl(env, 'http://proxy', 'http://prefexample');
  204. testProxyUrl(env, 'http://proxy', 'http://example.no');
  205. testProxyUrl(env, '', 'http://a.b.example');
  206. });
  207. describe('no_proxy=*', function() {
  208. var env = {};
  209. env.HTTP_PROXY = 'http://proxy';
  210. env.NO_PROXY = '*';
  211. testProxyUrl(env, '', 'http://example.com');
  212. });
  213. describe('no_proxy=*.example (host suffix with *.)', function() {
  214. var env = {};
  215. env.HTTP_PROXY = 'http://proxy';
  216. env.NO_PROXY = '*.example';
  217. testProxyUrl(env, 'http://proxy', 'http://example');
  218. testProxyUrl(env, 'http://proxy', 'http://example:80');
  219. testProxyUrl(env, 'http://proxy', 'http://example:1337');
  220. testProxyUrl(env, '', 'http://sub.example');
  221. testProxyUrl(env, '', 'http://sub.example:80');
  222. testProxyUrl(env, '', 'http://sub.example:1337');
  223. testProxyUrl(env, 'http://proxy', 'http://prefexample');
  224. testProxyUrl(env, 'http://proxy', 'http://example.no');
  225. testProxyUrl(env, '', 'http://a.b.example');
  226. });
  227. describe('no_proxy=*example (substring suffix)', function() {
  228. var env = {};
  229. env.HTTP_PROXY = 'http://proxy';
  230. env.NO_PROXY = '*example';
  231. testProxyUrl(env, '', 'http://example');
  232. testProxyUrl(env, '', 'http://example:80');
  233. testProxyUrl(env, '', 'http://example:1337');
  234. testProxyUrl(env, '', 'http://sub.example');
  235. testProxyUrl(env, '', 'http://sub.example:80');
  236. testProxyUrl(env, '', 'http://sub.example:1337');
  237. testProxyUrl(env, '', 'http://prefexample');
  238. testProxyUrl(env, '', 'http://a.b.example');
  239. testProxyUrl(env, 'http://proxy', 'http://example.no');
  240. testProxyUrl(env, 'http://proxy', 'http://host/example');
  241. });
  242. describe('no_proxy=.*example (arbitrary wildcards are NOT supported)',
  243. function() {
  244. var env = {};
  245. env.HTTP_PROXY = 'http://proxy';
  246. env.NO_PROXY = '.*example';
  247. testProxyUrl(env, 'http://proxy', 'http://example');
  248. testProxyUrl(env, 'http://proxy', 'http://sub.example');
  249. testProxyUrl(env, 'http://proxy', 'http://sub.example');
  250. testProxyUrl(env, 'http://proxy', 'http://prefexample');
  251. testProxyUrl(env, 'http://proxy', 'http://x.prefexample');
  252. testProxyUrl(env, 'http://proxy', 'http://a.b.example');
  253. });
  254. describe('no_proxy=[::1],[::2]:80,10.0.0.1,10.0.0.2:80 (IP addresses)',
  255. function() {
  256. var env = {};
  257. env.HTTP_PROXY = 'http://proxy';
  258. env.NO_PROXY = '[::1],[::2]:80,10.0.0.1,10.0.0.2:80';
  259. testProxyUrl(env, '', 'http://[::1]/');
  260. testProxyUrl(env, '', 'http://[::1]:80/');
  261. testProxyUrl(env, '', 'http://[::1]:1337/');
  262. testProxyUrl(env, '', 'http://[::2]/');
  263. testProxyUrl(env, '', 'http://[::2]:80/');
  264. testProxyUrl(env, 'http://proxy', 'http://[::2]:1337/');
  265. testProxyUrl(env, '', 'http://10.0.0.1/');
  266. testProxyUrl(env, '', 'http://10.0.0.1:80/');
  267. testProxyUrl(env, '', 'http://10.0.0.1:1337/');
  268. testProxyUrl(env, '', 'http://10.0.0.2/');
  269. testProxyUrl(env, '', 'http://10.0.0.2:80/');
  270. testProxyUrl(env, 'http://proxy', 'http://10.0.0.2:1337/');
  271. });
  272. describe('no_proxy=127.0.0.1/32 (CIDR is NOT supported)', function() {
  273. var env = {};
  274. env.HTTP_PROXY = 'http://proxy';
  275. env.NO_PROXY = '127.0.0.1/32';
  276. testProxyUrl(env, 'http://proxy', 'http://127.0.0.1');
  277. testProxyUrl(env, 'http://proxy', 'http://127.0.0.1/32');
  278. });
  279. describe('no_proxy=127.0.0.1 does NOT match localhost', function() {
  280. var env = {};
  281. env.HTTP_PROXY = 'http://proxy';
  282. env.NO_PROXY = '127.0.0.1';
  283. testProxyUrl(env, '', 'http://127.0.0.1');
  284. // We're not performing DNS queries, so this shouldn't match.
  285. testProxyUrl(env, 'http://proxy', 'http://localhost');
  286. });
  287. describe('no_proxy with protocols that have a default port', function() {
  288. var env = {};
  289. env.WS_PROXY = 'http://ws';
  290. env.WSS_PROXY = 'http://wss';
  291. env.HTTP_PROXY = 'http://http';
  292. env.HTTPS_PROXY = 'http://https';
  293. env.GOPHER_PROXY = 'http://gopher';
  294. env.FTP_PROXY = 'http://ftp';
  295. env.ALL_PROXY = 'http://all';
  296. env.NO_PROXY = 'xxx:21,xxx:70,xxx:80,xxx:443';
  297. testProxyUrl(env, '', 'http://xxx');
  298. testProxyUrl(env, '', 'http://xxx:80');
  299. testProxyUrl(env, 'http://http', 'http://xxx:1337');
  300. testProxyUrl(env, '', 'ws://xxx');
  301. testProxyUrl(env, '', 'ws://xxx:80');
  302. testProxyUrl(env, 'http://ws', 'ws://xxx:1337');
  303. testProxyUrl(env, '', 'https://xxx');
  304. testProxyUrl(env, '', 'https://xxx:443');
  305. testProxyUrl(env, 'http://https', 'https://xxx:1337');
  306. testProxyUrl(env, '', 'wss://xxx');
  307. testProxyUrl(env, '', 'wss://xxx:443');
  308. testProxyUrl(env, 'http://wss', 'wss://xxx:1337');
  309. testProxyUrl(env, '', 'gopher://xxx');
  310. testProxyUrl(env, '', 'gopher://xxx:70');
  311. testProxyUrl(env, 'http://gopher', 'gopher://xxx:1337');
  312. testProxyUrl(env, '', 'ftp://xxx');
  313. testProxyUrl(env, '', 'ftp://xxx:21');
  314. testProxyUrl(env, 'http://ftp', 'ftp://xxx:1337');
  315. });
  316. describe('no_proxy should not be case-sensitive', function() {
  317. var env = {};
  318. env.HTTP_PROXY = 'http://proxy';
  319. env.NO_PROXY = 'XXX,YYY,ZzZ';
  320. testProxyUrl(env, '', 'http://xxx');
  321. testProxyUrl(env, '', 'http://XXX');
  322. testProxyUrl(env, '', 'http://yyy');
  323. testProxyUrl(env, '', 'http://YYY');
  324. testProxyUrl(env, '', 'http://ZzZ');
  325. testProxyUrl(env, '', 'http://zZz');
  326. });
  327. describe('NPM proxy configuration', function() {
  328. describe('npm_config_http_proxy should work', function() {
  329. var env = {};
  330. // eslint-disable-next-line camelcase
  331. env.npm_config_http_proxy = 'http://http-proxy';
  332. testProxyUrl(env, '', 'https://example');
  333. testProxyUrl(env, 'http://http-proxy', 'http://example');
  334. // eslint-disable-next-line camelcase
  335. env.npm_config_http_proxy = 'http://priority';
  336. testProxyUrl(env, 'http://priority', 'http://example');
  337. });
  338. // eslint-disable-next-line max-len
  339. describe('npm_config_http_proxy should take precedence over HTTP_PROXY and npm_config_proxy', function() {
  340. var env = {};
  341. // eslint-disable-next-line camelcase
  342. env.npm_config_http_proxy = 'http://http-proxy';
  343. // eslint-disable-next-line camelcase
  344. env.npm_config_proxy = 'http://unexpected-proxy';
  345. env.HTTP_PROXY = 'http://unexpected-proxy';
  346. testProxyUrl(env, 'http://http-proxy', 'http://example');
  347. });
  348. describe('npm_config_https_proxy should work', function() {
  349. var env = {};
  350. // eslint-disable-next-line camelcase
  351. env.npm_config_http_proxy = 'http://unexpected.proxy';
  352. testProxyUrl(env, '', 'https://example');
  353. // eslint-disable-next-line camelcase
  354. env.npm_config_https_proxy = 'http://https-proxy';
  355. testProxyUrl(env, 'http://https-proxy', 'https://example');
  356. // eslint-disable-next-line camelcase
  357. env.npm_config_https_proxy = 'http://priority';
  358. testProxyUrl(env, 'http://priority', 'https://example');
  359. });
  360. // eslint-disable-next-line max-len
  361. describe('npm_config_https_proxy should take precedence over HTTPS_PROXY and npm_config_proxy', function() {
  362. var env = {};
  363. // eslint-disable-next-line camelcase
  364. env.npm_config_https_proxy = 'http://https-proxy';
  365. // eslint-disable-next-line camelcase
  366. env.npm_config_proxy = 'http://unexpected-proxy';
  367. env.HTTPS_PROXY = 'http://unexpected-proxy';
  368. testProxyUrl(env, 'http://https-proxy', 'https://example');
  369. });
  370. describe('npm_config_proxy should work', function() {
  371. var env = {};
  372. // eslint-disable-next-line camelcase
  373. env.npm_config_proxy = 'http://http-proxy';
  374. testProxyUrl(env, 'http://http-proxy', 'http://example');
  375. testProxyUrl(env, 'http://http-proxy', 'https://example');
  376. // eslint-disable-next-line camelcase
  377. env.npm_config_proxy = 'http://priority';
  378. testProxyUrl(env, 'http://priority', 'http://example');
  379. testProxyUrl(env, 'http://priority', 'https://example');
  380. });
  381. // eslint-disable-next-line max-len
  382. describe('HTTP_PROXY and HTTPS_PROXY should take precedence over npm_config_proxy', function() {
  383. var env = {};
  384. env.HTTP_PROXY = 'http://http-proxy';
  385. env.HTTPS_PROXY = 'http://https-proxy';
  386. // eslint-disable-next-line camelcase
  387. env.npm_config_proxy = 'http://unexpected-proxy';
  388. testProxyUrl(env, 'http://http-proxy', 'http://example');
  389. testProxyUrl(env, 'http://https-proxy', 'https://example');
  390. });
  391. describe('npm_config_no_proxy should work', function() {
  392. var env = {};
  393. env.HTTP_PROXY = 'http://proxy';
  394. // eslint-disable-next-line camelcase
  395. env.npm_config_no_proxy = 'example';
  396. testProxyUrl(env, '', 'http://example');
  397. testProxyUrl(env, 'http://proxy', 'http://otherwebsite');
  398. });
  399. // eslint-disable-next-line max-len
  400. describe('npm_config_no_proxy should take precedence over NO_PROXY', function() {
  401. var env = {};
  402. env.HTTP_PROXY = 'http://proxy';
  403. env.NO_PROXY = 'otherwebsite';
  404. // eslint-disable-next-line camelcase
  405. env.npm_config_no_proxy = 'example';
  406. testProxyUrl(env, '', 'http://example');
  407. testProxyUrl(env, 'http://proxy', 'http://otherwebsite');
  408. });
  409. });
  410. });