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