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 "comment": "Upper-case ASCII is lower-cased", 44 "href": "a://example.net", 45 "new_value": "B", 46 "expected": { 47 "href": "b://example.net/", 48 "protocol": "b:" 49 } 50 }, 51 { 52 "comment": "Non-ASCII is rejected", 53 "href": "a://example.net", 54 "new_value": "é", 55 "expected": { 56 "href": "a://example.net/", 57 "protocol": "a:" 58 } 59 }, 60 { 61 "comment": "No leading digit", 62 "href": "a://example.net", 63 "new_value": "0b", 64 "expected": { 65 "href": "a://example.net/", 66 "protocol": "a:" 67 } 68 }, 69 { 70 "comment": "No leading punctuation", 71 "href": "a://example.net", 72 "new_value": "+b", 73 "expected": { 74 "href": "a://example.net/", 75 "protocol": "a:" 76 } 77 }, 78 { 79 "href": "a://example.net", 80 "new_value": "bC0+-.", 81 "expected": { 82 "href": "bc0+-.://example.net/", 83 "protocol": "bc0+-.:" 84 } 85 }, 86 { 87 "comment": "Only some punctuation is acceptable", 88 "href": "a://example.net", 89 "new_value": "b,c", 90 "expected": { 91 "href": "a://example.net/", 92 "protocol": "a:" 93 } 94 }, 95 { 96 "comment": "Non-ASCII is rejected", 97 "href": "a://example.net", 98 "new_value": "bé", 99 "expected": { 100 "href": "a://example.net/", 101 "protocol": "a:" 102 } 103 }, 104 { 105 "comment": "Can’t switch from file URL with no host", 106 "href": "file://localhost/", 107 "new_value": "http", 108 "expected": { 109 "href": "file:///", 110 "protocol": "file:" 111 } 112 }, 113 { 114 "href": "file:///test", 115 "new_value": "gopher", 116 "expected": { 117 "href": "file:///test", 118 "protocol": "file:" 119 } 120 }, 121 { 122 "href": "file:", 123 "new_value": "wss", 124 "expected": { 125 "href": "file:///", 126 "protocol": "file:" 127 } 128 }, 129 { 130 "comment": "Spec deviation: from special scheme to not is not problematic. https://github.com/whatwg/url/issues/104", 131 "href": "http://example.net", 132 "new_value": "b", 133 "expected": { 134 "href": "b://example.net/", 135 "protocol": "b:" 136 } 137 }, 138 { 139 "comment": "Cannot-be-a-base URL doesn’t have a host, but URL in a special scheme must.", 140 "href": "mailto:me@example.net", 141 "new_value": "http", 142 "expected": { 143 "href": "mailto:me@example.net", 144 "protocol": "mailto:" 145 } 146 }, 147 { 148 "comment": "Spec deviation: from non-special scheme with a host to special is not problematic. https://github.com/whatwg/url/issues/104", 149 "href": "ssh://me@example.net", 150 "new_value": "http", 151 "expected": { 152 "href": "http://me@example.net/", 153 "protocol": "http:" 154 } 155 }, 156 { 157 "comment": "Stuff after the first ':' is ignored", 158 "href": "http://example.net", 159 "new_value": "https:foo : bar", 160 "expected": { 161 "href": "https://example.net/", 162 "protocol": "https:" 163 } 164 }, 165 { 166 "comment": "Stuff after the first ':' is ignored", 167 "href": "data:text/html,<p>Test", 168 "new_value": "view-source+data:foo : bar", 169 "expected": { 170 "href": "view-source+data:text/html,<p>Test", 171 "protocol": "view-source+data:" 172 } 173 } 174 ], 175 "username": [ 176 { 177 "comment": "No host means no username", 178 "href": "file:///home/you/index.html", 179 "new_value": "me", 180 "expected": { 181 "href": "file:///home/you/index.html", 182 "username": "" 183 } 184 }, 185 { 186 "comment": "No host means no username", 187 "href": "unix:/run/foo.socket", 188 "new_value": "me", 189 "expected": { 190 "href": "unix:/run/foo.socket", 191 "username": "" 192 } 193 }, 194 { 195 "comment": "Cannot-be-a-base means no username", 196 "href": "mailto:you@example.net", 197 "new_value": "me", 198 "expected": { 199 "href": "mailto:you@example.net", 200 "username": "" 201 } 202 }, 203 { 204 "href": "javascript:alert(1)", 205 "new_value": "wario", 206 "expected": { 207 "href": "javascript:alert(1)", 208 "username": "" 209 } 210 }, 211 { 212 "href": "http://example.net", 213 "new_value": "me", 214 "expected": { 215 "href": "http://me@example.net/", 216 "username": "me" 217 } 218 }, 219 { 220 "href": "http://:secret@example.net", 221 "new_value": "me", 222 "expected": { 223 "href": "http://me:secret@example.net/", 224 "username": "me" 225 } 226 }, 227 { 228 "href": "http://me@example.net", 229 "new_value": "", 230 "expected": { 231 "href": "http://example.net/", 232 "username": "" 233 } 234 }, 235 { 236 "href": "http://me:secret@example.net", 237 "new_value": "", 238 "expected": { 239 "href": "http://:secret@example.net/", 240 "username": "" 241 } 242 }, 243 { 244 "comment": "UTF-8 percent encoding with the userinfo encode set.", 245 "href": "http://example.net", 246 "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", 247 "expected": { 248 "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/", 249 "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" 250 } 251 }, 252 { 253 "comment": "Bytes already percent-encoded are left as-is.", 254 "href": "http://example.net", 255 "new_value": "%c3%89té", 256 "expected": { 257 "href": "http://%c3%89t%C3%A9@example.net/", 258 "username": "%c3%89t%C3%A9" 259 } 260 }, 261 { 262 "href": "sc:///", 263 "new_value": "x", 264 "expected": { 265 "href": "sc:///", 266 "username": "" 267 } 268 }, 269 { 270 "href": "file://test/", 271 "new_value": "test", 272 "expected": { 273 "href": "file://test/", 274 "username": "" 275 } 276 }, 277 { 278 "href": "javascript://x/", 279 "new_value": "wario", 280 "expected": { 281 "href": "javascript://wario@x/", 282 "username": "wario" 283 } 284 } 285 ], 286 "password": [ 287 { 288 "comment": "No host means no password", 289 "href": "file:///home/me/index.html", 290 "new_value": "secret", 291 "expected": { 292 "href": "file:///home/me/index.html", 293 "password": "" 294 } 295 }, 296 { 297 "comment": "No host means no password", 298 "href": "unix:/run/foo.socket", 299 "new_value": "secret", 300 "expected": { 301 "href": "unix:/run/foo.socket", 302 "password": "" 303 } 304 }, 305 { 306 "comment": "Cannot-be-a-base means no password", 307 "href": "mailto:me@example.net", 308 "new_value": "secret", 309 "expected": { 310 "href": "mailto:me@example.net", 311 "password": "" 312 } 313 }, 314 { 315 "href": "http://example.net", 316 "new_value": "secret", 317 "expected": { 318 "href": "http://:secret@example.net/", 319 "password": "secret" 320 } 321 }, 322 { 323 "href": "http://me@example.net", 324 "new_value": "secret", 325 "expected": { 326 "href": "http://me:secret@example.net/", 327 "password": "secret" 328 } 329 }, 330 { 331 "href": "http://:secret@example.net", 332 "new_value": "", 333 "expected": { 334 "href": "http://example.net/", 335 "password": "" 336 } 337 }, 338 { 339 "href": "http://me:secret@example.net", 340 "new_value": "", 341 "expected": { 342 "href": "http://me@example.net/", 343 "password": "" 344 } 345 }, 346 { 347 "comment": "UTF-8 percent encoding with the userinfo encode set.", 348 "href": "http://example.net", 349 "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", 350 "expected": { 351 "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/", 352 "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" 353 } 354 }, 355 { 356 "comment": "Bytes already percent-encoded are left as-is.", 357 "href": "http://example.net", 358 "new_value": "%c3%89té", 359 "expected": { 360 "href": "http://:%c3%89t%C3%A9@example.net/", 361 "password": "%c3%89t%C3%A9" 362 } 363 }, 364 { 365 "href": "sc:///", 366 "new_value": "x", 367 "expected": { 368 "href": "sc:///", 369 "password": "" 370 } 371 }, 372 { 373 "href": "file://test/", 374 "new_value": "test", 375 "expected": { 376 "href": "file://test/", 377 "password": "" 378 } 379 }, 380 { 381 "href": "javascript://x/", 382 "new_value": "bowser", 383 "expected": { 384 "href": "javascript://:bowser@x/", 385 "password": "bowser" 386 } 387 } 388 ], 389 "host": [ 390 { 391 "href": "sc://x/", 392 "new_value": "\u0009", 393 "expected": { 394 "href": "sc:///", 395 "host": "", 396 "hostname": "" 397 } 398 }, 399 { 400 "href": "sc://x/", 401 "new_value": "\u000A", 402 "expected": { 403 "href": "sc:///", 404 "host": "", 405 "hostname": "" 406 } 407 }, 408 { 409 "href": "sc://x/", 410 "new_value": "\u000D", 411 "expected": { 412 "href": "sc:///", 413 "host": "", 414 "hostname": "" 415 } 416 }, 417 { 418 "href": "sc://x/", 419 "new_value": "#", 420 "expected": { 421 "href": "sc:///", 422 "host": "", 423 "hostname": "" 424 } 425 }, 426 { 427 "href": "sc://x/", 428 "new_value": "/", 429 "expected": { 430 "href": "sc:///", 431 "host": "", 432 "hostname": "" 433 } 434 }, 435 { 436 "href": "sc://x/", 437 "new_value": "?", 438 "expected": { 439 "href": "sc:///", 440 "host": "", 441 "hostname": "" 442 } 443 }, 444 { 445 "href": "sc://x/", 446 "new_value": "@", 447 "expected": { 448 "href": "sc://x/", 449 "host": "x", 450 "hostname": "x" 451 } 452 }, 453 { 454 "href": "sc://x/", 455 "new_value": "ß", 456 "expected": { 457 "href": "sc://%C3%9F/", 458 "host": "%C3%9F", 459 "hostname": "%C3%9F" 460 } 461 }, 462 { 463 "comment": "Cannot-be-a-base means no host", 464 "href": "mailto:me@example.net", 465 "new_value": "example.com", 466 "expected": { 467 "href": "mailto:me@example.net", 468 "host": "" 469 } 470 }, 471 { 472 "comment": "Cannot-be-a-base means no password", 473 "href": "data:text/plain,Stuff", 474 "new_value": "example.net", 475 "expected": { 476 "href": "data:text/plain,Stuff", 477 "host": "" 478 } 479 }, 480 { 481 "href": "http://example.net", 482 "new_value": "example.com:8080", 483 "expected": { 484 "href": "http://example.com:8080/", 485 "host": "example.com:8080", 486 "hostname": "example.com", 487 "port": "8080" 488 } 489 }, 490 { 491 "comment": "Port number is unchanged if not specified in the new value", 492 "href": "http://example.net:8080", 493 "new_value": "example.com", 494 "expected": { 495 "href": "http://example.com:8080/", 496 "host": "example.com:8080", 497 "hostname": "example.com", 498 "port": "8080" 499 } 500 }, 501 { 502 "comment": "Port number is removed if empty in the new value: https://github.com/whatwg/url/pull/113", 503 "href": "http://example.net:8080", 504 "new_value": "example.com:", 505 "expected": { 506 "href": "http://example.com/", 507 "host": "example.com", 508 "hostname": "example.com", 509 "port": "" 510 } 511 }, 512 { 513 "comment": "The empty host is not valid for special schemes", 514 "href": "http://example.net", 515 "new_value": "", 516 "expected": { 517 "href": "http://example.net/", 518 "host": "example.net" 519 } 520 }, 521 { 522 "comment": "The empty host is OK for non-special schemes", 523 "href": "view-source+http://example.net/foo", 524 "new_value": "", 525 "expected": { 526 "href": "view-source+http:///foo", 527 "host": "" 528 } 529 }, 530 { 531 "comment": "Path-only URLs can gain a host", 532 "href": "a:/foo", 533 "new_value": "example.net", 534 "expected": { 535 "href": "a://example.net/foo", 536 "host": "example.net" 537 } 538 }, 539 { 540 "comment": "IPv4 address syntax is normalized", 541 "href": "http://example.net", 542 "new_value": "0x7F000001:8080", 543 "expected": { 544 "href": "http://127.0.0.1:8080/", 545 "host": "127.0.0.1:8080", 546 "hostname": "127.0.0.1", 547 "port": "8080" 548 } 549 }, 550 { 551 "comment": "IPv6 address syntax is normalized", 552 "href": "http://example.net", 553 "new_value": "[::0:01]:2", 554 "expected": { 555 "href": "http://[::1]:2/", 556 "host": "[::1]:2", 557 "hostname": "[::1]", 558 "port": "2" 559 } 560 }, 561 { 562 "comment": "Default port number is removed", 563 "href": "http://example.net", 564 "new_value": "example.com:80", 565 "expected": { 566 "href": "http://example.com/", 567 "host": "example.com", 568 "hostname": "example.com", 569 "port": "" 570 } 571 }, 572 { 573 "comment": "Default port number is removed", 574 "href": "https://example.net", 575 "new_value": "example.com:443", 576 "expected": { 577 "href": "https://example.com/", 578 "host": "example.com", 579 "hostname": "example.com", 580 "port": "" 581 } 582 }, 583 { 584 "comment": "Default port number is only removed for the relevant scheme", 585 "href": "https://example.net", 586 "new_value": "example.com:80", 587 "expected": { 588 "href": "https://example.com:80/", 589 "host": "example.com:80", 590 "hostname": "example.com", 591 "port": "80" 592 } 593 }, 594 { 595 "comment": "Stuff after a / delimiter is ignored", 596 "href": "http://example.net/path", 597 "new_value": "example.com/stuff", 598 "expected": { 599 "href": "http://example.com/path", 600 "host": "example.com", 601 "hostname": "example.com", 602 "port": "" 603 } 604 }, 605 { 606 "comment": "Stuff after a / delimiter is ignored", 607 "href": "http://example.net/path", 608 "new_value": "example.com:8080/stuff", 609 "expected": { 610 "href": "http://example.com:8080/path", 611 "host": "example.com:8080", 612 "hostname": "example.com", 613 "port": "8080" 614 } 615 }, 616 { 617 "comment": "Stuff after a ? delimiter is ignored", 618 "href": "http://example.net/path", 619 "new_value": "example.com?stuff", 620 "expected": { 621 "href": "http://example.com/path", 622 "host": "example.com", 623 "hostname": "example.com", 624 "port": "" 625 } 626 }, 627 { 628 "comment": "Stuff after a ? delimiter is ignored", 629 "href": "http://example.net/path", 630 "new_value": "example.com:8080?stuff", 631 "expected": { 632 "href": "http://example.com:8080/path", 633 "host": "example.com:8080", 634 "hostname": "example.com", 635 "port": "8080" 636 } 637 }, 638 { 639 "comment": "Stuff after a # delimiter is ignored", 640 "href": "http://example.net/path", 641 "new_value": "example.com#stuff", 642 "expected": { 643 "href": "http://example.com/path", 644 "host": "example.com", 645 "hostname": "example.com", 646 "port": "" 647 } 648 }, 649 { 650 "comment": "Stuff after a # delimiter is ignored", 651 "href": "http://example.net/path", 652 "new_value": "example.com:8080#stuff", 653 "expected": { 654 "href": "http://example.com:8080/path", 655 "host": "example.com:8080", 656 "hostname": "example.com", 657 "port": "8080" 658 } 659 }, 660 { 661 "comment": "Stuff after a \\ delimiter is ignored for special schemes", 662 "href": "http://example.net/path", 663 "new_value": "example.com\\stuff", 664 "expected": { 665 "href": "http://example.com/path", 666 "host": "example.com", 667 "hostname": "example.com", 668 "port": "" 669 } 670 }, 671 { 672 "comment": "Stuff after a \\ delimiter is ignored for special schemes", 673 "href": "http://example.net/path", 674 "new_value": "example.com:8080\\stuff", 675 "expected": { 676 "href": "http://example.com:8080/path", 677 "host": "example.com:8080", 678 "hostname": "example.com", 679 "port": "8080" 680 } 681 }, 682 { 683 "comment": "\\ is not a delimiter for non-special schemes, but still forbidden in hosts", 684 "href": "view-source+http://example.net/path", 685 "new_value": "example.com\\stuff", 686 "expected": { 687 "href": "view-source+http://example.net/path", 688 "host": "example.net", 689 "hostname": "example.net", 690 "port": "" 691 } 692 }, 693 { 694 "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", 695 "href": "view-source+http://example.net/path", 696 "new_value": "example.com:8080stuff2", 697 "expected": { 698 "href": "view-source+http://example.com:8080/path", 699 "host": "example.com:8080", 700 "hostname": "example.com", 701 "port": "8080" 702 } 703 }, 704 { 705 "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", 706 "href": "http://example.net/path", 707 "new_value": "example.com:8080stuff2", 708 "expected": { 709 "href": "http://example.com:8080/path", 710 "host": "example.com:8080", 711 "hostname": "example.com", 712 "port": "8080" 713 } 714 }, 715 { 716 "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", 717 "href": "http://example.net/path", 718 "new_value": "example.com:8080+2", 719 "expected": { 720 "href": "http://example.com:8080/path", 721 "host": "example.com:8080", 722 "hostname": "example.com", 723 "port": "8080" 724 } 725 }, 726 { 727 "comment": "Port numbers are 16 bit integers", 728 "href": "http://example.net/path", 729 "new_value": "example.com:65535", 730 "expected": { 731 "href": "http://example.com:65535/path", 732 "host": "example.com:65535", 733 "hostname": "example.com", 734 "port": "65535" 735 } 736 }, 737 { 738 "comment": "Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though.", 739 "href": "http://example.net/path", 740 "new_value": "example.com:65536", 741 "expected": { 742 "href": "http://example.com/path", 743 "host": "example.com", 744 "hostname": "example.com", 745 "port": "" 746 } 747 }, 748 { 749 "comment": "Broken IPv6", 750 "href": "http://example.net/", 751 "new_value": "[google.com]", 752 "expected": { 753 "href": "http://example.net/", 754 "host": "example.net", 755 "hostname": "example.net" 756 } 757 }, 758 { 759 "href": "http://example.net/", 760 "new_value": "[::1.2.3.4x]", 761 "expected": { 762 "href": "http://example.net/", 763 "host": "example.net", 764 "hostname": "example.net" 765 } 766 }, 767 { 768 "href": "http://example.net/", 769 "new_value": "[::1.2.3.]", 770 "expected": { 771 "href": "http://example.net/", 772 "host": "example.net", 773 "hostname": "example.net" 774 } 775 }, 776 { 777 "href": "http://example.net/", 778 "new_value": "[::1.2.]", 779 "expected": { 780 "href": "http://example.net/", 781 "host": "example.net", 782 "hostname": "example.net" 783 } 784 }, 785 { 786 "href": "http://example.net/", 787 "new_value": "[::1.]", 788 "expected": { 789 "href": "http://example.net/", 790 "host": "example.net", 791 "hostname": "example.net" 792 } 793 } 794 ], 795 "hostname": [ 796 { 797 "href": "sc://x/", 798 "new_value": "\u0009", 799 "expected": { 800 "href": "sc:///", 801 "host": "", 802 "hostname": "" 803 } 804 }, 805 { 806 "href": "sc://x/", 807 "new_value": "\u000A", 808 "expected": { 809 "href": "sc:///", 810 "host": "", 811 "hostname": "" 812 } 813 }, 814 { 815 "href": "sc://x/", 816 "new_value": "\u000D", 817 "expected": { 818 "href": "sc:///", 819 "host": "", 820 "hostname": "" 821 } 822 }, 823 { 824 "href": "sc://x/", 825 "new_value": "#", 826 "expected": { 827 "href": "sc:///", 828 "host": "", 829 "hostname": "" 830 } 831 }, 832 { 833 "href": "sc://x/", 834 "new_value": "/", 835 "expected": { 836 "href": "sc:///", 837 "host": "", 838 "hostname": "" 839 } 840 }, 841 { 842 "href": "sc://x/", 843 "new_value": "?", 844 "expected": { 845 "href": "sc:///", 846 "host": "", 847 "hostname": "" 848 } 849 }, 850 { 851 "href": "sc://x/", 852 "new_value": "@", 853 "expected": { 854 "href": "sc://x/", 855 "host": "x", 856 "hostname": "x" 857 } 858 }, 859 { 860 "comment": "Cannot-be-a-base means no host", 861 "href": "mailto:me@example.net", 862 "new_value": "example.com", 863 "expected": { 864 "href": "mailto:me@example.net", 865 "host": "" 866 } 867 }, 868 { 869 "comment": "Cannot-be-a-base means no password", 870 "href": "data:text/plain,Stuff", 871 "new_value": "example.net", 872 "expected": { 873 "href": "data:text/plain,Stuff", 874 "host": "" 875 } 876 }, 877 { 878 "href": "http://example.net:8080", 879 "new_value": "example.com", 880 "expected": { 881 "href": "http://example.com:8080/", 882 "host": "example.com:8080", 883 "hostname": "example.com", 884 "port": "8080" 885 } 886 }, 887 { 888 "comment": "The empty host is not valid for special schemes", 889 "href": "http://example.net", 890 "new_value": "", 891 "expected": { 892 "href": "http://example.net/", 893 "host": "example.net" 894 } 895 }, 896 { 897 "comment": "The empty host is OK for non-special schemes", 898 "href": "view-source+http://example.net/foo", 899 "new_value": "", 900 "expected": { 901 "href": "view-source+http:///foo", 902 "host": "" 903 } 904 }, 905 { 906 "comment": "Path-only URLs can gain a host", 907 "href": "a:/foo", 908 "new_value": "example.net", 909 "expected": { 910 "href": "a://example.net/foo", 911 "host": "example.net" 912 } 913 }, 914 { 915 "comment": "IPv4 address syntax is normalized", 916 "href": "http://example.net:8080", 917 "new_value": "0x7F000001", 918 "expected": { 919 "href": "http://127.0.0.1:8080/", 920 "host": "127.0.0.1:8080", 921 "hostname": "127.0.0.1", 922 "port": "8080" 923 } 924 }, 925 { 926 "comment": "IPv6 address syntax is normalized", 927 "href": "http://example.net", 928 "new_value": "[::0:01]", 929 "expected": { 930 "href": "http://[::1]/", 931 "host": "[::1]", 932 "hostname": "[::1]", 933 "port": "" 934 } 935 }, 936 { 937 "comment": "Stuff after a : delimiter is ignored", 938 "href": "http://example.net/path", 939 "new_value": "example.com:8080", 940 "expected": { 941 "href": "http://example.com/path", 942 "host": "example.com", 943 "hostname": "example.com", 944 "port": "" 945 } 946 }, 947 { 948 "comment": "Stuff after a : delimiter is ignored", 949 "href": "http://example.net:8080/path", 950 "new_value": "example.com:", 951 "expected": { 952 "href": "http://example.com:8080/path", 953 "host": "example.com:8080", 954 "hostname": "example.com", 955 "port": "8080" 956 } 957 }, 958 { 959 "comment": "Stuff after a / delimiter is ignored", 960 "href": "http://example.net/path", 961 "new_value": "example.com/stuff", 962 "expected": { 963 "href": "http://example.com/path", 964 "host": "example.com", 965 "hostname": "example.com", 966 "port": "" 967 } 968 }, 969 { 970 "comment": "Stuff after a ? delimiter is ignored", 971 "href": "http://example.net/path", 972 "new_value": "example.com?stuff", 973 "expected": { 974 "href": "http://example.com/path", 975 "host": "example.com", 976 "hostname": "example.com", 977 "port": "" 978 } 979 }, 980 { 981 "comment": "Stuff after a # delimiter is ignored", 982 "href": "http://example.net/path", 983 "new_value": "example.com#stuff", 984 "expected": { 985 "href": "http://example.com/path", 986 "host": "example.com", 987 "hostname": "example.com", 988 "port": "" 989 } 990 }, 991 { 992 "comment": "Stuff after a \\ delimiter is ignored for special schemes", 993 "href": "http://example.net/path", 994 "new_value": "example.com\\stuff", 995 "expected": { 996 "href": "http://example.com/path", 997 "host": "example.com", 998 "hostname": "example.com", 999 "port": "" 1000 } 1001 }, 1002 { 1003 "comment": "\\ is not a delimiter for non-special schemes, but still forbidden in hosts", 1004 "href": "view-source+http://example.net/path", 1005 "new_value": "example.com\\stuff", 1006 "expected": { 1007 "href": "view-source+http://example.net/path", 1008 "host": "example.net", 1009 "hostname": "example.net", 1010 "port": "" 1011 } 1012 }, 1013 { 1014 "comment": "Broken IPv6", 1015 "href": "http://example.net/", 1016 "new_value": "[google.com]", 1017 "expected": { 1018 "href": "http://example.net/", 1019 "host": "example.net", 1020 "hostname": "example.net" 1021 } 1022 }, 1023 { 1024 "href": "http://example.net/", 1025 "new_value": "[::1.2.3.4x]", 1026 "expected": { 1027 "href": "http://example.net/", 1028 "host": "example.net", 1029 "hostname": "example.net" 1030 } 1031 }, 1032 { 1033 "href": "http://example.net/", 1034 "new_value": "[::1.2.3.]", 1035 "expected": { 1036 "href": "http://example.net/", 1037 "host": "example.net", 1038 "hostname": "example.net" 1039 } 1040 }, 1041 { 1042 "href": "http://example.net/", 1043 "new_value": "[::1.2.]", 1044 "expected": { 1045 "href": "http://example.net/", 1046 "host": "example.net", 1047 "hostname": "example.net" 1048 } 1049 }, 1050 { 1051 "href": "http://example.net/", 1052 "new_value": "[::1.]", 1053 "expected": { 1054 "href": "http://example.net/", 1055 "host": "example.net", 1056 "hostname": "example.net" 1057 } 1058 } 1059 ], 1060 "port": [ 1061 { 1062 "href": "http://example.net", 1063 "new_value": "8080", 1064 "expected": { 1065 "href": "http://example.net:8080/", 1066 "host": "example.net:8080", 1067 "hostname": "example.net", 1068 "port": "8080" 1069 } 1070 }, 1071 { 1072 "comment": "Port number is removed if empty is the new value", 1073 "href": "http://example.net:8080", 1074 "new_value": "", 1075 "expected": { 1076 "href": "http://example.net/", 1077 "host": "example.net", 1078 "hostname": "example.net", 1079 "port": "" 1080 } 1081 }, 1082 { 1083 "comment": "Default port number is removed", 1084 "href": "http://example.net:8080", 1085 "new_value": "80", 1086 "expected": { 1087 "href": "http://example.net/", 1088 "host": "example.net", 1089 "hostname": "example.net", 1090 "port": "" 1091 } 1092 }, 1093 { 1094 "comment": "Default port number is removed", 1095 "href": "https://example.net:4433", 1096 "new_value": "443", 1097 "expected": { 1098 "href": "https://example.net/", 1099 "host": "example.net", 1100 "hostname": "example.net", 1101 "port": "" 1102 } 1103 }, 1104 { 1105 "comment": "Default port number is only removed for the relevant scheme", 1106 "href": "https://example.net", 1107 "new_value": "80", 1108 "expected": { 1109 "href": "https://example.net:80/", 1110 "host": "example.net:80", 1111 "hostname": "example.net", 1112 "port": "80" 1113 } 1114 }, 1115 { 1116 "comment": "Stuff after a / delimiter is ignored", 1117 "href": "http://example.net/path", 1118 "new_value": "8080/stuff", 1119 "expected": { 1120 "href": "http://example.net:8080/path", 1121 "host": "example.net:8080", 1122 "hostname": "example.net", 1123 "port": "8080" 1124 } 1125 }, 1126 { 1127 "comment": "Stuff after a ? delimiter is ignored", 1128 "href": "http://example.net/path", 1129 "new_value": "8080?stuff", 1130 "expected": { 1131 "href": "http://example.net:8080/path", 1132 "host": "example.net:8080", 1133 "hostname": "example.net", 1134 "port": "8080" 1135 } 1136 }, 1137 { 1138 "comment": "Stuff after a # delimiter is ignored", 1139 "href": "http://example.net/path", 1140 "new_value": "8080#stuff", 1141 "expected": { 1142 "href": "http://example.net:8080/path", 1143 "host": "example.net:8080", 1144 "hostname": "example.net", 1145 "port": "8080" 1146 } 1147 }, 1148 { 1149 "comment": "Stuff after a \\ delimiter is ignored for special schemes", 1150 "href": "http://example.net/path", 1151 "new_value": "8080\\stuff", 1152 "expected": { 1153 "href": "http://example.net:8080/path", 1154 "host": "example.net:8080", 1155 "hostname": "example.net", 1156 "port": "8080" 1157 } 1158 }, 1159 { 1160 "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", 1161 "href": "view-source+http://example.net/path", 1162 "new_value": "8080stuff2", 1163 "expected": { 1164 "href": "view-source+http://example.net:8080/path", 1165 "host": "example.net:8080", 1166 "hostname": "example.net", 1167 "port": "8080" 1168 } 1169 }, 1170 { 1171 "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", 1172 "href": "http://example.net/path", 1173 "new_value": "8080stuff2", 1174 "expected": { 1175 "href": "http://example.net:8080/path", 1176 "host": "example.net:8080", 1177 "hostname": "example.net", 1178 "port": "8080" 1179 } 1180 }, 1181 { 1182 "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", 1183 "href": "http://example.net/path", 1184 "new_value": "8080+2", 1185 "expected": { 1186 "href": "http://example.net:8080/path", 1187 "host": "example.net:8080", 1188 "hostname": "example.net", 1189 "port": "8080" 1190 } 1191 }, 1192 { 1193 "comment": "Port numbers are 16 bit integers", 1194 "href": "http://example.net/path", 1195 "new_value": "65535", 1196 "expected": { 1197 "href": "http://example.net:65535/path", 1198 "host": "example.net:65535", 1199 "hostname": "example.net", 1200 "port": "65535" 1201 } 1202 }, 1203 { 1204 "comment": "Port numbers are 16 bit integers, overflowing is an error", 1205 "href": "http://example.net:8080/path", 1206 "new_value": "65536", 1207 "expected": { 1208 "href": "http://example.net:8080/path", 1209 "host": "example.net:8080", 1210 "hostname": "example.net", 1211 "port": "8080" 1212 } 1213 }, 1214 { 1215 "comment": "Port numbers are 16 bit integers, overflowing is an error", 1216 "href": "non-special://example.net:8080/path", 1217 "new_value": "65536", 1218 "expected": { 1219 "href": "non-special://example.net:8080/path", 1220 "host": "example.net:8080", 1221 "hostname": "example.net", 1222 "port": "8080" 1223 } 1224 }, 1225 { 1226 "href": "file://test/", 1227 "new_value": "12", 1228 "expected": { 1229 "href": "file://test/", 1230 "port": "" 1231 } 1232 }, 1233 { 1234 "href": "file://localhost/", 1235 "new_value": "12", 1236 "expected": { 1237 "href": "file:///", 1238 "port": "" 1239 } 1240 }, 1241 { 1242 "href": "non-base:value", 1243 "new_value": "12", 1244 "expected": { 1245 "href": "non-base:value", 1246 "port": "" 1247 } 1248 }, 1249 { 1250 "href": "sc:///", 1251 "new_value": "12", 1252 "expected": { 1253 "href": "sc:///", 1254 "port": "" 1255 } 1256 }, 1257 { 1258 "href": "sc://x/", 1259 "new_value": "12", 1260 "expected": { 1261 "href": "sc://x:12/", 1262 "port": "12" 1263 } 1264 }, 1265 { 1266 "href": "javascript://x/", 1267 "new_value": "12", 1268 "expected": { 1269 "href": "javascript://x:12/", 1270 "port": "12" 1271 } 1272 } 1273 ], 1274 "pathname": [ 1275 { 1276 "comment": "Cannot-be-a-base don’t have a path", 1277 "href": "mailto:me@example.net", 1278 "new_value": "/foo", 1279 "expected": { 1280 "href": "mailto:me@example.net", 1281 "pathname": "me@example.net" 1282 } 1283 }, 1284 { 1285 "href": "unix:/run/foo.socket?timeout=10", 1286 "new_value": "/var/log/../run/bar.socket", 1287 "expected": { 1288 "href": "unix:/var/run/bar.socket?timeout=10", 1289 "pathname": "/var/run/bar.socket" 1290 } 1291 }, 1292 { 1293 "href": "https://example.net#nav", 1294 "new_value": "home", 1295 "expected": { 1296 "href": "https://example.net/home#nav", 1297 "pathname": "/home" 1298 } 1299 }, 1300 { 1301 "href": "https://example.net#nav", 1302 "new_value": "../home", 1303 "expected": { 1304 "href": "https://example.net/home#nav", 1305 "pathname": "/home" 1306 } 1307 }, 1308 { 1309 "comment": "\\ is a segment delimiter for 'special' URLs", 1310 "href": "http://example.net/home?lang=fr#nav", 1311 "new_value": "\\a\\%2E\\b\\%2e.\\c", 1312 "expected": { 1313 "href": "http://example.net/a/c?lang=fr#nav", 1314 "pathname": "/a/c" 1315 } 1316 }, 1317 { 1318 "comment": "\\ is *not* a segment delimiter for non-'special' URLs", 1319 "href": "view-source+http://example.net/home?lang=fr#nav", 1320 "new_value": "\\a\\%2E\\b\\%2e.\\c", 1321 "expected": { 1322 "href": "view-source+http://example.net/\\a\\%2E\\b\\%2e.\\c?lang=fr#nav", 1323 "pathname": "/\\a\\%2E\\b\\%2e.\\c" 1324 } 1325 }, 1326 { 1327 "comment": "UTF-8 percent encoding with the default encode set. Tabs and newlines are removed. Leading or training C0 controls and space are removed.", 1328 "href": "a:/", 1329 "new_value": "\u0000\u0001\t\n\r\u001f !\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", 1330 "expected": { 1331 "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", 1332 "pathname": "/!%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E%3F@AZ[\\]^_%60az%7B|%7D~%7F%C2%80%C2%81%C3%89%C3%A9" 1333 } 1334 }, 1335 { 1336 "comment": "Bytes already percent-encoded are left as-is, including %2E outside dotted segments.", 1337 "href": "http://example.net", 1338 "new_value": "%2e%2E%c3%89té", 1339 "expected": { 1340 "href": "http://example.net/%2e%2E%c3%89t%C3%A9", 1341 "pathname": "/%2e%2E%c3%89t%C3%A9" 1342 } 1343 }, 1344 { 1345 "comment": "? needs to be encoded", 1346 "href": "http://example.net", 1347 "new_value": "?", 1348 "expected": { 1349 "href": "http://example.net/%3F", 1350 "pathname": "/%3F" 1351 } 1352 }, 1353 { 1354 "comment": "# needs to be encoded", 1355 "href": "http://example.net", 1356 "new_value": "#", 1357 "expected": { 1358 "href": "http://example.net/%23", 1359 "pathname": "/%23" 1360 } 1361 }, 1362 { 1363 "comment": "? needs to be encoded, non-special scheme", 1364 "href": "sc://example.net", 1365 "new_value": "?", 1366 "expected": { 1367 "href": "sc://example.net/%3F", 1368 "pathname": "/%3F" 1369 } 1370 }, 1371 { 1372 "comment": "# needs to be encoded, non-special scheme", 1373 "href": "sc://example.net", 1374 "new_value": "#", 1375 "expected": { 1376 "href": "sc://example.net/%23", 1377 "pathname": "/%23" 1378 } 1379 } 1380 ], 1381 "search": [ 1382 { 1383 "href": "https://example.net#nav", 1384 "new_value": "lang=fr", 1385 "expected": { 1386 "href": "https://example.net/?lang=fr#nav", 1387 "search": "?lang=fr" 1388 } 1389 }, 1390 { 1391 "href": "https://example.net?lang=en-US#nav", 1392 "new_value": "lang=fr", 1393 "expected": { 1394 "href": "https://example.net/?lang=fr#nav", 1395 "search": "?lang=fr" 1396 } 1397 }, 1398 { 1399 "href": "https://example.net?lang=en-US#nav", 1400 "new_value": "?lang=fr", 1401 "expected": { 1402 "href": "https://example.net/?lang=fr#nav", 1403 "search": "?lang=fr" 1404 } 1405 }, 1406 { 1407 "href": "https://example.net?lang=en-US#nav", 1408 "new_value": "??lang=fr", 1409 "expected": { 1410 "href": "https://example.net/??lang=fr#nav", 1411 "search": "??lang=fr" 1412 } 1413 }, 1414 { 1415 "href": "https://example.net?lang=en-US#nav", 1416 "new_value": "?", 1417 "expected": { 1418 "href": "https://example.net/?#nav", 1419 "search": "" 1420 } 1421 }, 1422 { 1423 "href": "https://example.net?lang=en-US#nav", 1424 "new_value": "", 1425 "expected": { 1426 "href": "https://example.net/#nav", 1427 "search": "" 1428 } 1429 }, 1430 { 1431 "href": "https://example.net?lang=en-US", 1432 "new_value": "", 1433 "expected": { 1434 "href": "https://example.net/", 1435 "search": "" 1436 } 1437 }, 1438 { 1439 "href": "https://example.net", 1440 "new_value": "", 1441 "expected": { 1442 "href": "https://example.net/", 1443 "search": "" 1444 } 1445 }, 1446 { 1447 "comment": "UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. Leading or training C0 controls and space are removed.", 1448 "href": "a:/", 1449 "new_value": "\u0000\u0001\t\n\r\u001f !\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", 1450 "expected": { 1451 "href": "a:/?!%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9", 1452 "search": "?!%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" 1453 } 1454 }, 1455 { 1456 "comment": "Bytes already percent-encoded are left as-is", 1457 "href": "http://example.net", 1458 "new_value": "%c3%89té", 1459 "expected": { 1460 "href": "http://example.net/?%c3%89t%C3%A9", 1461 "search": "?%c3%89t%C3%A9" 1462 } 1463 } 1464 ], 1465 "hash": [ 1466 { 1467 "href": "https://example.net", 1468 "new_value": "main", 1469 "expected": { 1470 "href": "https://example.net/#main", 1471 "hash": "#main" 1472 } 1473 }, 1474 { 1475 "href": "https://example.net#nav", 1476 "new_value": "main", 1477 "expected": { 1478 "href": "https://example.net/#main", 1479 "hash": "#main" 1480 } 1481 }, 1482 { 1483 "href": "https://example.net?lang=en-US", 1484 "new_value": "##nav", 1485 "expected": { 1486 "href": "https://example.net/?lang=en-US##nav", 1487 "hash": "##nav" 1488 } 1489 }, 1490 { 1491 "href": "https://example.net?lang=en-US#nav", 1492 "new_value": "#main", 1493 "expected": { 1494 "href": "https://example.net/?lang=en-US#main", 1495 "hash": "#main" 1496 } 1497 }, 1498 { 1499 "href": "https://example.net?lang=en-US#nav", 1500 "new_value": "#", 1501 "expected": { 1502 "href": "https://example.net/?lang=en-US#", 1503 "hash": "" 1504 } 1505 }, 1506 { 1507 "href": "https://example.net?lang=en-US#nav", 1508 "new_value": "", 1509 "expected": { 1510 "href": "https://example.net/?lang=en-US", 1511 "hash": "" 1512 } 1513 }, 1514 { 1515 "comment": "Simple percent-encoding; nuls, tabs, and newlines are removed", 1516 "href": "a:/", 1517 "new_value": "\u0000\u0001\t\n\r\u001f !\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", 1518 "expected": { 1519 "href": "a:/#!%01%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9", 1520 "hash": "#!%01%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" 1521 } 1522 }, 1523 { 1524 "comment": "Bytes already percent-encoded are left as-is", 1525 "href": "http://example.net", 1526 "new_value": "%c3%89té", 1527 "expected": { 1528 "href": "http://example.net/#%c3%89t%C3%A9", 1529 "hash": "#%c3%89t%C3%A9" 1530 } 1531 } 1532 ] 1533} 1534