1{
2    "comment": [
3        "## Tests for setters of https://url.spec.whatwg.org/#urlutils-members",
4        "",
5        "This file contains a JSON object.",
6        "Other than 'comment', each key is an attribute of the `URL` interface",
7        "defined in WHATWG’s URL Standard.",
8        "The values are arrays of test case objects for that attribute.",
9        "",
10        "To run a test case for the attribute `attr`:",
11        "",
12        "* Create a new `URL` object with the value for the 'href' key",
13        "  the constructor single parameter. (Without a base URL.)",
14        "  This must not throw.",
15        "* Set the attribute `attr` to (invoke its setter with)",
16        "  with the value of for 'new_value' key.",
17        "* The value for the 'expected' key is another object.",
18        "  For each `key` / `value` pair of that object,",
19        "  get the attribute `key` (invoke its getter).",
20        "  The returned string must be equal to `value`.",
21        "",
22        "Note: the 'href' setter is already covered by urltestdata.json."
23    ],
24    "protocol": [
25        {
26            "comment": "The empty string is not a valid scheme. Setter leaves the URL unchanged.",
27            "href": "a://example.net",
28            "new_value": "",
29            "expected": {
30                "href": "a://example.net",
31                "protocol": "a:"
32            }
33        },
34        {
35            "href": "a://example.net",
36            "new_value": "b",
37            "expected": {
38                "href": "b://example.net",
39                "protocol": "b:"
40            }
41        },
42        {
43            "href": "javascript:alert(1)",
44            "new_value": "defuse",
45            "expected": {
46                "href": "defuse:alert(1)",
47                "protocol": "defuse:"
48            }
49        },
50        {
51            "comment": "Upper-case ASCII is lower-cased",
52            "href": "a://example.net",
53            "new_value": "B",
54            "expected": {
55                "href": "b://example.net",
56                "protocol": "b:"
57            }
58        },
59        {
60            "comment": "Non-ASCII is rejected",
61            "href": "a://example.net",
62            "new_value": "é",
63            "expected": {
64                "href": "a://example.net",
65                "protocol": "a:"
66            }
67        },
68        {
69            "comment": "No leading digit",
70            "href": "a://example.net",
71            "new_value": "0b",
72            "expected": {
73                "href": "a://example.net",
74                "protocol": "a:"
75            }
76        },
77        {
78            "comment": "No leading punctuation",
79            "href": "a://example.net",
80            "new_value": "+b",
81            "expected": {
82                "href": "a://example.net",
83                "protocol": "a:"
84            }
85        },
86        {
87            "href": "a://example.net",
88            "new_value": "bC0+-.",
89            "expected": {
90                "href": "bc0+-.://example.net",
91                "protocol": "bc0+-.:"
92            }
93        },
94        {
95            "comment": "Only some punctuation is acceptable",
96            "href": "a://example.net",
97            "new_value": "b,c",
98            "expected": {
99                "href": "a://example.net",
100                "protocol": "a:"
101            }
102        },
103        {
104            "comment": "Non-ASCII is rejected",
105            "href": "a://example.net",
106            "new_value": "bé",
107            "expected": {
108                "href": "a://example.net",
109                "protocol": "a:"
110            }
111        },
112        {
113            "comment": "Can’t switch from URL containing username/password/port to file",
114            "href": "http://test@example.net",
115            "new_value": "file",
116            "expected": {
117                "href": "http://test@example.net/",
118                "protocol": "http:"
119            }
120        },
121        {
122            "href": "https://example.net:1234",
123            "new_value": "file",
124            "expected": {
125                "href": "https://example.net:1234/",
126                "protocol": "https:"
127            }
128        },
129        {
130            "href": "wss://x:x@example.net:1234",
131            "new_value": "file",
132            "expected": {
133                "href": "wss://x:x@example.net:1234/",
134                "protocol": "wss:"
135            }
136        },
137        {
138            "comment": "Can’t switch from file URL with no host",
139            "href": "file://localhost/",
140            "new_value": "http",
141            "expected": {
142                "href": "file:///",
143                "protocol": "file:"
144            }
145        },
146        {
147            "href": "file:///test",
148            "new_value": "https",
149            "expected": {
150                "href": "file:///test",
151                "protocol": "file:"
152            }
153        },
154        {
155            "href": "file:",
156            "new_value": "wss",
157            "expected": {
158                "href": "file:///",
159                "protocol": "file:"
160            }
161        },
162        {
163            "comment": "Can’t switch from special scheme to non-special",
164            "href": "http://example.net",
165            "new_value": "b",
166            "expected": {
167                "href": "http://example.net/",
168                "protocol": "http:"
169            }
170        },
171        {
172            "href": "file://hi/path",
173            "new_value": "s",
174            "expected": {
175                "href": "file://hi/path",
176                "protocol": "file:"
177            }
178        },
179        {
180            "href": "https://example.net",
181            "new_value": "s",
182            "expected": {
183                "href": "https://example.net/",
184                "protocol": "https:"
185            }
186        },
187        {
188            "href": "ftp://example.net",
189            "new_value": "test",
190            "expected": {
191                "href": "ftp://example.net/",
192                "protocol": "ftp:"
193            }
194        },
195        {
196            "comment": "Cannot-be-a-base URL doesn’t have a host, but URL in a special scheme must.",
197            "href": "mailto:me@example.net",
198            "new_value": "http",
199            "expected": {
200                "href": "mailto:me@example.net",
201                "protocol": "mailto:"
202            }
203        },
204        {
205            "comment": "Can’t switch from non-special scheme to special",
206            "href": "ssh://me@example.net",
207            "new_value": "http",
208            "expected": {
209                "href": "ssh://me@example.net",
210                "protocol": "ssh:"
211            }
212        },
213        {
214            "href": "ssh://me@example.net",
215            "new_value": "https",
216            "expected": {
217                "href": "ssh://me@example.net",
218                "protocol": "ssh:"
219            }
220        },
221        {
222            "href": "ssh://me@example.net",
223            "new_value": "file",
224            "expected": {
225                "href": "ssh://me@example.net",
226                "protocol": "ssh:"
227            }
228        },
229        {
230            "href": "ssh://example.net",
231            "new_value": "file",
232            "expected": {
233                "href": "ssh://example.net",
234                "protocol": "ssh:"
235            }
236        },
237        {
238            "href": "nonsense:///test",
239            "new_value": "https",
240            "expected": {
241                "href": "nonsense:///test",
242                "protocol": "nonsense:"
243            }
244        },
245        {
246            "comment": "Stuff after the first ':' is ignored",
247            "href": "http://example.net",
248            "new_value": "https:foo : bar",
249            "expected": {
250                "href": "https://example.net/",
251                "protocol": "https:"
252            }
253        },
254        {
255            "comment": "Stuff after the first ':' is ignored",
256            "href": "data:text/html,<p>Test",
257            "new_value": "view-source+data:foo : bar",
258            "expected": {
259                "href": "view-source+data:text/html,<p>Test",
260                "protocol": "view-source+data:"
261            }
262        },
263        {
264            "comment": "Port is set to null if it is the default for new scheme.",
265            "href": "http://foo.com:443/",
266            "new_value": "https",
267            "expected": {
268                "href": "https://foo.com/",
269                "protocol": "https:",
270                "port": ""
271            }
272        },
273        {
274            "comment": "Tab and newline are stripped",
275            "href": "http://test/",
276            "new_value": "h\u000D\u000Att\u0009ps",
277            "expected": {
278              "href": "https://test/",
279              "protocol": "https:",
280              "port": ""
281            }
282        },
283        {
284            "href": "http://test/",
285            "new_value": "https\u000D",
286            "expected": {
287              "href": "https://test/",
288              "protocol": "https:"
289            }
290        },
291        {
292            "comment": "Non-tab/newline C0 controls result in no-op",
293            "href": "http://test/",
294            "new_value": "https\u0000",
295            "expected": {
296              "href": "http://test/",
297              "protocol": "http:"
298            }
299        },
300        {
301            "href": "http://test/",
302            "new_value": "https\u000C",
303            "expected": {
304              "href": "http://test/",
305              "protocol": "http:"
306            }
307        },
308        {
309            "href": "http://test/",
310            "new_value": "https\u000E",
311            "expected": {
312              "href": "http://test/",
313              "protocol": "http:"
314            }
315        },
316        {
317            "href": "http://test/",
318            "new_value": "https\u0020",
319            "expected": {
320              "href": "http://test/",
321              "protocol": "http:"
322            }
323        }
324    ],
325    "username": [
326        {
327            "comment": "No host means no username",
328            "href": "file:///home/you/index.html",
329            "new_value": "me",
330            "expected": {
331                "href": "file:///home/you/index.html",
332                "username": ""
333            }
334        },
335        {
336            "comment": "No host means no username",
337            "href": "unix:/run/foo.socket",
338            "new_value": "me",
339            "expected": {
340                "href": "unix:/run/foo.socket",
341                "username": ""
342            }
343        },
344        {
345            "comment": "Cannot-be-a-base means no username",
346            "href": "mailto:you@example.net",
347            "new_value": "me",
348            "expected": {
349                "href": "mailto:you@example.net",
350                "username": ""
351            }
352        },
353        {
354            "href": "javascript:alert(1)",
355            "new_value": "wario",
356            "expected": {
357                "href": "javascript:alert(1)",
358                "username": ""
359            }
360        },
361        {
362            "href": "http://example.net",
363            "new_value": "me",
364            "expected": {
365                "href": "http://me@example.net/",
366                "username": "me"
367            }
368        },
369        {
370            "href": "http://:secret@example.net",
371            "new_value": "me",
372            "expected": {
373                "href": "http://me:secret@example.net/",
374                "username": "me"
375            }
376        },
377        {
378            "href": "http://me@example.net",
379            "new_value": "",
380            "expected": {
381                "href": "http://example.net/",
382                "username": ""
383            }
384        },
385        {
386            "href": "http://me:secret@example.net",
387            "new_value": "",
388            "expected": {
389                "href": "http://:secret@example.net/",
390                "username": ""
391            }
392        },
393        {
394            "comment": "UTF-8 percent encoding with the userinfo encode set.",
395            "href": "http://example.net",
396            "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé",
397            "expected": {
398                "href": "http://%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/",
399                "username": "%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9"
400            }
401        },
402        {
403            "comment": "Bytes already percent-encoded are left as-is.",
404            "href": "http://example.net",
405            "new_value": "%c3%89té",
406            "expected": {
407                "href": "http://%c3%89t%C3%A9@example.net/",
408                "username": "%c3%89t%C3%A9"
409            }
410        },
411        {
412            "href": "sc:///",
413            "new_value": "x",
414            "expected": {
415                "href": "sc:///",
416                "username": ""
417            }
418        },
419        {
420            "href": "javascript://x/",
421            "new_value": "wario",
422            "expected": {
423                "href": "javascript://wario@x/",
424                "username": "wario"
425            }
426        },
427        {
428            "href": "file://test/",
429            "new_value": "test",
430            "expected": {
431                "href": "file://test/",
432                "username": ""
433            }
434        }
435    ],
436    "password": [
437        {
438            "comment": "No host means no password",
439            "href": "file:///home/me/index.html",
440            "new_value": "secret",
441            "expected": {
442                "href": "file:///home/me/index.html",
443                "password": ""
444            }
445        },
446        {
447            "comment": "No host means no password",
448            "href": "unix:/run/foo.socket",
449            "new_value": "secret",
450            "expected": {
451                "href": "unix:/run/foo.socket",
452                "password": ""
453            }
454        },
455        {
456            "comment": "Cannot-be-a-base means no password",
457            "href": "mailto:me@example.net",
458            "new_value": "secret",
459            "expected": {
460                "href": "mailto:me@example.net",
461                "password": ""
462            }
463        },
464        {
465            "href": "http://example.net",
466            "new_value": "secret",
467            "expected": {
468                "href": "http://:secret@example.net/",
469                "password": "secret"
470            }
471        },
472        {
473            "href": "http://me@example.net",
474            "new_value": "secret",
475            "expected": {
476                "href": "http://me:secret@example.net/",
477                "password": "secret"
478            }
479        },
480        {
481            "href": "http://:secret@example.net",
482            "new_value": "",
483            "expected": {
484                "href": "http://example.net/",
485                "password": ""
486            }
487        },
488        {
489            "href": "http://me:secret@example.net",
490            "new_value": "",
491            "expected": {
492                "href": "http://me@example.net/",
493                "password": ""
494            }
495        },
496        {
497            "comment": "UTF-8 percent encoding with the userinfo encode set.",
498            "href": "http://example.net",
499            "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé",
500            "expected": {
501                "href": "http://:%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/",
502                "password": "%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9"
503            }
504        },
505        {
506            "comment": "Bytes already percent-encoded are left as-is.",
507            "href": "http://example.net",
508            "new_value": "%c3%89té",
509            "expected": {
510                "href": "http://:%c3%89t%C3%A9@example.net/",
511                "password": "%c3%89t%C3%A9"
512            }
513        },
514        {
515            "href": "sc:///",
516            "new_value": "x",
517            "expected": {
518                "href": "sc:///",
519                "password": ""
520            }
521        },
522        {
523            "href": "javascript://x/",
524            "new_value": "bowser",
525            "expected": {
526                "href": "javascript://:bowser@x/",
527                "password": "bowser"
528            }
529        },
530        {
531            "href": "file://test/",
532            "new_value": "test",
533            "expected": {
534                "href": "file://test/",
535                "password": ""
536            }
537        }
538    ],
539    "host": [
540        {
541            "comment": "Non-special scheme",
542            "href": "sc://x/",
543            "new_value": "\u0000",
544            "expected": {
545                "href": "sc://x/",
546                "host": "x",
547                "hostname": "x"
548            }
549        },
550        {
551            "href": "sc://x/",
552            "new_value": "\u0009",
553            "expected": {
554                "href": "sc:///",
555                "host": "",
556                "hostname": ""
557            }
558        },
559        {
560            "href": "sc://x/",
561            "new_value": "\u000A",
562            "expected": {
563                "href": "sc:///",
564                "host": "",
565                "hostname": ""
566            }
567        },
568        {
569            "href": "sc://x/",
570            "new_value": "\u000D",
571            "expected": {
572                "href": "sc:///",
573                "host": "",
574                "hostname": ""
575            }
576        },
577        {
578            "href": "sc://x/",
579            "new_value": " ",
580            "expected": {
581                "href": "sc://x/",
582                "host": "x",
583                "hostname": "x"
584            }
585        },
586        {
587            "href": "sc://x/",
588            "new_value": "#",
589            "expected": {
590                "href": "sc:///",
591                "host": "",
592                "hostname": ""
593            }
594        },
595        {
596            "href": "sc://x/",
597            "new_value": "/",
598            "expected": {
599                "href": "sc:///",
600                "host": "",
601                "hostname": ""
602            }
603        },
604        {
605            "href": "sc://x/",
606            "new_value": "?",
607            "expected": {
608                "href": "sc:///",
609                "host": "",
610                "hostname": ""
611            }
612        },
613        {
614            "href": "sc://x/",
615            "new_value": "@",
616            "expected": {
617                "href": "sc://x/",
618                "host": "x",
619                "hostname": "x"
620            }
621        },
622        {
623            "href": "sc://x/",
624            "new_value": "ß",
625            "expected": {
626                "href": "sc://%C3%9F/",
627                "host": "%C3%9F",
628                "hostname": "%C3%9F"
629            }
630        },
631        {
632            "comment": "IDNA Nontransitional_Processing",
633            "href": "https://x/",
634            "new_value": "ß",
635            "expected": {
636                "href": "https://xn--zca/",
637                "host": "xn--zca",
638                "hostname": "xn--zca"
639            }
640        },
641        {
642            "comment": "Cannot-be-a-base means no host",
643            "href": "mailto:me@example.net",
644            "new_value": "example.com",
645            "expected": {
646                "href": "mailto:me@example.net",
647                "host": ""
648            }
649        },
650        {
651            "comment": "Cannot-be-a-base means no host",
652            "href": "data:text/plain,Stuff",
653            "new_value": "example.net",
654            "expected": {
655                "href": "data:text/plain,Stuff",
656                "host": ""
657            }
658        },
659        {
660            "href": "http://example.net",
661            "new_value": "example.com:8080",
662            "expected": {
663                "href": "http://example.com:8080/",
664                "host": "example.com:8080",
665                "hostname": "example.com",
666                "port": "8080"
667            }
668        },
669        {
670            "comment": "Port number is unchanged if not specified in the new value",
671            "href": "http://example.net:8080",
672            "new_value": "example.com",
673            "expected": {
674                "href": "http://example.com:8080/",
675                "host": "example.com:8080",
676                "hostname": "example.com",
677                "port": "8080"
678            }
679        },
680        {
681            "comment": "Port number is unchanged if not specified",
682            "href": "http://example.net:8080",
683            "new_value": "example.com:",
684            "expected": {
685                "href": "http://example.com:8080/",
686                "host": "example.com:8080",
687                "hostname": "example.com",
688                "port": "8080"
689            }
690        },
691        {
692            "comment": "The empty host is not valid for special schemes",
693            "href": "http://example.net",
694            "new_value": "",
695            "expected": {
696                "href": "http://example.net/",
697                "host": "example.net"
698            }
699        },
700        {
701            "comment": "The empty host is OK for non-special schemes",
702            "href": "view-source+http://example.net/foo",
703            "new_value": "",
704            "expected": {
705                "href": "view-source+http:///foo",
706                "host": ""
707            }
708        },
709        {
710            "comment": "Path-only URLs can gain a host",
711            "href": "a:/foo",
712            "new_value": "example.net",
713            "expected": {
714                "href": "a://example.net/foo",
715                "host": "example.net"
716            }
717        },
718        {
719            "comment": "IPv4 address syntax is normalized",
720            "href": "http://example.net",
721            "new_value": "0x7F000001:8080",
722            "expected": {
723                "href": "http://127.0.0.1:8080/",
724                "host": "127.0.0.1:8080",
725                "hostname": "127.0.0.1",
726                "port": "8080"
727            }
728        },
729        {
730            "comment": "IPv6 address syntax is normalized",
731            "href": "http://example.net",
732            "new_value": "[::0:01]:2",
733            "expected": {
734                "href": "http://[::1]:2/",
735                "host": "[::1]:2",
736                "hostname": "[::1]",
737                "port": "2"
738            }
739        },
740        {
741            "comment": "IPv6 literal address with port, crbug.com/1012416",
742            "href": "http://example.net",
743            "new_value": "[2001:db8::2]:4002",
744            "expected": {
745                "href": "http://[2001:db8::2]:4002/",
746                "host": "[2001:db8::2]:4002",
747                "hostname": "[2001:db8::2]",
748                "port": "4002"
749             }
750        },
751        {
752            "comment": "Default port number is removed",
753            "href": "http://example.net",
754            "new_value": "example.com:80",
755            "expected": {
756                "href": "http://example.com/",
757                "host": "example.com",
758                "hostname": "example.com",
759                "port": ""
760            }
761        },
762        {
763            "comment": "Default port number is removed",
764            "href": "https://example.net",
765            "new_value": "example.com:443",
766            "expected": {
767                "href": "https://example.com/",
768                "host": "example.com",
769                "hostname": "example.com",
770                "port": ""
771            }
772        },
773        {
774            "comment": "Default port number is only removed for the relevant scheme",
775            "href": "https://example.net",
776            "new_value": "example.com:80",
777            "expected": {
778                "href": "https://example.com:80/",
779                "host": "example.com:80",
780                "hostname": "example.com",
781                "port": "80"
782            }
783        },
784        {
785            "comment": "Port number is removed if new port is scheme default and existing URL has a non-default port",
786            "href": "http://example.net:8080",
787            "new_value": "example.com:80",
788            "expected": {
789                "href": "http://example.com/",
790                "host": "example.com",
791                "hostname": "example.com",
792                "port": ""
793            }
794        },
795        {
796            "comment": "Stuff after a / delimiter is ignored",
797            "href": "http://example.net/path",
798            "new_value": "example.com/stuff",
799            "expected": {
800                "href": "http://example.com/path",
801                "host": "example.com",
802                "hostname": "example.com",
803                "port": ""
804            }
805        },
806        {
807            "comment": "Stuff after a / delimiter is ignored",
808            "href": "http://example.net/path",
809            "new_value": "example.com:8080/stuff",
810            "expected": {
811                "href": "http://example.com:8080/path",
812                "host": "example.com:8080",
813                "hostname": "example.com",
814                "port": "8080"
815            }
816        },
817        {
818            "comment": "Stuff after a ? delimiter is ignored",
819            "href": "http://example.net/path",
820            "new_value": "example.com?stuff",
821            "expected": {
822                "href": "http://example.com/path",
823                "host": "example.com",
824                "hostname": "example.com",
825                "port": ""
826            }
827        },
828        {
829            "comment": "Stuff after a ? delimiter is ignored",
830            "href": "http://example.net/path",
831            "new_value": "example.com:8080?stuff",
832            "expected": {
833                "href": "http://example.com:8080/path",
834                "host": "example.com:8080",
835                "hostname": "example.com",
836                "port": "8080"
837            }
838        },
839        {
840            "comment": "Stuff after a # delimiter is ignored",
841            "href": "http://example.net/path",
842            "new_value": "example.com#stuff",
843            "expected": {
844                "href": "http://example.com/path",
845                "host": "example.com",
846                "hostname": "example.com",
847                "port": ""
848            }
849        },
850        {
851            "comment": "Stuff after a # delimiter is ignored",
852            "href": "http://example.net/path",
853            "new_value": "example.com:8080#stuff",
854            "expected": {
855                "href": "http://example.com:8080/path",
856                "host": "example.com:8080",
857                "hostname": "example.com",
858                "port": "8080"
859            }
860        },
861        {
862            "comment": "Stuff after a \\ delimiter is ignored for special schemes",
863            "href": "http://example.net/path",
864            "new_value": "example.com\\stuff",
865            "expected": {
866                "href": "http://example.com/path",
867                "host": "example.com",
868                "hostname": "example.com",
869                "port": ""
870            }
871        },
872        {
873            "comment": "Stuff after a \\ delimiter is ignored for special schemes",
874            "href": "http://example.net/path",
875            "new_value": "example.com:8080\\stuff",
876            "expected": {
877                "href": "http://example.com:8080/path",
878                "host": "example.com:8080",
879                "hostname": "example.com",
880                "port": "8080"
881            }
882        },
883        {
884            "comment": "\\ is not a delimiter for non-special schemes, but still forbidden in hosts",
885            "href": "view-source+http://example.net/path",
886            "new_value": "example.com\\stuff",
887            "expected": {
888                "href": "view-source+http://example.net/path",
889                "host": "example.net",
890                "hostname": "example.net",
891                "port": ""
892            }
893        },
894        {
895            "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error",
896            "href": "view-source+http://example.net/path",
897            "new_value": "example.com:8080stuff2",
898            "expected": {
899                "href": "view-source+http://example.com:8080/path",
900                "host": "example.com:8080",
901                "hostname": "example.com",
902                "port": "8080"
903            }
904        },
905        {
906            "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error",
907            "href": "http://example.net/path",
908            "new_value": "example.com:8080stuff2",
909            "expected": {
910                "href": "http://example.com:8080/path",
911                "host": "example.com:8080",
912                "hostname": "example.com",
913                "port": "8080"
914            }
915        },
916        {
917            "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error",
918            "href": "http://example.net/path",
919            "new_value": "example.com:8080+2",
920            "expected": {
921                "href": "http://example.com:8080/path",
922                "host": "example.com:8080",
923                "hostname": "example.com",
924                "port": "8080"
925            }
926        },
927        {
928            "comment": "Port numbers are 16 bit integers",
929            "href": "http://example.net/path",
930            "new_value": "example.com:65535",
931            "expected": {
932                "href": "http://example.com:65535/path",
933                "host": "example.com:65535",
934                "hostname": "example.com",
935                "port": "65535"
936            }
937        },
938        {
939            "comment": "Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though.",
940            "href": "http://example.net/path",
941            "new_value": "example.com:65536",
942            "expected": {
943                "href": "http://example.com/path",
944                "host": "example.com",
945                "hostname": "example.com",
946                "port": ""
947            }
948        },
949        {
950            "comment": "Broken IPv6",
951            "href": "http://example.net/",
952            "new_value": "[google.com]",
953            "expected": {
954                "href": "http://example.net/",
955                "host": "example.net",
956                "hostname": "example.net"
957            }
958        },
959        {
960            "href": "http://example.net/",
961            "new_value": "[::1.2.3.4x]",
962            "expected": {
963                "href": "http://example.net/",
964                "host": "example.net",
965                "hostname": "example.net"
966            }
967        },
968        {
969            "href": "http://example.net/",
970            "new_value": "[::1.2.3.]",
971            "expected": {
972                "href": "http://example.net/",
973                "host": "example.net",
974                "hostname": "example.net"
975            }
976        },
977        {
978            "href": "http://example.net/",
979            "new_value": "[::1.2.]",
980            "expected": {
981                "href": "http://example.net/",
982                "host": "example.net",
983                "hostname": "example.net"
984            }
985        },
986        {
987            "href": "http://example.net/",
988            "new_value": "[::1.]",
989            "expected": {
990                "href": "http://example.net/",
991                "host": "example.net",
992                "hostname": "example.net"
993            }
994        },
995        {
996            "href": "file://y/",
997            "new_value": "x:123",
998            "expected": {
999                "href": "file://y/",
1000                "host": "y",
1001                "hostname": "y",
1002                "port": ""
1003            }
1004        },
1005        {
1006            "href": "file://y/",
1007            "new_value": "loc%41lhost",
1008            "expected": {
1009                "href": "file:///",
1010                "host": "",
1011                "hostname": "",
1012                "port": ""
1013            }
1014        },
1015        {
1016            "href": "file://hi/x",
1017            "new_value": "",
1018            "expected": {
1019                "href": "file:///x",
1020                "host": "",
1021                "hostname": "",
1022                "port": ""
1023            }
1024        },
1025        {
1026            "href": "sc://test@test/",
1027            "new_value": "",
1028            "expected": {
1029                "href": "sc://test@test/",
1030                "host": "test",
1031                "hostname": "test",
1032                "username": "test"
1033            }
1034        },
1035        {
1036            "href": "sc://test:12/",
1037            "new_value": "",
1038            "expected": {
1039                "href": "sc://test:12/",
1040                "host": "test:12",
1041                "hostname": "test",
1042                "port": "12"
1043            }
1044        },
1045        {
1046            "comment": "Leading / is not stripped",
1047            "href": "http://example.com/",
1048            "new_value": "///bad.com",
1049            "expected": {
1050                "href": "http://example.com/",
1051                "host": "example.com",
1052                "hostname": "example.com"
1053            }
1054        },
1055        {
1056            "comment": "Leading / is not stripped",
1057            "href": "sc://example.com/",
1058            "new_value": "///bad.com",
1059            "expected": {
1060                "href": "sc:///",
1061                "host": "",
1062                "hostname": ""
1063            }
1064        },
1065        {
1066            "href": "https://example.com/",
1067            "new_value": "a%C2%ADb",
1068            "expected": {
1069                "href": "https://ab/",
1070                "host": "ab",
1071                "hostname": "ab"
1072            }
1073        },
1074        {
1075            "href": "https://example.com/",
1076            "new_value": "\u00AD",
1077            "expected": {
1078                "href": "https://example.com/",
1079                "host": "example.com",
1080                "hostname": "example.com"
1081            }
1082        },
1083        {
1084            "href": "https://example.com/",
1085            "new_value": "%C2%AD",
1086            "expected": {
1087                "href": "https://example.com/",
1088                "host": "example.com",
1089                "hostname": "example.com"
1090            }
1091        },
1092        {
1093            "href": "https://example.com/",
1094            "new_value": "xn--",
1095            "expected": {
1096                "href": "https://example.com/",
1097                "host": "example.com",
1098                "hostname": "example.com"
1099            }
1100        }
1101    ],
1102    "hostname": [
1103        {
1104            "comment": "Non-special scheme",
1105            "href": "sc://x/",
1106            "new_value": "\u0000",
1107            "expected": {
1108                "href": "sc://x/",
1109                "host": "x",
1110                "hostname": "x"
1111            }
1112        },
1113        {
1114            "href": "sc://x/",
1115            "new_value": "\u0009",
1116            "expected": {
1117                "href": "sc:///",
1118                "host": "",
1119                "hostname": ""
1120            }
1121        },
1122        {
1123            "href": "sc://x/",
1124            "new_value": "\u000A",
1125            "expected": {
1126                "href": "sc:///",
1127                "host": "",
1128                "hostname": ""
1129            }
1130        },
1131        {
1132            "href": "sc://x/",
1133            "new_value": "\u000D",
1134            "expected": {
1135                "href": "sc:///",
1136                "host": "",
1137                "hostname": ""
1138            }
1139        },
1140        {
1141            "href": "sc://x/",
1142            "new_value": " ",
1143            "expected": {
1144                "href": "sc://x/",
1145                "host": "x",
1146                "hostname": "x"
1147            }
1148        },
1149        {
1150            "href": "sc://x/",
1151            "new_value": "#",
1152            "expected": {
1153                "href": "sc:///",
1154                "host": "",
1155                "hostname": ""
1156            }
1157        },
1158        {
1159            "href": "sc://x/",
1160            "new_value": "/",
1161            "expected": {
1162                "href": "sc:///",
1163                "host": "",
1164                "hostname": ""
1165            }
1166        },
1167        {
1168            "href": "sc://x/",
1169            "new_value": "?",
1170            "expected": {
1171                "href": "sc:///",
1172                "host": "",
1173                "hostname": ""
1174            }
1175        },
1176        {
1177            "href": "sc://x/",
1178            "new_value": "@",
1179            "expected": {
1180                "href": "sc://x/",
1181                "host": "x",
1182                "hostname": "x"
1183            }
1184        },
1185        {
1186            "comment": "Cannot-be-a-base means no host",
1187            "href": "mailto:me@example.net",
1188            "new_value": "example.com",
1189            "expected": {
1190                "href": "mailto:me@example.net",
1191                "host": ""
1192            }
1193        },
1194        {
1195            "comment": "Cannot-be-a-base means no host",
1196            "href": "data:text/plain,Stuff",
1197            "new_value": "example.net",
1198            "expected": {
1199                "href": "data:text/plain,Stuff",
1200                "host": ""
1201            }
1202        },
1203        {
1204            "href": "http://example.net:8080",
1205            "new_value": "example.com",
1206            "expected": {
1207                "href": "http://example.com:8080/",
1208                "host": "example.com:8080",
1209                "hostname": "example.com",
1210                "port": "8080"
1211            }
1212        },
1213        {
1214            "comment": "The empty host is not valid for special schemes",
1215            "href": "http://example.net",
1216            "new_value": "",
1217            "expected": {
1218                "href": "http://example.net/",
1219                "host": "example.net"
1220            }
1221        },
1222        {
1223            "comment": "The empty host is OK for non-special schemes",
1224            "href": "view-source+http://example.net/foo",
1225            "new_value": "",
1226            "expected": {
1227                "href": "view-source+http:///foo",
1228                "host": ""
1229            }
1230        },
1231        {
1232            "comment": "Path-only URLs can gain a host",
1233            "href": "a:/foo",
1234            "new_value": "example.net",
1235            "expected": {
1236                "href": "a://example.net/foo",
1237                "host": "example.net"
1238            }
1239        },
1240        {
1241            "comment": "IPv4 address syntax is normalized",
1242            "href": "http://example.net:8080",
1243            "new_value": "0x7F000001",
1244            "expected": {
1245                "href": "http://127.0.0.1:8080/",
1246                "host": "127.0.0.1:8080",
1247                "hostname": "127.0.0.1",
1248                "port": "8080"
1249            }
1250        },
1251        {
1252            "comment": "IPv6 address syntax is normalized",
1253            "href": "http://example.net",
1254            "new_value": "[::0:01]",
1255            "expected": {
1256                "href": "http://[::1]/",
1257                "host": "[::1]",
1258                "hostname": "[::1]",
1259                "port": ""
1260            }
1261        },
1262        {
1263            "comment": ": delimiter invalidates entire value",
1264            "href": "http://example.net/path",
1265            "new_value": "example.com:8080",
1266            "expected": {
1267                "href": "http://example.net/path",
1268                "host": "example.net",
1269                "hostname": "example.net",
1270                "port": ""
1271            }
1272        },
1273        {
1274            "comment": ": delimiter invalidates entire value",
1275            "href": "http://example.net:8080/path",
1276            "new_value": "example.com:",
1277            "expected": {
1278                "href": "http://example.net:8080/path",
1279                "host": "example.net:8080",
1280                "hostname": "example.net",
1281                "port": "8080"
1282            }
1283        },
1284        {
1285            "comment": "Stuff after a / delimiter is ignored",
1286            "href": "http://example.net/path",
1287            "new_value": "example.com/stuff",
1288            "expected": {
1289                "href": "http://example.com/path",
1290                "host": "example.com",
1291                "hostname": "example.com",
1292                "port": ""
1293            }
1294        },
1295        {
1296            "comment": "Stuff after a ? delimiter is ignored",
1297            "href": "http://example.net/path",
1298            "new_value": "example.com?stuff",
1299            "expected": {
1300                "href": "http://example.com/path",
1301                "host": "example.com",
1302                "hostname": "example.com",
1303                "port": ""
1304            }
1305        },
1306        {
1307            "comment": "Stuff after a # delimiter is ignored",
1308            "href": "http://example.net/path",
1309            "new_value": "example.com#stuff",
1310            "expected": {
1311                "href": "http://example.com/path",
1312                "host": "example.com",
1313                "hostname": "example.com",
1314                "port": ""
1315            }
1316        },
1317        {
1318            "comment": "Stuff after a \\ delimiter is ignored for special schemes",
1319            "href": "http://example.net/path",
1320            "new_value": "example.com\\stuff",
1321            "expected": {
1322                "href": "http://example.com/path",
1323                "host": "example.com",
1324                "hostname": "example.com",
1325                "port": ""
1326            }
1327        },
1328        {
1329            "comment": "\\ is not a delimiter for non-special schemes, but still forbidden in hosts",
1330            "href": "view-source+http://example.net/path",
1331            "new_value": "example.com\\stuff",
1332            "expected": {
1333                "href": "view-source+http://example.net/path",
1334                "host": "example.net",
1335                "hostname": "example.net",
1336                "port": ""
1337            }
1338        },
1339        {
1340            "comment": "Broken IPv6",
1341            "href": "http://example.net/",
1342            "new_value": "[google.com]",
1343            "expected": {
1344                "href": "http://example.net/",
1345                "host": "example.net",
1346                "hostname": "example.net"
1347            }
1348        },
1349        {
1350            "href": "http://example.net/",
1351            "new_value": "[::1.2.3.4x]",
1352            "expected": {
1353                "href": "http://example.net/",
1354                "host": "example.net",
1355                "hostname": "example.net"
1356            }
1357        },
1358        {
1359            "href": "http://example.net/",
1360            "new_value": "[::1.2.3.]",
1361            "expected": {
1362                "href": "http://example.net/",
1363                "host": "example.net",
1364                "hostname": "example.net"
1365            }
1366        },
1367        {
1368            "href": "http://example.net/",
1369            "new_value": "[::1.2.]",
1370            "expected": {
1371                "href": "http://example.net/",
1372                "host": "example.net",
1373                "hostname": "example.net"
1374            }
1375        },
1376        {
1377            "href": "http://example.net/",
1378            "new_value": "[::1.]",
1379            "expected": {
1380                "href": "http://example.net/",
1381                "host": "example.net",
1382                "hostname": "example.net"
1383            }
1384        },
1385        {
1386            "href": "file://y/",
1387            "new_value": "x:123",
1388            "expected": {
1389                "href": "file://y/",
1390                "host": "y",
1391                "hostname": "y",
1392                "port": ""
1393            }
1394        },
1395        {
1396            "href": "file://y/",
1397            "new_value": "loc%41lhost",
1398            "expected": {
1399                "href": "file:///",
1400                "host": "",
1401                "hostname": "",
1402                "port": ""
1403            }
1404        },
1405        {
1406            "href": "file://hi/x",
1407            "new_value": "",
1408            "expected": {
1409                "href": "file:///x",
1410                "host": "",
1411                "hostname": "",
1412                "port": ""
1413            }
1414        },
1415        {
1416            "href": "sc://test@test/",
1417            "new_value": "",
1418            "expected": {
1419                "href": "sc://test@test/",
1420                "host": "test",
1421                "hostname": "test",
1422                "username": "test"
1423            }
1424        },
1425        {
1426            "href": "sc://test:12/",
1427            "new_value": "",
1428            "expected": {
1429                "href": "sc://test:12/",
1430                "host": "test:12",
1431                "hostname": "test",
1432                "port": "12"
1433            }
1434        },
1435        {
1436            "comment": "Drop /. from path",
1437            "href": "non-spec:/.//p",
1438            "new_value": "h",
1439            "expected": {
1440                "href": "non-spec://h//p",
1441                "host": "h",
1442                "hostname": "h",
1443                "pathname": "//p"
1444            }
1445        },
1446        {
1447            "href": "non-spec:/.//p",
1448            "new_value": "",
1449            "expected": {
1450                "href": "non-spec:////p",
1451                "host": "",
1452                "hostname": "",
1453                "pathname": "//p"
1454            }
1455        },
1456        {
1457            "comment": "Leading / is not stripped",
1458            "href": "http://example.com/",
1459            "new_value": "///bad.com",
1460            "expected": {
1461                "href": "http://example.com/",
1462                "host": "example.com",
1463                "hostname": "example.com"
1464            }
1465        },
1466        {
1467            "comment": "Leading / is not stripped",
1468            "href": "sc://example.com/",
1469            "new_value": "///bad.com",
1470            "expected": {
1471                "href": "sc:///",
1472                "host": "",
1473                "hostname": ""
1474            }
1475        },
1476        {
1477            "href": "https://example.com/",
1478            "new_value": "a%C2%ADb",
1479            "expected": {
1480                "href": "https://ab/",
1481                "host": "ab",
1482                "hostname": "ab"
1483            }
1484        },
1485        {
1486            "href": "https://example.com/",
1487            "new_value": "\u00AD",
1488            "expected": {
1489                "href": "https://example.com/",
1490                "host": "example.com",
1491                "hostname": "example.com"
1492            }
1493        },
1494        {
1495            "href": "https://example.com/",
1496            "new_value": "%C2%AD",
1497            "expected": {
1498                "href": "https://example.com/",
1499                "host": "example.com",
1500                "hostname": "example.com"
1501            }
1502        },
1503        {
1504            "href": "https://example.com/",
1505            "new_value": "xn--",
1506            "expected": {
1507                "href": "https://example.com/",
1508                "host": "example.com",
1509                "hostname": "example.com"
1510            }
1511        }
1512    ],
1513    "port": [
1514        {
1515            "href": "http://example.net",
1516            "new_value": "8080",
1517            "expected": {
1518                "href": "http://example.net:8080/",
1519                "host": "example.net:8080",
1520                "hostname": "example.net",
1521                "port": "8080"
1522            }
1523        },
1524        {
1525            "comment": "Port number is removed if empty is the new value",
1526            "href": "http://example.net:8080",
1527            "new_value": "",
1528            "expected": {
1529                "href": "http://example.net/",
1530                "host": "example.net",
1531                "hostname": "example.net",
1532                "port": ""
1533            }
1534        },
1535        {
1536            "comment": "Default port number is removed",
1537            "href": "http://example.net:8080",
1538            "new_value": "80",
1539            "expected": {
1540                "href": "http://example.net/",
1541                "host": "example.net",
1542                "hostname": "example.net",
1543                "port": ""
1544            }
1545        },
1546        {
1547            "comment": "Default port number is removed",
1548            "href": "https://example.net:4433",
1549            "new_value": "443",
1550            "expected": {
1551                "href": "https://example.net/",
1552                "host": "example.net",
1553                "hostname": "example.net",
1554                "port": ""
1555            }
1556        },
1557        {
1558            "comment": "Default port number is only removed for the relevant scheme",
1559            "href": "https://example.net",
1560            "new_value": "80",
1561            "expected": {
1562                "href": "https://example.net:80/",
1563                "host": "example.net:80",
1564                "hostname": "example.net",
1565                "port": "80"
1566            }
1567        },
1568        {
1569            "comment": "Stuff after a / delimiter is ignored",
1570            "href": "http://example.net/path",
1571            "new_value": "8080/stuff",
1572            "expected": {
1573                "href": "http://example.net:8080/path",
1574                "host": "example.net:8080",
1575                "hostname": "example.net",
1576                "port": "8080"
1577            }
1578        },
1579        {
1580            "comment": "Stuff after a ? delimiter is ignored",
1581            "href": "http://example.net/path",
1582            "new_value": "8080?stuff",
1583            "expected": {
1584                "href": "http://example.net:8080/path",
1585                "host": "example.net:8080",
1586                "hostname": "example.net",
1587                "port": "8080"
1588            }
1589        },
1590        {
1591            "comment": "Stuff after a # delimiter is ignored",
1592            "href": "http://example.net/path",
1593            "new_value": "8080#stuff",
1594            "expected": {
1595                "href": "http://example.net:8080/path",
1596                "host": "example.net:8080",
1597                "hostname": "example.net",
1598                "port": "8080"
1599            }
1600        },
1601        {
1602            "comment": "Stuff after a \\ delimiter is ignored for special schemes",
1603            "href": "http://example.net/path",
1604            "new_value": "8080\\stuff",
1605            "expected": {
1606                "href": "http://example.net:8080/path",
1607                "host": "example.net:8080",
1608                "hostname": "example.net",
1609                "port": "8080"
1610            }
1611        },
1612        {
1613            "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error",
1614            "href": "view-source+http://example.net/path",
1615            "new_value": "8080stuff2",
1616            "expected": {
1617                "href": "view-source+http://example.net:8080/path",
1618                "host": "example.net:8080",
1619                "hostname": "example.net",
1620                "port": "8080"
1621            }
1622        },
1623        {
1624            "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error",
1625            "href": "http://example.net/path",
1626            "new_value": "8080stuff2",
1627            "expected": {
1628                "href": "http://example.net:8080/path",
1629                "host": "example.net:8080",
1630                "hostname": "example.net",
1631                "port": "8080"
1632            }
1633        },
1634        {
1635            "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error",
1636            "href": "http://example.net/path",
1637            "new_value": "8080+2",
1638            "expected": {
1639                "href": "http://example.net:8080/path",
1640                "host": "example.net:8080",
1641                "hostname": "example.net",
1642                "port": "8080"
1643            }
1644        },
1645        {
1646            "comment": "Port numbers are 16 bit integers",
1647            "href": "http://example.net/path",
1648            "new_value": "65535",
1649            "expected": {
1650                "href": "http://example.net:65535/path",
1651                "host": "example.net:65535",
1652                "hostname": "example.net",
1653                "port": "65535"
1654            }
1655        },
1656        {
1657            "comment": "Port numbers are 16 bit integers, overflowing is an error",
1658            "href": "http://example.net:8080/path",
1659            "new_value": "65536",
1660            "expected": {
1661                "href": "http://example.net:8080/path",
1662                "host": "example.net:8080",
1663                "hostname": "example.net",
1664                "port": "8080"
1665            }
1666        },
1667        {
1668            "comment": "Setting port to a string that doesn't parse as a number",
1669            "href": "http://example.net:8080/path",
1670            "new_value": "randomstring",
1671            "expected": {
1672                "href": "http://example.net:8080/path",
1673                "host": "example.net:8080",
1674                "hostname": "example.net",
1675                "port": "8080"
1676            }
1677        },
1678        {
1679            "comment": "Port numbers are 16 bit integers, overflowing is an error",
1680            "href": "non-special://example.net:8080/path",
1681            "new_value": "65536",
1682            "expected": {
1683                "href": "non-special://example.net:8080/path",
1684                "host": "example.net:8080",
1685                "hostname": "example.net",
1686                "port": "8080"
1687            }
1688        },
1689        {
1690            "href": "file://test/",
1691            "new_value": "12",
1692            "expected": {
1693                "href": "file://test/",
1694                "port": ""
1695            }
1696        },
1697        {
1698            "href": "file://localhost/",
1699            "new_value": "12",
1700            "expected": {
1701                "href": "file:///",
1702                "port": ""
1703            }
1704        },
1705        {
1706            "href": "non-base:value",
1707            "new_value": "12",
1708            "expected": {
1709                "href": "non-base:value",
1710                "port": ""
1711            }
1712        },
1713        {
1714            "href": "sc:///",
1715            "new_value": "12",
1716            "expected": {
1717                "href": "sc:///",
1718                "port": ""
1719            }
1720        },
1721        {
1722            "href": "sc://x/",
1723            "new_value": "12",
1724            "expected": {
1725                "href": "sc://x:12/",
1726                "port": "12"
1727            }
1728        },
1729        {
1730            "href": "javascript://x/",
1731            "new_value": "12",
1732            "expected": {
1733                "href": "javascript://x:12/",
1734                "port": "12"
1735            }
1736        },
1737        {
1738            "comment": "Leading u0009 on special scheme",
1739            "href": "https://domain.com:443",
1740            "new_value": "\u00098080",
1741            "expected": {
1742                "port": "8080"
1743            }
1744        },
1745        {
1746            "comment": "Leading u0009 on non-special scheme",
1747            "href": "wpt++://domain.com:443",
1748            "new_value": "\u00098080",
1749            "expected": {
1750                "port": "8080"
1751            }
1752        },
1753        {
1754            "comment": "Should use all ascii prefixed characters as port",
1755            "href": "https://www.google.com:4343",
1756            "new_value": "4wpt",
1757            "expected": {
1758                "port": "4"
1759            }
1760        }
1761    ],
1762    "pathname": [
1763        {
1764            "comment": "Opaque paths cannot be set",
1765            "href": "mailto:me@example.net",
1766            "new_value": "/foo",
1767            "expected": {
1768                "href": "mailto:me@example.net",
1769                "pathname": "me@example.net"
1770            }
1771        },
1772        {
1773            "href": "data:original",
1774            "new_value": "new value",
1775            "expected": {
1776                "href": "data:original",
1777                "pathname": "original"
1778            }
1779        },
1780        {
1781            "href": "sc:original",
1782            "new_value": "new value",
1783            "expected": {
1784                "href": "sc:original",
1785                "pathname": "original"
1786            }
1787        },
1788        {
1789            "comment": "Special URLs cannot have their paths erased",
1790            "href": "file:///some/path",
1791            "new_value": "",
1792            "expected": {
1793                "href": "file:///",
1794                "pathname": "/"
1795            }
1796        },
1797        {
1798            "comment": "Non-special URLs can have their paths erased",
1799            "href": "foo://somehost/some/path",
1800            "new_value": "",
1801            "expected": {
1802                "href": "foo://somehost",
1803                "pathname": ""
1804            }
1805        },
1806        {
1807            "comment": "Non-special URLs with an empty host can have their paths erased",
1808            "href": "foo:///some/path",
1809            "new_value": "",
1810            "expected": {
1811                "href": "foo://",
1812                "pathname": ""
1813            }
1814        },
1815        {
1816            "comment": "Path-only URLs cannot have their paths erased",
1817            "href": "foo:/some/path",
1818            "new_value": "",
1819            "expected": {
1820                "href": "foo:/",
1821                "pathname": "/"
1822            }
1823        },
1824        {
1825            "comment": "Path-only URLs always have an initial slash",
1826            "href": "foo:/some/path",
1827            "new_value": "test",
1828            "expected": {
1829                "href": "foo:/test",
1830                "pathname": "/test"
1831            }
1832        },
1833        {
1834            "href": "unix:/run/foo.socket?timeout=10",
1835            "new_value": "/var/log/../run/bar.socket",
1836            "expected": {
1837                "href": "unix:/var/run/bar.socket?timeout=10",
1838                "pathname": "/var/run/bar.socket"
1839            }
1840        },
1841        {
1842            "href": "https://example.net#nav",
1843            "new_value": "home",
1844            "expected": {
1845                "href": "https://example.net/home#nav",
1846                "pathname": "/home"
1847            }
1848        },
1849        {
1850            "href": "https://example.net#nav",
1851            "new_value": "../home",
1852            "expected": {
1853                "href": "https://example.net/home#nav",
1854                "pathname": "/home"
1855            }
1856        },
1857        {
1858            "comment": "\\ is a segment delimiter for 'special' URLs",
1859            "href": "http://example.net/home?lang=fr#nav",
1860            "new_value": "\\a\\%2E\\b\\%2e.\\c",
1861            "expected": {
1862                "href": "http://example.net/a/c?lang=fr#nav",
1863                "pathname": "/a/c"
1864            }
1865        },
1866        {
1867            "comment": "\\ is *not* a segment delimiter for non-'special' URLs",
1868            "href": "view-source+http://example.net/home?lang=fr#nav",
1869            "new_value": "\\a\\%2E\\b\\%2e.\\c",
1870            "expected": {
1871                "href": "view-source+http://example.net/\\a\\%2E\\b\\%2e.\\c?lang=fr#nav",
1872                "pathname": "/\\a\\%2E\\b\\%2e.\\c"
1873            }
1874        },
1875        {
1876            "comment": "UTF-8 percent encoding with the default encode set. Tabs and newlines are removed.",
1877            "href": "a:/",
1878            "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé",
1879            "expected": {
1880                "href": "a:/%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E%3F@AZ[\\]^_%60az%7B|%7D~%7F%C2%80%C2%81%C3%89%C3%A9",
1881                "pathname": "/%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E%3F@AZ[\\]^_%60az%7B|%7D~%7F%C2%80%C2%81%C3%89%C3%A9"
1882            }
1883        },
1884        {
1885            "comment": "Bytes already percent-encoded are left as-is, including %2E outside dotted segments.",
1886            "href": "http://example.net",
1887            "new_value": "%2e%2E%c3%89té",
1888            "expected": {
1889                "href": "http://example.net/%2e%2E%c3%89t%C3%A9",
1890                "pathname": "/%2e%2E%c3%89t%C3%A9"
1891            }
1892        },
1893        {
1894            "comment": "? needs to be encoded",
1895            "href": "http://example.net",
1896            "new_value": "?",
1897            "expected": {
1898                "href": "http://example.net/%3F",
1899                "pathname": "/%3F"
1900            }
1901        },
1902        {
1903            "comment": "# needs to be encoded",
1904            "href": "http://example.net",
1905            "new_value": "#",
1906            "expected": {
1907                "href": "http://example.net/%23",
1908                "pathname": "/%23"
1909            }
1910        },
1911        {
1912            "comment": "? needs to be encoded, non-special scheme",
1913            "href": "sc://example.net",
1914            "new_value": "?",
1915            "expected": {
1916                "href": "sc://example.net/%3F",
1917                "pathname": "/%3F"
1918            }
1919        },
1920        {
1921            "comment": "# needs to be encoded, non-special scheme",
1922            "href": "sc://example.net",
1923            "new_value": "#",
1924            "expected": {
1925                "href": "sc://example.net/%23",
1926                "pathname": "/%23"
1927            }
1928        },
1929        {
1930            "comment": "? doesn't mess up encoding",
1931            "href": "http://example.net",
1932            "new_value": "/?é",
1933            "expected": {
1934                "href": "http://example.net/%3F%C3%A9",
1935                "pathname": "/%3F%C3%A9"
1936            }
1937        },
1938        {
1939            "comment": "# doesn't mess up encoding",
1940            "href": "http://example.net",
1941            "new_value": "/#é",
1942            "expected": {
1943                "href": "http://example.net/%23%C3%A9",
1944                "pathname": "/%23%C3%A9"
1945            }
1946        },
1947        {
1948            "comment": "File URLs and (back)slashes",
1949            "href": "file://monkey/",
1950            "new_value": "\\\\",
1951            "expected": {
1952                "href": "file://monkey//",
1953                "pathname": "//"
1954            }
1955        },
1956        {
1957            "comment": "File URLs and (back)slashes",
1958            "href": "file:///unicorn",
1959            "new_value": "//\\/",
1960            "expected": {
1961                "href": "file://////",
1962                "pathname": "////"
1963            }
1964        },
1965        {
1966            "comment": "File URLs and (back)slashes",
1967            "href": "file:///unicorn",
1968            "new_value": "//monkey/..//",
1969            "expected": {
1970                "href": "file://///",
1971                "pathname": "///"
1972            }
1973        },
1974        {
1975            "comment": "Serialize /. in path",
1976            "href": "non-spec:/",
1977            "new_value": "/.//p",
1978            "expected": {
1979                "href": "non-spec:/.//p",
1980                "pathname": "//p"
1981            }
1982        },
1983        {
1984            "href": "non-spec:/",
1985            "new_value": "/..//p",
1986            "expected": {
1987                "href": "non-spec:/.//p",
1988                "pathname": "//p"
1989            }
1990        },
1991        {
1992            "href": "non-spec:/",
1993            "new_value": "//p",
1994            "expected": {
1995                "href": "non-spec:/.//p",
1996                "pathname": "//p"
1997            }
1998        },
1999        {
2000            "comment": "Drop /. from path",
2001            "href": "non-spec:/.//",
2002            "new_value": "p",
2003            "expected": {
2004                "href": "non-spec:/p",
2005                "pathname": "/p"
2006            }
2007        },
2008        {
2009            "comment": "Non-special URLs with non-opaque paths percent-encode U+0020",
2010            "href": "data:/nospace",
2011            "new_value": "space ",
2012            "expected": {
2013                "href": "data:/space%20",
2014                "pathname": "/space%20"
2015            }
2016        },
2017        {
2018            "href": "sc:/nospace",
2019            "new_value": "space ",
2020            "expected": {
2021                "href": "sc:/space%20",
2022                "pathname": "/space%20"
2023            }
2024        }
2025    ],
2026    "search": [
2027        {
2028            "href": "https://example.net#nav",
2029            "new_value": "lang=fr",
2030            "expected": {
2031                "href": "https://example.net/?lang=fr#nav",
2032                "search": "?lang=fr"
2033            }
2034        },
2035        {
2036            "href": "https://example.net?lang=en-US#nav",
2037            "new_value": "lang=fr",
2038            "expected": {
2039                "href": "https://example.net/?lang=fr#nav",
2040                "search": "?lang=fr"
2041            }
2042        },
2043        {
2044            "href": "https://example.net?lang=en-US#nav",
2045            "new_value": "?lang=fr",
2046            "expected": {
2047                "href": "https://example.net/?lang=fr#nav",
2048                "search": "?lang=fr"
2049            }
2050        },
2051        {
2052            "href": "https://example.net?lang=en-US#nav",
2053            "new_value": "??lang=fr",
2054            "expected": {
2055                "href": "https://example.net/??lang=fr#nav",
2056                "search": "??lang=fr"
2057            }
2058        },
2059        {
2060            "href": "https://example.net?lang=en-US#nav",
2061            "new_value": "?",
2062            "expected": {
2063                "href": "https://example.net/?#nav",
2064                "search": ""
2065            }
2066        },
2067        {
2068            "href": "https://example.net?lang=en-US#nav",
2069            "new_value": "",
2070            "expected": {
2071                "href": "https://example.net/#nav",
2072                "search": ""
2073            }
2074        },
2075        {
2076            "href": "https://example.net?lang=en-US",
2077            "new_value": "",
2078            "expected": {
2079                "href": "https://example.net/",
2080                "search": ""
2081            }
2082        },
2083        {
2084            "href": "https://example.net",
2085            "new_value": "",
2086            "expected": {
2087                "href": "https://example.net/",
2088                "search": ""
2089            }
2090        },
2091        {
2092            "comment": "UTF-8 percent encoding with the query encode set. Tabs and newlines are removed.",
2093            "href": "a:/",
2094            "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé",
2095            "expected": {
2096                "href": "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9",
2097                "search": "?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9"
2098            }
2099        },
2100        {
2101            "comment": "Bytes already percent-encoded are left as-is",
2102            "href": "http://example.net",
2103            "new_value": "%c3%89té",
2104            "expected": {
2105                "href": "http://example.net/?%c3%89t%C3%A9",
2106                "search": "?%c3%89t%C3%A9"
2107            }
2108        },
2109        {
2110            "comment": "Drop trailing spaces from trailing opaque paths",
2111            "href": "data:space ?query",
2112            "new_value": "",
2113            "expected": {
2114                "href": "data:space",
2115                "pathname": "space",
2116                "search": ""
2117            }
2118        },
2119        {
2120            "href": "sc:space ?query",
2121            "new_value": "",
2122            "expected": {
2123                "href": "sc:space",
2124                "pathname": "space",
2125                "search": ""
2126            }
2127        },
2128        {
2129            "comment": "Do not drop trailing spaces from non-trailing opaque paths",
2130            "href": "data:space  ?query#fragment",
2131            "new_value": "",
2132            "expected": {
2133                "href": "data:space  #fragment",
2134                "search": ""
2135            }
2136        },
2137        {
2138            "href": "sc:space  ?query#fragment",
2139            "new_value": "",
2140            "expected": {
2141                "href": "sc:space  #fragment",
2142                "search": ""
2143            }
2144        }
2145    ],
2146    "hash": [
2147        {
2148            "href": "https://example.net",
2149            "new_value": "main",
2150            "expected": {
2151                "href": "https://example.net/#main",
2152                "hash": "#main"
2153            }
2154        },
2155        {
2156            "href": "https://example.net#nav",
2157            "new_value": "main",
2158            "expected": {
2159                "href": "https://example.net/#main",
2160                "hash": "#main"
2161            }
2162        },
2163        {
2164            "href": "https://example.net?lang=en-US",
2165            "new_value": "##nav",
2166            "expected": {
2167                "href": "https://example.net/?lang=en-US##nav",
2168                "hash": "##nav"
2169            }
2170        },
2171        {
2172            "href": "https://example.net?lang=en-US#nav",
2173            "new_value": "#main",
2174            "expected": {
2175                "href": "https://example.net/?lang=en-US#main",
2176                "hash": "#main"
2177            }
2178        },
2179        {
2180            "href": "https://example.net?lang=en-US#nav",
2181            "new_value": "#",
2182            "expected": {
2183                "href": "https://example.net/?lang=en-US#",
2184                "hash": ""
2185            }
2186        },
2187        {
2188            "href": "https://example.net?lang=en-US#nav",
2189            "new_value": "",
2190            "expected": {
2191                "href": "https://example.net/?lang=en-US",
2192                "hash": ""
2193            }
2194        },
2195        {
2196            "href": "http://example.net",
2197            "new_value": "#foo bar",
2198            "expected": {
2199                "href": "http://example.net/#foo%20bar",
2200                "hash": "#foo%20bar"
2201            }
2202        },
2203        {
2204            "href": "http://example.net",
2205            "new_value": "#foo\"bar",
2206            "expected": {
2207                "href": "http://example.net/#foo%22bar",
2208                "hash": "#foo%22bar"
2209            }
2210        },
2211        {
2212            "href": "http://example.net",
2213            "new_value": "#foo<bar",
2214            "expected": {
2215                "href": "http://example.net/#foo%3Cbar",
2216                "hash": "#foo%3Cbar"
2217            }
2218        },
2219        {
2220            "href": "http://example.net",
2221            "new_value": "#foo>bar",
2222            "expected": {
2223                "href": "http://example.net/#foo%3Ebar",
2224                "hash": "#foo%3Ebar"
2225            }
2226        },
2227        {
2228            "href": "http://example.net",
2229            "new_value": "#foo`bar",
2230            "expected": {
2231                "href": "http://example.net/#foo%60bar",
2232                "hash": "#foo%60bar"
2233            }
2234        },
2235        {
2236            "comment": "Simple percent-encoding; tabs and newlines are removed",
2237            "href": "a:/",
2238            "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé",
2239            "expected": {
2240                "href": "a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9",
2241                "hash": "#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9"
2242            }
2243        },
2244        {
2245            "comment": "Percent-encode NULLs in fragment",
2246            "href": "http://example.net",
2247            "new_value": "a\u0000b",
2248            "expected": {
2249                "href": "http://example.net/#a%00b",
2250                "hash": "#a%00b"
2251            }
2252        },
2253        {
2254            "comment": "Percent-encode NULLs in fragment",
2255            "href": "non-spec:/",
2256            "new_value": "a\u0000b",
2257            "expected": {
2258                "href": "non-spec:/#a%00b",
2259                "hash": "#a%00b"
2260            }
2261        },
2262        {
2263            "comment": "Bytes already percent-encoded are left as-is",
2264            "href": "http://example.net",
2265            "new_value": "%c3%89té",
2266            "expected": {
2267                "href": "http://example.net/#%c3%89t%C3%A9",
2268                "hash": "#%c3%89t%C3%A9"
2269            }
2270        },
2271        {
2272            "href": "javascript:alert(1)",
2273            "new_value": "castle",
2274            "expected": {
2275                "href": "javascript:alert(1)#castle",
2276                "hash": "#castle"
2277            }
2278        },
2279        {
2280            "comment": "Drop trailing spaces from trailing opaque paths",
2281            "href": "data:space                                                                                                                                  #fragment",
2282            "new_value": "",
2283            "expected": {
2284                "href": "data:space",
2285                "pathname": "space",
2286                "hash": ""
2287            }
2288        },
2289        {
2290            "href": "sc:space    #fragment",
2291            "new_value": "",
2292            "expected": {
2293                "href": "sc:space",
2294                "pathname": "space",
2295                "hash": ""
2296            }
2297        },
2298        {
2299            "comment": "Do not drop trailing spaces from non-trailing opaque paths",
2300            "href": "data:space  ?query#fragment",
2301            "new_value": "",
2302            "expected": {
2303                "href": "data:space  ?query",
2304                "hash": ""
2305            }
2306        },
2307        {
2308            "href": "sc:space  ?query#fragment",
2309            "new_value": "",
2310            "expected": {
2311                "href": "sc:space  ?query",
2312                "hash": ""
2313            }
2314        }
2315    ],
2316    "href": [
2317        {
2318            "href": "file:///var/log/system.log",
2319            "new_value": "http://0300.168.0xF0",
2320            "expected": {
2321                "href": "http://192.168.0.240/",
2322                "protocol": "http:"
2323            }
2324        }
2325    ]
2326}
2327