1'use strict';
2const common = require('../common');
3
4if (!common.hasIntl)
5  common.skip('missing Intl');
6
7const assert = require('assert');
8const inspect = require('util').inspect;
9
10const url = require('url');
11
12// URLs to parse, and expected data
13// { url : parsed }
14const parseTests = {
15  '//some_path': {
16    href: '//some_path',
17    pathname: '//some_path',
18    path: '//some_path'
19  },
20
21  'http:\\\\evil-phisher\\foo.html#h\\a\\s\\h': {
22    protocol: 'http:',
23    slashes: true,
24    host: 'evil-phisher',
25    hostname: 'evil-phisher',
26    pathname: '/foo.html',
27    path: '/foo.html',
28    hash: '#h%5Ca%5Cs%5Ch',
29    href: 'http://evil-phisher/foo.html#h%5Ca%5Cs%5Ch'
30  },
31
32  'http:\\\\evil-phisher\\foo.html?json="\\"foo\\""#h\\a\\s\\h': {
33    protocol: 'http:',
34    slashes: true,
35    host: 'evil-phisher',
36    hostname: 'evil-phisher',
37    pathname: '/foo.html',
38    search: '?json=%22%5C%22foo%5C%22%22',
39    query: 'json=%22%5C%22foo%5C%22%22',
40    path: '/foo.html?json=%22%5C%22foo%5C%22%22',
41    hash: '#h%5Ca%5Cs%5Ch',
42    href: 'http://evil-phisher/foo.html?json=%22%5C%22foo%5C%22%22#h%5Ca%5Cs%5Ch'
43  },
44
45  'http:\\\\evil-phisher\\foo.html#h\\a\\s\\h?blarg': {
46    protocol: 'http:',
47    slashes: true,
48    host: 'evil-phisher',
49    hostname: 'evil-phisher',
50    pathname: '/foo.html',
51    path: '/foo.html',
52    hash: '#h%5Ca%5Cs%5Ch?blarg',
53    href: 'http://evil-phisher/foo.html#h%5Ca%5Cs%5Ch?blarg'
54  },
55
56
57  'http:\\\\evil-phisher\\foo.html': {
58    protocol: 'http:',
59    slashes: true,
60    host: 'evil-phisher',
61    hostname: 'evil-phisher',
62    pathname: '/foo.html',
63    path: '/foo.html',
64    href: 'http://evil-phisher/foo.html'
65  },
66
67  'HTTP://www.example.com/': {
68    href: 'http://www.example.com/',
69    protocol: 'http:',
70    slashes: true,
71    host: 'www.example.com',
72    hostname: 'www.example.com',
73    pathname: '/',
74    path: '/'
75  },
76
77  'HTTP://www.example.com': {
78    href: 'http://www.example.com/',
79    protocol: 'http:',
80    slashes: true,
81    host: 'www.example.com',
82    hostname: 'www.example.com',
83    pathname: '/',
84    path: '/'
85  },
86
87  'http://www.ExAmPlE.com/': {
88    href: 'http://www.example.com/',
89    protocol: 'http:',
90    slashes: true,
91    host: 'www.example.com',
92    hostname: 'www.example.com',
93    pathname: '/',
94    path: '/'
95  },
96
97  'http://user:pw@www.ExAmPlE.com/': {
98    href: 'http://user:pw@www.example.com/',
99    protocol: 'http:',
100    slashes: true,
101    auth: 'user:pw',
102    host: 'www.example.com',
103    hostname: 'www.example.com',
104    pathname: '/',
105    path: '/'
106  },
107
108  'http://USER:PW@www.ExAmPlE.com/': {
109    href: 'http://USER:PW@www.example.com/',
110    protocol: 'http:',
111    slashes: true,
112    auth: 'USER:PW',
113    host: 'www.example.com',
114    hostname: 'www.example.com',
115    pathname: '/',
116    path: '/'
117  },
118
119  'http://user@www.example.com/': {
120    href: 'http://user@www.example.com/',
121    protocol: 'http:',
122    slashes: true,
123    auth: 'user',
124    host: 'www.example.com',
125    hostname: 'www.example.com',
126    pathname: '/',
127    path: '/'
128  },
129
130  'http://user%3Apw@www.example.com/': {
131    href: 'http://user:pw@www.example.com/',
132    protocol: 'http:',
133    slashes: true,
134    auth: 'user:pw',
135    host: 'www.example.com',
136    hostname: 'www.example.com',
137    pathname: '/',
138    path: '/'
139  },
140
141  'http://x.com/path?that\'s#all, folks': {
142    href: 'http://x.com/path?that%27s#all,%20folks',
143    protocol: 'http:',
144    slashes: true,
145    host: 'x.com',
146    hostname: 'x.com',
147    search: '?that%27s',
148    query: 'that%27s',
149    pathname: '/path',
150    hash: '#all,%20folks',
151    path: '/path?that%27s'
152  },
153
154  'HTTP://X.COM/Y': {
155    href: 'http://x.com/Y',
156    protocol: 'http:',
157    slashes: true,
158    host: 'x.com',
159    hostname: 'x.com',
160    pathname: '/Y',
161    path: '/Y'
162  },
163
164  // Whitespace in the front
165  ' http://www.example.com/': {
166    href: 'http://www.example.com/',
167    protocol: 'http:',
168    slashes: true,
169    host: 'www.example.com',
170    hostname: 'www.example.com',
171    pathname: '/',
172    path: '/'
173  },
174
175  // + not an invalid host character
176  // per https://url.spec.whatwg.org/#host-parsing
177  'http://x.y.com+a/b/c': {
178    href: 'http://x.y.com+a/b/c',
179    protocol: 'http:',
180    slashes: true,
181    host: 'x.y.com+a',
182    hostname: 'x.y.com+a',
183    pathname: '/b/c',
184    path: '/b/c'
185  },
186
187  // An unexpected invalid char in the hostname.
188  'HtTp://x.y.cOm;a/b/c?d=e#f g<h>i': {
189    href: 'http://x.y.com/;a/b/c?d=e#f%20g%3Ch%3Ei',
190    protocol: 'http:',
191    slashes: true,
192    host: 'x.y.com',
193    hostname: 'x.y.com',
194    pathname: ';a/b/c',
195    search: '?d=e',
196    query: 'd=e',
197    hash: '#f%20g%3Ch%3Ei',
198    path: ';a/b/c?d=e'
199  },
200
201  // Make sure that we don't accidentally lcast the path parts.
202  'HtTp://x.y.cOm;A/b/c?d=e#f g<h>i': {
203    href: 'http://x.y.com/;A/b/c?d=e#f%20g%3Ch%3Ei',
204    protocol: 'http:',
205    slashes: true,
206    host: 'x.y.com',
207    hostname: 'x.y.com',
208    pathname: ';A/b/c',
209    search: '?d=e',
210    query: 'd=e',
211    hash: '#f%20g%3Ch%3Ei',
212    path: ';A/b/c?d=e'
213  },
214
215  'http://x...y...#p': {
216    href: 'http://x...y.../#p',
217    protocol: 'http:',
218    slashes: true,
219    host: 'x...y...',
220    hostname: 'x...y...',
221    hash: '#p',
222    pathname: '/',
223    path: '/'
224  },
225
226  'http://x/p/"quoted"': {
227    href: 'http://x/p/%22quoted%22',
228    protocol: 'http:',
229    slashes: true,
230    host: 'x',
231    hostname: 'x',
232    pathname: '/p/%22quoted%22',
233    path: '/p/%22quoted%22'
234  },
235
236  '<http://goo.corn/bread> Is a URL!': {
237    href: '%3Chttp://goo.corn/bread%3E%20Is%20a%20URL!',
238    pathname: '%3Chttp://goo.corn/bread%3E%20Is%20a%20URL!',
239    path: '%3Chttp://goo.corn/bread%3E%20Is%20a%20URL!'
240  },
241
242  'http://www.narwhaljs.org/blog/categories?id=news': {
243    href: 'http://www.narwhaljs.org/blog/categories?id=news',
244    protocol: 'http:',
245    slashes: true,
246    host: 'www.narwhaljs.org',
247    hostname: 'www.narwhaljs.org',
248    search: '?id=news',
249    query: 'id=news',
250    pathname: '/blog/categories',
251    path: '/blog/categories?id=news'
252  },
253
254  'http://mt0.google.com/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s=': {
255    href: 'http://mt0.google.com/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s=',
256    protocol: 'http:',
257    slashes: true,
258    host: 'mt0.google.com',
259    hostname: 'mt0.google.com',
260    pathname: '/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s=',
261    path: '/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s='
262  },
263
264  'http://mt0.google.com/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=': {
265    href: 'http://mt0.google.com/vt/lyrs=m@114???&hl=en&src=api' +
266          '&x=2&y=2&z=3&s=',
267    protocol: 'http:',
268    slashes: true,
269    host: 'mt0.google.com',
270    hostname: 'mt0.google.com',
271    search: '???&hl=en&src=api&x=2&y=2&z=3&s=',
272    query: '??&hl=en&src=api&x=2&y=2&z=3&s=',
273    pathname: '/vt/lyrs=m@114',
274    path: '/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s='
275  },
276
277  'http://user:pass@mt0.google.com/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=': {
278    href: 'http://user:pass@mt0.google.com/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=',
279    protocol: 'http:',
280    slashes: true,
281    host: 'mt0.google.com',
282    auth: 'user:pass',
283    hostname: 'mt0.google.com',
284    search: '???&hl=en&src=api&x=2&y=2&z=3&s=',
285    query: '??&hl=en&src=api&x=2&y=2&z=3&s=',
286    pathname: '/vt/lyrs=m@114',
287    path: '/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s='
288  },
289
290  'file:///etc/passwd': {
291    href: 'file:///etc/passwd',
292    slashes: true,
293    protocol: 'file:',
294    pathname: '/etc/passwd',
295    hostname: '',
296    host: '',
297    path: '/etc/passwd'
298  },
299
300  'file://localhost/etc/passwd': {
301    href: 'file://localhost/etc/passwd',
302    protocol: 'file:',
303    slashes: true,
304    pathname: '/etc/passwd',
305    hostname: 'localhost',
306    host: 'localhost',
307    path: '/etc/passwd'
308  },
309
310  'file://foo/etc/passwd': {
311    href: 'file://foo/etc/passwd',
312    protocol: 'file:',
313    slashes: true,
314    pathname: '/etc/passwd',
315    hostname: 'foo',
316    host: 'foo',
317    path: '/etc/passwd'
318  },
319
320  'file:///etc/node/': {
321    href: 'file:///etc/node/',
322    slashes: true,
323    protocol: 'file:',
324    pathname: '/etc/node/',
325    hostname: '',
326    host: '',
327    path: '/etc/node/'
328  },
329
330  'file://localhost/etc/node/': {
331    href: 'file://localhost/etc/node/',
332    protocol: 'file:',
333    slashes: true,
334    pathname: '/etc/node/',
335    hostname: 'localhost',
336    host: 'localhost',
337    path: '/etc/node/'
338  },
339
340  'file://foo/etc/node/': {
341    href: 'file://foo/etc/node/',
342    protocol: 'file:',
343    slashes: true,
344    pathname: '/etc/node/',
345    hostname: 'foo',
346    host: 'foo',
347    path: '/etc/node/'
348  },
349
350  'http:/baz/../foo/bar': {
351    href: 'http:/baz/../foo/bar',
352    protocol: 'http:',
353    pathname: '/baz/../foo/bar',
354    path: '/baz/../foo/bar'
355  },
356
357  'http://user:pass@example.com:8000/foo/bar?baz=quux#frag': {
358    href: 'http://user:pass@example.com:8000/foo/bar?baz=quux#frag',
359    protocol: 'http:',
360    slashes: true,
361    host: 'example.com:8000',
362    auth: 'user:pass',
363    port: '8000',
364    hostname: 'example.com',
365    hash: '#frag',
366    search: '?baz=quux',
367    query: 'baz=quux',
368    pathname: '/foo/bar',
369    path: '/foo/bar?baz=quux'
370  },
371
372  '//user:pass@example.com:8000/foo/bar?baz=quux#frag': {
373    href: '//user:pass@example.com:8000/foo/bar?baz=quux#frag',
374    slashes: true,
375    host: 'example.com:8000',
376    auth: 'user:pass',
377    port: '8000',
378    hostname: 'example.com',
379    hash: '#frag',
380    search: '?baz=quux',
381    query: 'baz=quux',
382    pathname: '/foo/bar',
383    path: '/foo/bar?baz=quux'
384  },
385
386  '/foo/bar?baz=quux#frag': {
387    href: '/foo/bar?baz=quux#frag',
388    hash: '#frag',
389    search: '?baz=quux',
390    query: 'baz=quux',
391    pathname: '/foo/bar',
392    path: '/foo/bar?baz=quux'
393  },
394
395  'http:/foo/bar?baz=quux#frag': {
396    href: 'http:/foo/bar?baz=quux#frag',
397    protocol: 'http:',
398    hash: '#frag',
399    search: '?baz=quux',
400    query: 'baz=quux',
401    pathname: '/foo/bar',
402    path: '/foo/bar?baz=quux'
403  },
404
405  'mailto:foo@bar.com?subject=hello': {
406    href: 'mailto:foo@bar.com?subject=hello',
407    protocol: 'mailto:',
408    host: 'bar.com',
409    auth: 'foo',
410    hostname: 'bar.com',
411    search: '?subject=hello',
412    query: 'subject=hello',
413    path: '?subject=hello'
414  },
415
416  'javascript:alert(\'hello\');': {
417    href: 'javascript:alert(\'hello\');',
418    protocol: 'javascript:',
419    pathname: 'alert(\'hello\');',
420    path: 'alert(\'hello\');'
421  },
422
423  'xmpp:isaacschlueter@jabber.org': {
424    href: 'xmpp:isaacschlueter@jabber.org',
425    protocol: 'xmpp:',
426    host: 'jabber.org',
427    auth: 'isaacschlueter',
428    hostname: 'jabber.org'
429  },
430
431  'http://atpass:foo%40bar@127.0.0.1:8080/path?search=foo#bar': {
432    href: 'http://atpass:foo%40bar@127.0.0.1:8080/path?search=foo#bar',
433    protocol: 'http:',
434    slashes: true,
435    host: '127.0.0.1:8080',
436    auth: 'atpass:foo@bar',
437    hostname: '127.0.0.1',
438    port: '8080',
439    pathname: '/path',
440    search: '?search=foo',
441    query: 'search=foo',
442    hash: '#bar',
443    path: '/path?search=foo'
444  },
445
446  'svn+ssh://foo/bar': {
447    href: 'svn+ssh://foo/bar',
448    host: 'foo',
449    hostname: 'foo',
450    protocol: 'svn+ssh:',
451    pathname: '/bar',
452    path: '/bar',
453    slashes: true
454  },
455
456  'dash-test://foo/bar': {
457    href: 'dash-test://foo/bar',
458    host: 'foo',
459    hostname: 'foo',
460    protocol: 'dash-test:',
461    pathname: '/bar',
462    path: '/bar',
463    slashes: true
464  },
465
466  'dash-test:foo/bar': {
467    href: 'dash-test:foo/bar',
468    host: 'foo',
469    hostname: 'foo',
470    protocol: 'dash-test:',
471    pathname: '/bar',
472    path: '/bar'
473  },
474
475  'dot.test://foo/bar': {
476    href: 'dot.test://foo/bar',
477    host: 'foo',
478    hostname: 'foo',
479    protocol: 'dot.test:',
480    pathname: '/bar',
481    path: '/bar',
482    slashes: true
483  },
484
485  'dot.test:foo/bar': {
486    href: 'dot.test:foo/bar',
487    host: 'foo',
488    hostname: 'foo',
489    protocol: 'dot.test:',
490    pathname: '/bar',
491    path: '/bar'
492  },
493
494  // IDNA tests
495  'http://www.日本語.com/': {
496    href: 'http://www.xn--wgv71a119e.com/',
497    protocol: 'http:',
498    slashes: true,
499    host: 'www.xn--wgv71a119e.com',
500    hostname: 'www.xn--wgv71a119e.com',
501    pathname: '/',
502    path: '/'
503  },
504
505  'http://example.Bücher.com/': {
506    href: 'http://example.xn--bcher-kva.com/',
507    protocol: 'http:',
508    slashes: true,
509    host: 'example.xn--bcher-kva.com',
510    hostname: 'example.xn--bcher-kva.com',
511    pathname: '/',
512    path: '/'
513  },
514
515  'http://www.Äffchen.com/': {
516    href: 'http://www.xn--ffchen-9ta.com/',
517    protocol: 'http:',
518    slashes: true,
519    host: 'www.xn--ffchen-9ta.com',
520    hostname: 'www.xn--ffchen-9ta.com',
521    pathname: '/',
522    path: '/'
523  },
524
525  'http://www.Äffchen.cOm;A/b/c?d=e#f g<h>i': {
526    href: 'http://www.xn--ffchen-9ta.com/;A/b/c?d=e#f%20g%3Ch%3Ei',
527    protocol: 'http:',
528    slashes: true,
529    host: 'www.xn--ffchen-9ta.com',
530    hostname: 'www.xn--ffchen-9ta.com',
531    pathname: ';A/b/c',
532    search: '?d=e',
533    query: 'd=e',
534    hash: '#f%20g%3Ch%3Ei',
535    path: ';A/b/c?d=e'
536  },
537
538  'http://SÉLIER.COM/': {
539    href: 'http://xn--slier-bsa.com/',
540    protocol: 'http:',
541    slashes: true,
542    host: 'xn--slier-bsa.com',
543    hostname: 'xn--slier-bsa.com',
544    pathname: '/',
545    path: '/'
546  },
547
548  'http://ليهمابتكلموشعربي؟.ي؟/': {
549    href: 'http://xn--egbpdaj6bu4bxfgehfvwxn.xn--egb9f/',
550    protocol: 'http:',
551    slashes: true,
552    host: 'xn--egbpdaj6bu4bxfgehfvwxn.xn--egb9f',
553    hostname: 'xn--egbpdaj6bu4bxfgehfvwxn.xn--egb9f',
554    pathname: '/',
555    path: '/'
556  },
557
558  'http://➡.ws/➡': {
559    href: 'http://xn--hgi.ws/➡',
560    protocol: 'http:',
561    slashes: true,
562    host: 'xn--hgi.ws',
563    hostname: 'xn--hgi.ws',
564    pathname: '/➡',
565    path: '/➡'
566  },
567
568  'http://bucket_name.s3.amazonaws.com/image.jpg': {
569    protocol: 'http:',
570    slashes: true,
571    host: 'bucket_name.s3.amazonaws.com',
572    hostname: 'bucket_name.s3.amazonaws.com',
573    pathname: '/image.jpg',
574    href: 'http://bucket_name.s3.amazonaws.com/image.jpg',
575    path: '/image.jpg'
576  },
577
578  'git+http://github.com/joyent/node.git': {
579    protocol: 'git+http:',
580    slashes: true,
581    host: 'github.com',
582    hostname: 'github.com',
583    pathname: '/joyent/node.git',
584    path: '/joyent/node.git',
585    href: 'git+http://github.com/joyent/node.git'
586  },
587
588  // If local1@domain1 is uses as a relative URL it may
589  // be parse into auth@hostname, but here there is no
590  // way to make it work in url.parse, I add the test to be explicit
591  'local1@domain1': {
592    pathname: 'local1@domain1',
593    path: 'local1@domain1',
594    href: 'local1@domain1'
595  },
596
597  // While this may seem counter-intuitive, a browser will parse
598  // <a href='www.google.com'> as a path.
599  'www.example.com': {
600    href: 'www.example.com',
601    pathname: 'www.example.com',
602    path: 'www.example.com'
603  },
604
605  // ipv6 support
606  '[fe80::1]': {
607    href: '[fe80::1]',
608    pathname: '[fe80::1]',
609    path: '[fe80::1]'
610  },
611
612  'coap://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]': {
613    protocol: 'coap:',
614    slashes: true,
615    host: '[fedc:ba98:7654:3210:fedc:ba98:7654:3210]',
616    hostname: 'fedc:ba98:7654:3210:fedc:ba98:7654:3210',
617    href: 'coap://[fedc:ba98:7654:3210:fedc:ba98:7654:3210]/',
618    pathname: '/',
619    path: '/'
620  },
621
622  'coap://[1080:0:0:0:8:800:200C:417A]:61616/': {
623    protocol: 'coap:',
624    slashes: true,
625    host: '[1080:0:0:0:8:800:200c:417a]:61616',
626    port: '61616',
627    hostname: '1080:0:0:0:8:800:200c:417a',
628    href: 'coap://[1080:0:0:0:8:800:200c:417a]:61616/',
629    pathname: '/',
630    path: '/'
631  },
632
633  'http://user:password@[3ffe:2a00:100:7031::1]:8080': {
634    protocol: 'http:',
635    slashes: true,
636    auth: 'user:password',
637    host: '[3ffe:2a00:100:7031::1]:8080',
638    port: '8080',
639    hostname: '3ffe:2a00:100:7031::1',
640    href: 'http://user:password@[3ffe:2a00:100:7031::1]:8080/',
641    pathname: '/',
642    path: '/'
643  },
644
645  'coap://u:p@[::192.9.5.5]:61616/.well-known/r?n=Temperature': {
646    protocol: 'coap:',
647    slashes: true,
648    auth: 'u:p',
649    host: '[::192.9.5.5]:61616',
650    port: '61616',
651    hostname: '::192.9.5.5',
652    href: 'coap://u:p@[::192.9.5.5]:61616/.well-known/r?n=Temperature',
653    search: '?n=Temperature',
654    query: 'n=Temperature',
655    pathname: '/.well-known/r',
656    path: '/.well-known/r?n=Temperature'
657  },
658
659  // empty port
660  'http://example.com:': {
661    protocol: 'http:',
662    slashes: true,
663    host: 'example.com',
664    hostname: 'example.com',
665    href: 'http://example.com/',
666    pathname: '/',
667    path: '/'
668  },
669
670  'http://example.com:/a/b.html': {
671    protocol: 'http:',
672    slashes: true,
673    host: 'example.com',
674    hostname: 'example.com',
675    href: 'http://example.com/a/b.html',
676    pathname: '/a/b.html',
677    path: '/a/b.html'
678  },
679
680  'http://example.com:?a=b': {
681    protocol: 'http:',
682    slashes: true,
683    host: 'example.com',
684    hostname: 'example.com',
685    href: 'http://example.com/?a=b',
686    search: '?a=b',
687    query: 'a=b',
688    pathname: '/',
689    path: '/?a=b'
690  },
691
692  'http://example.com:#abc': {
693    protocol: 'http:',
694    slashes: true,
695    host: 'example.com',
696    hostname: 'example.com',
697    href: 'http://example.com/#abc',
698    hash: '#abc',
699    pathname: '/',
700    path: '/'
701  },
702
703  'http://[fe80::1]:/a/b?a=b#abc': {
704    protocol: 'http:',
705    slashes: true,
706    host: '[fe80::1]',
707    hostname: 'fe80::1',
708    href: 'http://[fe80::1]/a/b?a=b#abc',
709    search: '?a=b',
710    query: 'a=b',
711    hash: '#abc',
712    pathname: '/a/b',
713    path: '/a/b?a=b'
714  },
715
716  'http://-lovemonsterz.tumblr.com/rss': {
717    protocol: 'http:',
718    slashes: true,
719    host: '-lovemonsterz.tumblr.com',
720    hostname: '-lovemonsterz.tumblr.com',
721    href: 'http://-lovemonsterz.tumblr.com/rss',
722    pathname: '/rss',
723    path: '/rss',
724  },
725
726  'http://-lovemonsterz.tumblr.com:80/rss': {
727    protocol: 'http:',
728    slashes: true,
729    port: '80',
730    host: '-lovemonsterz.tumblr.com:80',
731    hostname: '-lovemonsterz.tumblr.com',
732    href: 'http://-lovemonsterz.tumblr.com:80/rss',
733    pathname: '/rss',
734    path: '/rss',
735  },
736
737  'http://user:pass@-lovemonsterz.tumblr.com/rss': {
738    protocol: 'http:',
739    slashes: true,
740    auth: 'user:pass',
741    host: '-lovemonsterz.tumblr.com',
742    hostname: '-lovemonsterz.tumblr.com',
743    href: 'http://user:pass@-lovemonsterz.tumblr.com/rss',
744    pathname: '/rss',
745    path: '/rss',
746  },
747
748  'http://user:pass@-lovemonsterz.tumblr.com:80/rss': {
749    protocol: 'http:',
750    slashes: true,
751    auth: 'user:pass',
752    port: '80',
753    host: '-lovemonsterz.tumblr.com:80',
754    hostname: '-lovemonsterz.tumblr.com',
755    href: 'http://user:pass@-lovemonsterz.tumblr.com:80/rss',
756    pathname: '/rss',
757    path: '/rss',
758  },
759
760  'http://_jabber._tcp.google.com/test': {
761    protocol: 'http:',
762    slashes: true,
763    host: '_jabber._tcp.google.com',
764    hostname: '_jabber._tcp.google.com',
765    href: 'http://_jabber._tcp.google.com/test',
766    pathname: '/test',
767    path: '/test',
768  },
769
770  'http://user:pass@_jabber._tcp.google.com/test': {
771    protocol: 'http:',
772    slashes: true,
773    auth: 'user:pass',
774    host: '_jabber._tcp.google.com',
775    hostname: '_jabber._tcp.google.com',
776    href: 'http://user:pass@_jabber._tcp.google.com/test',
777    pathname: '/test',
778    path: '/test',
779  },
780
781  'http://_jabber._tcp.google.com:80/test': {
782    protocol: 'http:',
783    slashes: true,
784    port: '80',
785    host: '_jabber._tcp.google.com:80',
786    hostname: '_jabber._tcp.google.com',
787    href: 'http://_jabber._tcp.google.com:80/test',
788    pathname: '/test',
789    path: '/test',
790  },
791
792  'http://user:pass@_jabber._tcp.google.com:80/test': {
793    protocol: 'http:',
794    slashes: true,
795    auth: 'user:pass',
796    port: '80',
797    host: '_jabber._tcp.google.com:80',
798    hostname: '_jabber._tcp.google.com',
799    href: 'http://user:pass@_jabber._tcp.google.com:80/test',
800    pathname: '/test',
801    path: '/test',
802  },
803
804  'http://x:1/\' <>"`/{}|\\^~`/': {
805    protocol: 'http:',
806    slashes: true,
807    host: 'x:1',
808    port: '1',
809    hostname: 'x',
810    pathname: '/%27%20%3C%3E%22%60/%7B%7D%7C/%5E~%60/',
811    path: '/%27%20%3C%3E%22%60/%7B%7D%7C/%5E~%60/',
812    href: 'http://x:1/%27%20%3C%3E%22%60/%7B%7D%7C/%5E~%60/'
813  },
814
815  'http://a@b@c/': {
816    protocol: 'http:',
817    slashes: true,
818    auth: 'a@b',
819    host: 'c',
820    hostname: 'c',
821    href: 'http://a%40b@c/',
822    path: '/',
823    pathname: '/'
824  },
825
826  'http://a@b?@c': {
827    protocol: 'http:',
828    slashes: true,
829    auth: 'a',
830    host: 'b',
831    hostname: 'b',
832    href: 'http://a@b/?@c',
833    path: '/?@c',
834    pathname: '/',
835    search: '?@c',
836    query: '@c'
837  },
838
839  'http://a.b/\tbc\ndr\ref g"hq\'j<kl>?mn\\op^q=r`99{st|uv}wz': {
840    protocol: 'http:',
841    slashes: true,
842    host: 'a.b',
843    port: null,
844    hostname: 'a.b',
845    hash: null,
846    pathname: '/%09bc%0Adr%0Def%20g%22hq%27j%3Ckl%3E',
847    path: '/%09bc%0Adr%0Def%20g%22hq%27j%3Ckl%3E?mn%5Cop%5Eq=r%6099%7Bst%7Cuv%7Dwz',
848    search: '?mn%5Cop%5Eq=r%6099%7Bst%7Cuv%7Dwz',
849    query: 'mn%5Cop%5Eq=r%6099%7Bst%7Cuv%7Dwz',
850    href: 'http://a.b/%09bc%0Adr%0Def%20g%22hq%27j%3Ckl%3E?mn%5Cop%5Eq=r%6099%7Bst%7Cuv%7Dwz'
851  },
852
853  'http://a\r" \t\n<\'b:b@c\r\nd/e?f': {
854    protocol: 'http:',
855    slashes: true,
856    auth: 'a" <\'b:b',
857    host: 'cd',
858    port: null,
859    hostname: 'cd',
860    hash: null,
861    search: '?f',
862    query: 'f',
863    pathname: '/e',
864    path: '/e?f',
865    href: 'http://a%22%20%3C\'b:b@cd/e?f'
866  },
867
868  // Git urls used by npm
869  'git+ssh://git@github.com:npm/npm': {
870    protocol: 'git+ssh:',
871    slashes: true,
872    auth: 'git',
873    host: 'github.com',
874    port: null,
875    hostname: 'github.com',
876    hash: null,
877    search: null,
878    query: null,
879    pathname: '/:npm/npm',
880    path: '/:npm/npm',
881    href: 'git+ssh://git@github.com/:npm/npm'
882  },
883
884  'https://*': {
885    protocol: 'https:',
886    slashes: true,
887    auth: null,
888    host: '*',
889    port: null,
890    hostname: '*',
891    hash: null,
892    search: null,
893    query: null,
894    pathname: '/',
895    path: '/',
896    href: 'https://*/'
897  },
898
899  // The following two URLs are the same, but they differ for a capital A.
900  // Verify that the protocol is checked in a case-insensitive manner.
901  'javascript:alert(1);a=\x27@white-listed.com\x27': {
902    protocol: 'javascript:',
903    slashes: null,
904    auth: null,
905    host: null,
906    port: null,
907    hostname: null,
908    hash: null,
909    search: null,
910    query: null,
911    pathname: "alert(1);a='@white-listed.com'",
912    path: "alert(1);a='@white-listed.com'",
913    href: "javascript:alert(1);a='@white-listed.com'"
914  },
915
916  'javAscript:alert(1);a=\x27@white-listed.com\x27': {
917    protocol: 'javascript:',
918    slashes: null,
919    auth: null,
920    host: null,
921    port: null,
922    hostname: null,
923    hash: null,
924    search: null,
925    query: null,
926    pathname: "alert(1);a='@white-listed.com'",
927    path: "alert(1);a='@white-listed.com'",
928    href: "javascript:alert(1);a='@white-listed.com'"
929  },
930
931  'ws://www.example.com': {
932    protocol: 'ws:',
933    slashes: true,
934    hostname: 'www.example.com',
935    host: 'www.example.com',
936    pathname: '/',
937    path: '/',
938    href: 'ws://www.example.com/'
939  },
940
941  'wss://www.example.com': {
942    protocol: 'wss:',
943    slashes: true,
944    hostname: 'www.example.com',
945    host: 'www.example.com',
946    pathname: '/',
947    path: '/',
948    href: 'wss://www.example.com/'
949  },
950
951  '//fhqwhgads@example.com/everybody-to-the-limit': {
952    protocol: null,
953    slashes: true,
954    auth: 'fhqwhgads',
955    host: 'example.com',
956    port: null,
957    hostname: 'example.com',
958    hash: null,
959    search: null,
960    query: null,
961    pathname: '/everybody-to-the-limit',
962    path: '/everybody-to-the-limit',
963    href: '//fhqwhgads@example.com/everybody-to-the-limit'
964  },
965
966  '//fhqwhgads@example.com/everybody#to-the-limit': {
967    protocol: null,
968    slashes: true,
969    auth: 'fhqwhgads',
970    host: 'example.com',
971    port: null,
972    hostname: 'example.com',
973    hash: '#to-the-limit',
974    search: null,
975    query: null,
976    pathname: '/everybody',
977    path: '/everybody',
978    href: '//fhqwhgads@example.com/everybody#to-the-limit'
979  },
980
981  '\bhttp://example.com/\b': {
982    protocol: 'http:',
983    slashes: true,
984    auth: null,
985    host: 'example.com',
986    port: null,
987    hostname: 'example.com',
988    hash: null,
989    search: null,
990    query: null,
991    pathname: '/',
992    path: '/',
993    href: 'http://example.com/'
994  },
995
996  'https://evil.com$.example.com': {
997    protocol: 'https:',
998    slashes: true,
999    auth: null,
1000    host: 'evil.com$.example.com',
1001    port: null,
1002    hostname: 'evil.com$.example.com',
1003    hash: null,
1004    search: null,
1005    query: null,
1006    pathname: '/',
1007    path: '/',
1008    href: 'https://evil.com$.example.com/'
1009  },
1010
1011  // Validate the output of hostname with commas.
1012  'x://0.0,1.1/': {
1013    protocol: 'x:',
1014    slashes: true,
1015    auth: null,
1016    host: '0.0,1.1',
1017    port: null,
1018    hostname: '0.0,1.1',
1019    hash: null,
1020    search: null,
1021    query: null,
1022    pathname: '/',
1023    path: '/',
1024    href: 'x://0.0,1.1/'
1025  }
1026};
1027
1028for (const u in parseTests) {
1029  let actual = url.parse(u);
1030  const spaced = url.parse(`     \t  ${u}\n\t`);
1031  let expected = Object.assign(new url.Url(), parseTests[u]);
1032
1033  Object.keys(actual).forEach(function(i) {
1034    if (expected[i] === undefined && actual[i] === null) {
1035      expected[i] = null;
1036    }
1037  });
1038
1039  assert.deepStrictEqual(
1040    actual,
1041    expected,
1042    `parsing ${u} and expected ${inspect(expected)} but got ${inspect(actual)}`
1043  );
1044  assert.deepStrictEqual(
1045    spaced,
1046    expected,
1047    `expected ${inspect(expected)}, got ${inspect(spaced)}`
1048  );
1049
1050  expected = parseTests[u].href;
1051  actual = url.format(parseTests[u]);
1052
1053  assert.strictEqual(actual, expected,
1054                     `format(${u}) == ${u}\nactual:${actual}`);
1055}
1056
1057{
1058  const parsed = url.parse('http://nodejs.org/')
1059    .resolveObject('jAvascript:alert(1);a=\x27@white-listed.com\x27');
1060
1061  const expected = Object.assign(new url.Url(), {
1062    protocol: 'javascript:',
1063    slashes: null,
1064    auth: null,
1065    host: null,
1066    port: null,
1067    hostname: null,
1068    hash: null,
1069    search: null,
1070    query: null,
1071    pathname: "alert(1);a='@white-listed.com'",
1072    path: "alert(1);a='@white-listed.com'",
1073    href: "javascript:alert(1);a='@white-listed.com'"
1074  });
1075
1076  assert.deepStrictEqual(parsed, expected);
1077}
1078