test_URIs.js (36098B)
1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 "use strict"; 7 8 // Run by: cd objdir; make -C netwerk/test/ xpcshell-tests 9 // or: cd objdir; make SOLO_FILE="test_URIs.js" -C netwerk/test/ check-one 10 11 // See also test_URIs2.js. 12 13 // Relevant RFCs: 1738, 1808, 2396, 3986 (newer than the code) 14 // http://greenbytes.de/tech/webdav/rfc3986.html#rfc.section.5.4 15 // http://greenbytes.de/tech/tc/uris/ 16 17 // TEST DATA 18 // --------- 19 var gTests = [ 20 { 21 spec: "about:blank", 22 scheme: "about", 23 prePath: "about:", 24 pathQueryRef: "blank", 25 ref: "", 26 nsIURL: false, 27 nsINestedURI: true, 28 immutable: true, 29 }, 30 { 31 spec: "about:foobar", 32 scheme: "about", 33 prePath: "about:", 34 pathQueryRef: "foobar", 35 ref: "", 36 nsIURL: false, 37 nsINestedURI: false, 38 immutable: true, 39 }, 40 { 41 spec: "chrome://foobar/somedir/somefile.xml", 42 scheme: "chrome", 43 prePath: "chrome://foobar", 44 pathQueryRef: "/somedir/somefile.xml", 45 ref: "", 46 nsIURL: true, 47 nsINestedURI: false, 48 immutable: true, 49 }, 50 { 51 spec: "data:text/html;charset=utf-8,<html></html>", 52 scheme: "data", 53 prePath: "data:", 54 pathQueryRef: "text/html;charset=utf-8,<html></html>", 55 ref: "", 56 nsIURL: false, 57 nsINestedURI: false, 58 }, 59 { 60 spec: "data:text/html;charset=utf-8,<html>\r\n\t</html>", 61 scheme: "data", 62 prePath: "data:", 63 pathQueryRef: "text/html;charset=utf-8,<html></html>", 64 ref: "", 65 nsIURL: false, 66 nsINestedURI: false, 67 }, 68 { 69 spec: "data:text/plain,hello%20world", 70 scheme: "data", 71 prePath: "data:", 72 pathQueryRef: "text/plain,hello%20world", 73 ref: "", 74 nsIURL: false, 75 nsINestedURI: false, 76 }, 77 { 78 spec: "data:text/plain,hello world", 79 scheme: "data", 80 prePath: "data:", 81 pathQueryRef: "text/plain,hello world", 82 ref: "", 83 nsIURL: false, 84 nsINestedURI: false, 85 }, 86 { 87 spec: "file:///dir/afile", 88 scheme: "data", 89 prePath: "data:", 90 pathQueryRef: "text/plain,2", 91 ref: "", 92 relativeURI: "data:te\nxt/plain,2", 93 nsIURL: false, 94 nsINestedURI: false, 95 }, 96 { 97 spec: "file://", 98 scheme: "file", 99 prePath: "file://", 100 pathQueryRef: "/", 101 ref: "", 102 nsIURL: true, 103 nsINestedURI: false, 104 }, 105 { 106 spec: "file:///", 107 scheme: "file", 108 prePath: "file://", 109 pathQueryRef: "/", 110 ref: "", 111 nsIURL: true, 112 nsINestedURI: false, 113 }, 114 { 115 spec: "file:///myFile.html", 116 scheme: "file", 117 prePath: "file://", 118 pathQueryRef: "/myFile.html", 119 ref: "", 120 nsIURL: true, 121 nsINestedURI: false, 122 }, 123 { 124 spec: "file:///dir/afile", 125 scheme: "file", 126 prePath: "file://", 127 pathQueryRef: "/dir/data/text/plain,2", 128 ref: "", 129 relativeURI: "data/text/plain,2", 130 nsIURL: true, 131 nsINestedURI: false, 132 }, 133 { 134 spec: "file:///dir/dir2/", 135 scheme: "file", 136 prePath: "file://", 137 pathQueryRef: "/dir/dir2/data/text/plain,2", 138 ref: "", 139 relativeURI: "data/text/plain,2", 140 nsIURL: true, 141 nsINestedURI: false, 142 }, 143 { 144 spec: "ftp://ftp.mozilla.org/pub/mozilla.org/README", 145 scheme: "ftp", 146 prePath: "ftp://ftp.mozilla.org", 147 pathQueryRef: "/pub/mozilla.org/README", 148 ref: "", 149 nsIURL: true, 150 nsINestedURI: false, 151 }, 152 { 153 spec: "ftp://foo:bar@ftp.mozilla.org:100/pub/mozilla.org/README", 154 scheme: "ftp", 155 prePath: "ftp://foo:bar@ftp.mozilla.org:100", 156 port: 100, 157 username: "foo", 158 password: "bar", 159 pathQueryRef: "/pub/mozilla.org/README", 160 ref: "", 161 nsIURL: true, 162 nsINestedURI: false, 163 }, 164 { 165 spec: "ftp://foo:@ftp.mozilla.org:100/pub/mozilla.org/README", 166 scheme: "ftp", 167 prePath: "ftp://foo@ftp.mozilla.org:100", 168 port: 100, 169 username: "foo", 170 password: "", 171 pathQueryRef: "/pub/mozilla.org/README", 172 ref: "", 173 nsIURL: true, 174 nsINestedURI: false, 175 }, 176 //Bug 706249 177 { 178 spec: "gopher://mozilla.org/", 179 scheme: "gopher", 180 prePath: "gopher://mozilla.org", 181 pathQueryRef: "/", 182 ref: "", 183 nsIURL: false, 184 nsINestedURI: false, 185 }, 186 { 187 spec: "http://www.example.com/", 188 scheme: "http", 189 prePath: "http://www.example.com", 190 pathQueryRef: "/", 191 ref: "", 192 nsIURL: true, 193 nsINestedURI: false, 194 }, 195 { 196 spec: "http://www.exa\nmple.com/", 197 scheme: "http", 198 prePath: "http://www.example.com", 199 pathQueryRef: "/", 200 ref: "", 201 nsIURL: true, 202 nsINestedURI: false, 203 }, 204 { 205 spec: "http://10.32.4.239/", 206 scheme: "http", 207 prePath: "http://10.32.4.239", 208 host: "10.32.4.239", 209 pathQueryRef: "/", 210 ref: "", 211 nsIURL: true, 212 nsINestedURI: false, 213 }, 214 { 215 spec: "http://[::192.9.5.5]/ipng", 216 scheme: "http", 217 prePath: "http://[::c009:505]", 218 host: "::c009:505", 219 pathQueryRef: "/ipng", 220 ref: "", 221 nsIURL: true, 222 nsINestedURI: false, 223 }, 224 { 225 spec: "http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:8888/index.html", 226 scheme: "http", 227 prePath: "http://[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:8888", 228 host: "fedc:ba98:7654:3210:fedc:ba98:7654:3210", 229 port: 8888, 230 pathQueryRef: "/index.html", 231 ref: "", 232 nsIURL: true, 233 nsINestedURI: false, 234 }, 235 { 236 spec: "http://bar:foo@www.mozilla.org:8080/pub/mozilla.org/README.html", 237 scheme: "http", 238 prePath: "http://bar:foo@www.mozilla.org:8080", 239 port: 8080, 240 username: "bar", 241 password: "foo", 242 host: "www.mozilla.org", 243 pathQueryRef: "/pub/mozilla.org/README.html", 244 ref: "", 245 nsIURL: true, 246 nsINestedURI: false, 247 }, 248 { 249 spec: "jar:resource://!/", 250 scheme: "jar", 251 prePath: "jar:", 252 pathQueryRef: "resource:///!/", 253 ref: "", 254 nsIURL: true, 255 nsINestedURI: true, 256 }, 257 { 258 spec: "jar:resource://gre/chrome.toolkit.jar!/", 259 scheme: "jar", 260 prePath: "jar:", 261 pathQueryRef: "resource://gre/chrome.toolkit.jar!/", 262 ref: "", 263 nsIURL: true, 264 nsINestedURI: true, 265 }, 266 { 267 spec: "mailto:webmaster@mozilla.com", 268 scheme: "mailto", 269 prePath: "mailto:", 270 pathQueryRef: "webmaster@mozilla.com", 271 ref: "", 272 nsIURL: false, 273 nsINestedURI: false, 274 }, 275 { 276 spec: "javascript:new Date()", 277 scheme: "javascript", 278 prePath: "javascript:", 279 pathQueryRef: "new Date()", 280 ref: "", 281 nsIURL: false, 282 nsINestedURI: false, 283 }, 284 { 285 spec: "blob:123456", 286 scheme: "blob", 287 prePath: "blob:", 288 pathQueryRef: "123456", 289 ref: "", 290 nsIURL: false, 291 nsINestedURI: false, 292 immutable: true, 293 }, 294 { 295 spec: "place:sort=8&maxResults=10", 296 scheme: "place", 297 prePath: "place:", 298 pathQueryRef: "sort=8&maxResults=10", 299 ref: "", 300 nsIURL: false, 301 nsINestedURI: false, 302 }, 303 { 304 spec: "resource://gre/", 305 scheme: "resource", 306 prePath: "resource://gre", 307 pathQueryRef: "/", 308 ref: "", 309 nsIURL: true, 310 nsINestedURI: false, 311 }, 312 { 313 spec: "resource://gre/components/", 314 scheme: "resource", 315 prePath: "resource://gre", 316 pathQueryRef: "/components/", 317 ref: "", 318 nsIURL: true, 319 nsINestedURI: false, 320 }, 321 322 // Adding more? Consider adding to test_URIs2.js instead, so that neither 323 // test runs for *too* long, risking timeouts on slow platforms. 324 ]; 325 326 var gHashSuffixes = ["#", "#myRef", "#myRef?a=b", "#myRef#", "#myRef#x:yz"]; 327 328 // TEST HELPER FUNCTIONS 329 // --------------------- 330 function do_info(text, stack) { 331 if (!stack) { 332 stack = Components.stack.caller; 333 } 334 335 dump( 336 "\n" + 337 "TEST-INFO | " + 338 stack.filename + 339 " | [" + 340 stack.name + 341 " : " + 342 stack.lineNumber + 343 "] " + 344 text + 345 "\n" 346 ); 347 } 348 349 // Checks that the URIs satisfy equals(), in both possible orderings. 350 // Also checks URI.equalsExceptRef(), because equal URIs should also be equal 351 // when we ignore the ref. 352 // 353 // The third argument is optional. If the client passes a third argument 354 // (e.g. todo_check_true), we'll use that in lieu of ok. 355 function do_check_uri_eq(aURI1, aURI2, aCheckTrueFunc = ok) { 356 do_info("(uri equals check: '" + aURI1.spec + "' == '" + aURI2.spec + "')"); 357 aCheckTrueFunc(aURI1.equals(aURI2)); 358 do_info("(uri equals check: '" + aURI2.spec + "' == '" + aURI1.spec + "')"); 359 aCheckTrueFunc(aURI2.equals(aURI1)); 360 361 // (Only take the extra step of testing 'equalsExceptRef' when we expect the 362 // URIs to really be equal. In 'todo' cases, the URIs may or may not be 363 // equal when refs are ignored - there's no way of knowing in general.) 364 if (aCheckTrueFunc == ok) { 365 do_check_uri_eqExceptRef(aURI1, aURI2, aCheckTrueFunc); 366 } 367 } 368 369 // Checks that the URIs satisfy equalsExceptRef(), in both possible orderings. 370 // 371 // The third argument is optional. If the client passes a third argument 372 // (e.g. todo_check_true), we'll use that in lieu of ok. 373 function do_check_uri_eqExceptRef(aURI1, aURI2, aCheckTrueFunc = ok) { 374 do_info( 375 "(uri equalsExceptRef check: '" + aURI1.spec + "' == '" + aURI2.spec + "')" 376 ); 377 aCheckTrueFunc(aURI1.equalsExceptRef(aURI2)); 378 do_info( 379 "(uri equalsExceptRef check: '" + aURI2.spec + "' == '" + aURI1.spec + "')" 380 ); 381 aCheckTrueFunc(aURI2.equalsExceptRef(aURI1)); 382 } 383 384 // Checks that the given property on aURI matches the corresponding property 385 // in the test bundle (or matches some function of that corresponding property, 386 // if aTestFunctor is passed in). 387 function do_check_property(aTest, aURI, aPropertyName, aTestFunctor) { 388 if (aTest[aPropertyName]) { 389 var expectedVal = aTestFunctor 390 ? aTestFunctor(aTest[aPropertyName]) 391 : aTest[aPropertyName]; 392 393 do_info( 394 "testing " + 395 aPropertyName + 396 " of " + 397 (aTestFunctor ? "modified '" : "'") + 398 aTest.spec + 399 "' is '" + 400 expectedVal + 401 "'" 402 ); 403 Assert.equal(aURI[aPropertyName], expectedVal); 404 } 405 } 406 407 // Test that a given URI parses correctly into its various components. 408 function do_test_uri_basic(aTest) { 409 var URI; 410 411 do_info( 412 "Basic tests for " + 413 aTest.spec + 414 " relative URI: " + 415 (aTest.relativeURI === undefined ? "(none)" : aTest.relativeURI) 416 ); 417 418 try { 419 URI = NetUtil.newURI(aTest.spec); 420 } catch (e) { 421 do_info("Caught error on parse of" + aTest.spec + " Error: " + e.result); 422 if (aTest.fail) { 423 Assert.equal(e.result, aTest.result); 424 return; 425 } 426 do_throw(e.result); 427 } 428 429 if (aTest.relativeURI) { 430 var relURI; 431 432 try { 433 relURI = Services.io.newURI(aTest.relativeURI, null, URI); 434 } catch (e) { 435 do_info( 436 "Caught error on Relative parse of " + 437 aTest.spec + 438 " + " + 439 aTest.relativeURI + 440 " Error: " + 441 e.result 442 ); 443 if (aTest.relativeFail) { 444 Assert.equal(e.result, aTest.relativeFail); 445 return; 446 } 447 do_throw(e.result); 448 } 449 do_info( 450 "relURI.pathQueryRef = " + 451 relURI.pathQueryRef + 452 ", was " + 453 URI.pathQueryRef 454 ); 455 URI = relURI; 456 do_info("URI.pathQueryRef now = " + URI.pathQueryRef); 457 } 458 459 // Sanity-check 460 do_info("testing " + aTest.spec + " equals a clone of itself"); 461 do_check_uri_eq(URI, URI.mutate().finalize()); 462 do_check_uri_eqExceptRef(URI, URI.mutate().setRef("").finalize()); 463 do_info("testing " + aTest.spec + " instanceof nsIURL"); 464 Assert.equal(URI instanceof Ci.nsIURL, aTest.nsIURL); 465 do_info("testing " + aTest.spec + " instanceof nsINestedURI"); 466 Assert.equal(URI instanceof Ci.nsINestedURI, aTest.nsINestedURI); 467 468 do_info( 469 "testing that " + 470 aTest.spec + 471 " throws or returns false " + 472 "from equals(null)" 473 ); 474 // XXXdholbert At some point it'd probably be worth making this behavior 475 // (throwing vs. returning false) consistent across URI implementations. 476 var threw = false; 477 var isEqualToNull; 478 try { 479 isEqualToNull = URI.equals(null); 480 } catch (e) { 481 threw = true; 482 } 483 Assert.ok(threw || !isEqualToNull); 484 485 // Check the various components 486 do_check_property(aTest, URI, "scheme"); 487 do_check_property(aTest, URI, "prePath"); 488 do_check_property(aTest, URI, "pathQueryRef"); 489 do_check_property(aTest, URI, "query"); 490 do_check_property(aTest, URI, "ref"); 491 do_check_property(aTest, URI, "port"); 492 do_check_property(aTest, URI, "username"); 493 do_check_property(aTest, URI, "password"); 494 do_check_property(aTest, URI, "host"); 495 do_check_property(aTest, URI, "specIgnoringRef"); 496 497 do_info("testing hasRef"); 498 Assert.equal(URI.hasRef, !!aTest.ref, "URI.hasRef is correct"); 499 do_info("testing hasUserPass"); 500 Assert.equal( 501 URI.hasUserPass, 502 !!aTest.username || !!aTest.password, 503 "URI.hasUserPass is correct" 504 ); 505 } 506 507 // Test that a given URI parses correctly when we add a given ref to the end 508 function do_test_uri_with_hash_suffix(aTest, aSuffix) { 509 do_info("making sure caller is using suffix that starts with '#'"); 510 Assert.equal(aSuffix[0], "#"); 511 512 var origURI = NetUtil.newURI(aTest.spec); 513 var testURI; 514 515 if (aTest.relativeURI) { 516 try { 517 origURI = Services.io.newURI(aTest.relativeURI, null, origURI); 518 } catch (e) { 519 do_info( 520 "Caught error on Relative parse of " + 521 aTest.spec + 522 " + " + 523 aTest.relativeURI + 524 " Error: " + 525 e.result 526 ); 527 return; 528 } 529 try { 530 testURI = Services.io.newURI(aSuffix, null, origURI); 531 } catch (e) { 532 do_info( 533 "Caught error adding suffix to " + 534 aTest.spec + 535 " + " + 536 aTest.relativeURI + 537 ", suffix " + 538 aSuffix + 539 " Error: " + 540 e.result 541 ); 542 return; 543 } 544 } else { 545 testURI = NetUtil.newURI(aTest.spec + aSuffix); 546 } 547 548 do_info( 549 "testing " + 550 aTest.spec + 551 " with '" + 552 aSuffix + 553 "' appended " + 554 "equals a clone of itself" 555 ); 556 do_check_uri_eq(testURI, testURI.mutate().finalize()); 557 558 do_info( 559 "testing " + 560 aTest.spec + 561 " doesn't equal self with '" + 562 aSuffix + 563 "' appended" 564 ); 565 566 Assert.ok(!origURI.equals(testURI)); 567 568 do_info( 569 "testing " + 570 aTest.spec + 571 " is equalExceptRef to self with '" + 572 aSuffix + 573 "' appended" 574 ); 575 do_check_uri_eqExceptRef(origURI, testURI); 576 577 Assert.equal(testURI.hasRef, true); 578 579 if (!origURI.ref) { 580 // These tests fail if origURI has a ref 581 do_info( 582 "testing setRef('') on " + 583 testURI.spec + 584 " is equal to no-ref version but not equal to ref version" 585 ); 586 var cloneNoRef = testURI.mutate().setRef("").finalize(); // we used to clone here. 587 do_info("cloneNoRef: " + cloneNoRef.spec + " hasRef: " + cloneNoRef.hasRef); 588 do_info("testURI: " + testURI.spec + " hasRef: " + testURI.hasRef); 589 do_check_uri_eq(cloneNoRef, origURI); 590 Assert.ok(!cloneNoRef.equals(testURI)); 591 592 do_info( 593 "testing cloneWithNewRef on " + 594 testURI.spec + 595 " with an empty ref is equal to no-ref version but not equal to ref version" 596 ); 597 var cloneNewRef = testURI.mutate().setRef("").finalize(); 598 do_check_uri_eq(cloneNewRef, origURI); 599 do_check_uri_eq(cloneNewRef, cloneNoRef); 600 Assert.ok(!cloneNewRef.equals(testURI)); 601 602 do_info( 603 "testing cloneWithNewRef on " + 604 origURI.spec + 605 " with the same new ref is equal to ref version and not equal to no-ref version" 606 ); 607 cloneNewRef = origURI.mutate().setRef(aSuffix).finalize(); 608 do_check_uri_eq(cloneNewRef, testURI); 609 Assert.ok(cloneNewRef.equals(testURI)); 610 } 611 612 do_check_property(aTest, testURI, "scheme"); 613 do_check_property(aTest, testURI, "prePath"); 614 if (!origURI.ref) { 615 // These don't work if it's a ref already because '+' doesn't give the right result 616 do_check_property(aTest, testURI, "pathQueryRef", function (aStr) { 617 return aStr + aSuffix; 618 }); 619 do_check_property(aTest, testURI, "ref", function () { 620 return aSuffix.substr(1); 621 }); 622 } 623 } 624 625 // Tests various ways of setting & clearing a ref on a URI. 626 function do_test_mutate_ref(aTest, aSuffix) { 627 do_info("making sure caller is using suffix that starts with '#'"); 628 Assert.equal(aSuffix[0], "#"); 629 630 var refURIWithSuffix = NetUtil.newURI(aTest.spec + aSuffix); 631 var refURIWithoutSuffix = NetUtil.newURI(aTest.spec); 632 633 var testURI = NetUtil.newURI(aTest.spec); 634 635 // First: Try setting .ref to our suffix 636 do_info( 637 "testing that setting .ref on " + 638 aTest.spec + 639 " to '" + 640 aSuffix + 641 "' does what we expect" 642 ); 643 testURI = testURI.mutate().setRef(aSuffix).finalize(); 644 do_check_uri_eq(testURI, refURIWithSuffix); 645 do_check_uri_eqExceptRef(testURI, refURIWithoutSuffix); 646 647 // Now try setting .ref but leave off the initial hash (expect same result) 648 var suffixLackingHash = aSuffix.substr(1); 649 if (suffixLackingHash) { 650 // (skip this our suffix was *just* a #) 651 do_info( 652 "testing that setting .ref on " + 653 aTest.spec + 654 " to '" + 655 suffixLackingHash + 656 "' does what we expect" 657 ); 658 testURI = testURI.mutate().setRef(suffixLackingHash).finalize(); 659 do_check_uri_eq(testURI, refURIWithSuffix); 660 do_check_uri_eqExceptRef(testURI, refURIWithoutSuffix); 661 } 662 663 // Now, clear .ref (should get us back the original spec) 664 do_info( 665 "testing that clearing .ref on " + testURI.spec + " does what we expect" 666 ); 667 testURI = testURI.mutate().setRef("").finalize(); 668 do_check_uri_eq(testURI, refURIWithoutSuffix); 669 do_check_uri_eqExceptRef(testURI, refURIWithSuffix); 670 671 if (!aTest.relativeURI) { 672 // TODO: These tests don't work as-is for relative URIs. 673 674 // Now try setting .spec directly (including suffix) and then clearing .ref 675 var specWithSuffix = aTest.spec + aSuffix; 676 do_info( 677 "testing that setting spec to " + 678 specWithSuffix + 679 " and then clearing ref does what we expect" 680 ); 681 682 testURI = testURI.mutate().setSpec(specWithSuffix).setRef("").finalize(); 683 do_check_uri_eq(testURI, refURIWithoutSuffix); 684 do_check_uri_eqExceptRef(testURI, refURIWithSuffix); 685 686 // XXX nsIJARURI throws an exception in SetPath(), so skip it for next part. 687 if (!(testURI instanceof Ci.nsIJARURI)) { 688 // Now try setting .pathQueryRef directly (including suffix) and then clearing .ref 689 // (same as above, but with now with .pathQueryRef instead of .spec) 690 testURI = NetUtil.newURI(aTest.spec); 691 692 var pathWithSuffix = aTest.pathQueryRef + aSuffix; 693 do_info( 694 "testing that setting path to " + 695 pathWithSuffix + 696 " and then clearing ref does what we expect" 697 ); 698 testURI = testURI 699 .mutate() 700 .setPathQueryRef(pathWithSuffix) 701 .setRef("") 702 .finalize(); 703 do_check_uri_eq(testURI, refURIWithoutSuffix); 704 do_check_uri_eqExceptRef(testURI, refURIWithSuffix); 705 706 // Also: make sure that clearing .pathQueryRef also clears .ref 707 testURI = testURI.mutate().setPathQueryRef(pathWithSuffix).finalize(); 708 do_info( 709 "testing that clearing path from " + 710 pathWithSuffix + 711 " also clears .ref" 712 ); 713 testURI = testURI.mutate().setPathQueryRef("").finalize(); 714 Assert.equal(testURI.ref, ""); 715 } 716 } 717 } 718 719 // Check that changing nested/about URIs works correctly. 720 add_task(function check_nested_mutations() { 721 // nsNestedAboutURI 722 let uri1 = Services.io.newURI("about:blank#"); 723 let uri2 = Services.io.newURI("about:blank"); 724 let uri3 = uri1.mutate().setRef("").finalize(); 725 do_check_uri_eq(uri3, uri2); 726 uri3 = uri2.mutate().setRef("#").finalize(); 727 do_check_uri_eq(uri3, uri1); 728 729 uri1 = Services.io.newURI("about:blank?something"); 730 uri2 = Services.io.newURI("about:blank"); 731 uri3 = uri1.mutate().setQuery("").finalize(); 732 do_check_uri_eq(uri3, uri2); 733 uri3 = uri2.mutate().setQuery("something").finalize(); 734 do_check_uri_eq(uri3, uri1); 735 736 uri1 = Services.io.newURI("about:blank?query#ref"); 737 uri2 = Services.io.newURI("about:blank"); 738 uri3 = uri1.mutate().setPathQueryRef("blank").finalize(); 739 do_check_uri_eq(uri3, uri2); 740 uri3 = uri2.mutate().setPathQueryRef("blank?query#ref").finalize(); 741 do_check_uri_eq(uri3, uri1); 742 743 // nsSimpleNestedURI 744 uri1 = Services.io.newURI("view-source:http://example.com/path#"); 745 uri2 = Services.io.newURI("view-source:http://example.com/path"); 746 uri3 = uri1.mutate().setRef("").finalize(); 747 do_check_uri_eq(uri3, uri2); 748 uri3 = uri2.mutate().setRef("#").finalize(); 749 do_check_uri_eq(uri3, uri1); 750 751 uri1 = Services.io.newURI("view-source:http://example.com/path?something"); 752 uri2 = Services.io.newURI("view-source:http://example.com/path"); 753 uri3 = uri1.mutate().setQuery("").finalize(); 754 do_check_uri_eq(uri3, uri2); 755 uri3 = uri2.mutate().setQuery("something").finalize(); 756 do_check_uri_eq(uri3, uri1); 757 758 uri1 = Services.io.newURI("view-source:http://example.com/path?query#ref"); 759 uri2 = Services.io.newURI("view-source:http://example.com/path"); 760 uri3 = uri1.mutate().setPathQueryRef("path").finalize(); 761 do_check_uri_eq(uri3, uri2); 762 uri3 = uri2.mutate().setPathQueryRef("path?query#ref").finalize(); 763 do_check_uri_eq(uri3, uri1); 764 765 uri1 = Services.io.newURI("view-source:about:blank#"); 766 uri2 = Services.io.newURI("view-source:about:blank"); 767 uri3 = uri1.mutate().setRef("").finalize(); 768 do_check_uri_eq(uri3, uri2); 769 uri3 = uri2.mutate().setRef("#").finalize(); 770 do_check_uri_eq(uri3, uri1); 771 772 uri1 = Services.io.newURI("view-source:about:blank?something"); 773 uri2 = Services.io.newURI("view-source:about:blank"); 774 uri3 = uri1.mutate().setQuery("").finalize(); 775 do_check_uri_eq(uri3, uri2); 776 uri3 = uri2.mutate().setQuery("something").finalize(); 777 do_check_uri_eq(uri3, uri1); 778 779 uri1 = Services.io.newURI("view-source:about:blank?query#ref"); 780 uri2 = Services.io.newURI("view-source:about:blank"); 781 uri3 = uri1.mutate().setPathQueryRef("blank").finalize(); 782 do_check_uri_eq(uri3, uri2); 783 uri3 = uri2.mutate().setPathQueryRef("blank?query#ref").finalize(); 784 do_check_uri_eq(uri3, uri1); 785 }); 786 787 add_task(function check_space_escaping() { 788 let uri = Services.io.newURI("data:text/plain,hello%20world#space hash"); 789 Assert.equal(uri.spec, "data:text/plain,hello%20world#space%20hash"); 790 uri = Services.io.newURI("data:text/plain,hello%20world#space%20hash"); 791 Assert.equal(uri.spec, "data:text/plain,hello%20world#space%20hash"); 792 uri = Services.io.newURI("data:text/plain,hello world#space%20hash"); 793 Assert.equal(uri.spec, "data:text/plain,hello world#space%20hash"); 794 uri = Services.io.newURI("data:text/plain,hello world#space hash"); 795 Assert.equal(uri.spec, "data:text/plain,hello world#space%20hash"); 796 uri = Services.io.newURI("http://example.com/test path#test path"); 797 uri = Services.io.newURI("http://example.com/test%20path#test%20path"); 798 }); 799 800 add_task(function check_space_with_query_and_ref() { 801 let url = Services.io.newURI("data:space"); 802 Assert.equal(url.spec, "data:space"); 803 804 url = Services.io.newURI("data:space ?"); 805 Assert.equal(url.spec, "data:space ?"); 806 url = Services.io.newURI("data:space #"); 807 Assert.equal(url.spec, "data:space #"); 808 809 url = Services.io.newURI("data:space?"); 810 Assert.equal(url.spec, "data:space?"); 811 url = Services.io.newURI("data:space#"); 812 Assert.equal(url.spec, "data:space#"); 813 814 url = Services.io.newURI("data:space ?query"); 815 Assert.equal(url.spec, "data:space ?query"); 816 url = url.mutate().setQuery("").finalize(); 817 Assert.equal(url.spec, "data:space"); 818 819 url = Services.io.newURI("data:space #ref"); 820 Assert.equal(url.spec, "data:space #ref"); 821 url = url.mutate().setRef("").finalize(); 822 Assert.equal(url.spec, "data:space"); 823 824 url = Services.io.newURI("data:space?query#ref"); 825 Assert.equal(url.spec, "data:space?query#ref"); 826 url = url.mutate().setRef("").finalize(); 827 Assert.equal(url.spec, "data:space?query"); 828 url = url.mutate().setQuery("").finalize(); 829 Assert.equal(url.spec, "data:space"); 830 831 url = Services.io.newURI("data:space#ref?query"); 832 Assert.equal(url.spec, "data:space#ref?query"); 833 url = url.mutate().setQuery("").finalize(); 834 Assert.equal(url.spec, "data:space#ref?query"); 835 url = url.mutate().setRef("").finalize(); 836 Assert.equal(url.spec, "data:space"); 837 838 url = Services.io.newURI("data:space ?query#ref"); 839 Assert.equal(url.spec, "data:space ?query#ref"); 840 url = url.mutate().setRef("").finalize(); 841 Assert.equal(url.spec, "data:space ?query"); 842 url = url.mutate().setQuery("").finalize(); 843 Assert.equal(url.spec, "data:space"); 844 845 url = Services.io.newURI("data:space #ref?query"); 846 Assert.equal(url.spec, "data:space #ref?query"); 847 url = url.mutate().setQuery("").finalize(); 848 Assert.equal(url.spec, "data:space #ref?query"); 849 url = url.mutate().setRef("").finalize(); 850 Assert.equal(url.spec, "data:space"); 851 }); 852 853 add_task(function check_schemeIsNull() { 854 let uri = Services.io.newURI("data:text/plain,aaa"); 855 Assert.ok(!uri.schemeIs(null)); 856 uri = Services.io.newURI("http://example.com"); 857 Assert.ok(!uri.schemeIs(null)); 858 uri = Services.io.newURI("dummyscheme://example.com"); 859 Assert.ok(!uri.schemeIs(null)); 860 uri = Services.io.newURI("jar:resource://gre/chrome.toolkit.jar!/"); 861 Assert.ok(!uri.schemeIs(null)); 862 uri = Services.io.newURI("moz-icon://.unknown?size=32"); 863 Assert.ok(!uri.schemeIs(null)); 864 }); 865 866 // Check that characters in the query of moz-extension aren't improperly unescaped (Bug 1547882) 867 add_task(function check_mozextension_query() { 868 let uri = Services.io.newURI( 869 "moz-extension://a7d1572e-3beb-4d93-a920-c408fa09e8ea/_source/holding.html" 870 ); 871 uri = uri 872 .mutate() 873 .setQuery("u=https%3A%2F%2Fnews.ycombinator.com%2F") 874 .finalize(); 875 Assert.equal(uri.query, "u=https%3A%2F%2Fnews.ycombinator.com%2F"); 876 uri = Services.io.newURI( 877 "moz-extension://a7d1572e-3beb-4d93-a920-c408fa09e8ea/_source/holding.html?u=https%3A%2F%2Fnews.ycombinator.com%2F" 878 ); 879 Assert.equal( 880 uri.spec, 881 "moz-extension://a7d1572e-3beb-4d93-a920-c408fa09e8ea/_source/holding.html?u=https%3A%2F%2Fnews.ycombinator.com%2F" 882 ); 883 Assert.equal(uri.query, "u=https%3A%2F%2Fnews.ycombinator.com%2F"); 884 }); 885 886 add_task(function check_resolve() { 887 let base = Services.io.newURI("http://example.com"); 888 let uri = Services.io.newURI("tel::+371 27028456", "utf-8", base); 889 Assert.equal(uri.spec, "tel::+371 27028456"); 890 }); 891 892 add_task(function test_extra_protocols() { 893 // dweb:// 894 let url = Services.io.newURI("dweb://example.com/test"); 895 Assert.equal(url.host, "example.com"); 896 897 // dat:// 898 url = Services.io.newURI( 899 "dat://41f8a987cfeba80a037e51cc8357d513b62514de36f2f9b3d3eeec7a8fb3b5a5/" 900 ); 901 Assert.equal( 902 url.host, 903 "41f8a987cfeba80a037e51cc8357d513b62514de36f2f9b3d3eeec7a8fb3b5a5" 904 ); 905 url = Services.io.newURI("dat://example.com/test"); 906 Assert.equal(url.host, "example.com"); 907 908 // ipfs:// 909 url = Services.io.newURI( 910 "ipfs://bafybeiccfclkdtucu6y4yc5cpr6y3yuinr67svmii46v5cfcrkp47ihehy/frontend/license.txt" 911 ); 912 Assert.equal(url.scheme, "ipfs"); 913 Assert.equal( 914 url.host, 915 "bafybeiccfclkdtucu6y4yc5cpr6y3yuinr67svmii46v5cfcrkp47ihehy" 916 ); 917 Assert.equal(url.filePath, "/frontend/license.txt"); 918 919 // ipns:// 920 url = Services.io.newURI("ipns://peerdium.gozala.io/index.html"); 921 Assert.equal(url.scheme, "ipns"); 922 Assert.equal(url.host, "peerdium.gozala.io"); 923 Assert.equal(url.filePath, "/index.html"); 924 925 // ssb:// 926 url = Services.io.newURI("ssb://scuttlebutt.nz/index.html"); 927 Assert.equal(url.scheme, "ssb"); 928 Assert.equal(url.host, "scuttlebutt.nz"); 929 Assert.equal(url.filePath, "/index.html"); 930 931 // wtp:// 932 url = Services.io.newURI( 933 "wtp://951ead31d09e4049fc1f21f137e233dd0589fcbd/blog/vim-tips/" 934 ); 935 Assert.equal(url.scheme, "wtp"); 936 Assert.equal(url.host, "951ead31d09e4049fc1f21f137e233dd0589fcbd"); 937 Assert.equal(url.filePath, "/blog/vim-tips/"); 938 }); 939 940 // TEST MAIN FUNCTION 941 // ------------------ 942 add_task(function mainTest() { 943 // UTF-8 check - From bug 622981 944 // ASCII 945 let base = Services.io.newURI("http://example.org/xenia?"); 946 let resolved = Services.io.newURI("?x", null, base); 947 let expected = Services.io.newURI("http://example.org/xenia?x"); 948 do_info( 949 "Bug 662981: ACSII - comparing " + resolved.spec + " and " + expected.spec 950 ); 951 Assert.ok(resolved.equals(expected)); 952 953 // UTF-8 character "è" 954 // Bug 622981 was triggered by an empty query string 955 base = Services.io.newURI("http://example.org/xènia?"); 956 resolved = Services.io.newURI("?x", null, base); 957 expected = Services.io.newURI("http://example.org/xènia?x"); 958 do_info( 959 "Bug 662981: UTF8 - comparing " + resolved.spec + " and " + expected.spec 960 ); 961 Assert.ok(resolved.equals(expected)); 962 963 gTests.forEach(function (aTest) { 964 // Check basic URI functionality 965 do_test_uri_basic(aTest); 966 967 if (!aTest.fail) { 968 // Try adding various #-prefixed strings to the ends of the URIs 969 gHashSuffixes.forEach(function (aSuffix) { 970 do_test_uri_with_hash_suffix(aTest, aSuffix); 971 if (!aTest.immutable) { 972 do_test_mutate_ref(aTest, aSuffix); 973 } 974 }); 975 976 // For URIs that we couldn't mutate above due to them being immutable: 977 // Now we check that they're actually immutable. 978 if (aTest.immutable) { 979 Assert.ok(aTest.immutable); 980 } 981 } 982 }); 983 }); 984 985 function check_round_trip_serialization(spec) { 986 dump(`checking ${spec}\n`); 987 let uri = Services.io.newURI(spec); 988 let str = serialize_to_escaped_string(uri); 989 let other = deserialize_from_escaped_string(str).QueryInterface(Ci.nsIURI); 990 equal(other.spec, uri.spec); 991 } 992 993 add_task(function test_iconURI_serialization() { 994 // URIs taken from test_moz_icon_uri.js 995 996 let tests = [ 997 "moz-icon://foo.html?contentType=bar&size=button&state=normal", 998 "moz-icon://foo.html?size=3", 999 "moz-icon://stock/foo", 1000 "moz-icon:file://foo.txt", 1001 "moz-icon://file://foo.txt", 1002 ]; 1003 1004 tests.forEach(str => check_round_trip_serialization(str)); 1005 }); 1006 1007 add_task(function test_jarURI_serialization() { 1008 check_round_trip_serialization("jar:http://example.com/bar.jar!/"); 1009 }); 1010 1011 add_task(async function round_trip_invalid_ace_label() { 1012 // This is well-formed punycode, but an invalid ACE label due to hyphens in 1013 // positions 3 & 4 and trailing hyphen. (Punycode-decode yields "xn--d淾-") 1014 let uri = Services.io.newURI("http://xn--xn--d--fg4n/"); 1015 Assert.equal(uri.spec, "http://xn--xn--d--fg4n/"); 1016 1017 // Entirely invalid punycode will throw a MALFORMED error. 1018 Assert.throws(() => { 1019 uri = Services.io.newURI("http://a.b.c.XN--pokxncvks"); 1020 }, /NS_ERROR_MALFORMED_URI/); 1021 }); 1022 1023 add_task(async function test_bug1875119() { 1024 let uri1 = Services.io.newURI("file:///path"); 1025 let uri2 = Services.io.newURI("resource://test/bla"); 1026 // type of uri2 is still SubstitutingURL which overrides the implementation of EnsureFile, 1027 // but it's scheme is now file. 1028 // See https://bugzilla.mozilla.org/show_bug.cgi?id=1876483 to disallow this 1029 uri2 = uri2.mutate().setSpec("file:///path2").finalize(); 1030 // NOTE: this test was originally expecting `uri1.equals(uri2)` to be throwing 1031 // a NS_NOINTERFACE error (instead of hitting a crash) when the new test landed 1032 // as part of Bug 1875119, then as a side-effect of the fix applied by Bug 1926106 1033 // the expected behavior is for the call to not raise an NS_NOINTERFACE error anymore 1034 // but to be returning false instead (and so the test has been adjusted accordingly). 1035 Assert.ok(!uri1.equals(uri2), "Expect uri1.equals(uri2) to be false"); 1036 }); 1037 1038 add_task(async function test_bug1843717() { 1039 // Make sure file path normalization on windows 1040 // doesn't affect the hash of the URL. 1041 let base = Services.io.newURI("file:///abc\\def/"); 1042 let uri = Services.io.newURI("foo\\bar#x\\y", null, base); 1043 Assert.equal(uri.spec, "file:///abc/def/foo/bar#x\\y"); 1044 uri = Services.io.newURI("foo\\bar#xy", null, base); 1045 Assert.equal(uri.spec, "file:///abc/def/foo/bar#xy"); 1046 uri = Services.io.newURI("foo\\bar#", null, base); 1047 Assert.equal(uri.spec, "file:///abc/def/foo/bar#"); 1048 }); 1049 1050 add_task(async function test_bug1874118() { 1051 let base = Services.io.newURI("file:///tmp/mock/path"); 1052 let uri = Services.io.newURI("file:c:\\\\foo\\\\bar.html", null, base); 1053 Assert.equal(uri.spec, "file:///c://foo//bar.html"); 1054 1055 base = Services.io.newURI("file:///tmp/mock/path"); 1056 uri = Services.io.newURI("file:c|\\\\foo\\\\bar.html", null, base); 1057 Assert.equal(uri.spec, "file:///c://foo//bar.html"); 1058 1059 base = Services.io.newURI("file:///C:/"); 1060 uri = Services.io.newURI("..", null, base); 1061 Assert.equal(uri.spec, "file:///C:/"); 1062 1063 base = Services.io.newURI("file:///"); 1064 uri = Services.io.newURI("C|/hello/../../", null, base); 1065 Assert.equal(uri.spec, "file:///C:/"); 1066 1067 base = Services.io.newURI("file:///"); 1068 uri = Services.io.newURI("/C:/../../", null, base); 1069 Assert.equal(uri.spec, "file:///C:/"); 1070 1071 base = Services.io.newURI("file:///"); 1072 uri = Services.io.newURI("/C://../../", null, base); 1073 Assert.equal(uri.spec, "file:///C:/"); 1074 1075 base = Services.io.newURI("file:///tmp/mock/path"); 1076 uri = Services.io.newURI("C|/foo/bar", null, base); 1077 Assert.equal(uri.spec, "file:///C:/foo/bar"); 1078 1079 base = Services.io.newURI("file:///tmp/mock/path"); 1080 uri = Services.io.newURI("/C|/foo/bar", null, base); 1081 Assert.equal(uri.spec, "file:///C:/foo/bar"); 1082 }); 1083 1084 add_task(async function test_bug1911529() { 1085 let testcases = [ 1086 [ 1087 "https://github.com/coder/coder/edit/main/docs/./enterprise.md", 1088 "https://github.com/coder/coder/edit/main/docs/enterprise.md", 1089 "enterprise", 1090 ], 1091 ["https://domain.com/.", "https://domain.com/", ""], 1092 ["https://domain.com/%2e", "https://domain.com/", ""], 1093 ["https://domain.com/%2e%2E", "https://domain.com/", ""], 1094 ["https://domain.com/%2e%2E/.", "https://domain.com/", ""], 1095 ["https://domain.com/./test.md", "https://domain.com/test.md", "test"], 1096 [ 1097 "https://domain.com/dir/sub/%2e%2e/%2e/test.md", 1098 "https://domain.com/dir/test.md", 1099 "test", 1100 ], 1101 ["https://domain.com/dir/..", "https://domain.com/", ""], 1102 ]; 1103 1104 for (let t of testcases) { 1105 let uri = Services.io.newURI(t[0]); 1106 let uri2 = Services.io.newURI(t[1]); 1107 Assert.ok(uri.equals(uri2), `${uri} must equal ${uri2}`); 1108 Assert.equal(t[2], uri.QueryInterface(Ci.nsIURL).fileBaseName); 1109 } 1110 }); 1111 1112 add_task(async function test_bug1939493() { 1113 let uri = Services.io.newURI("resource:///components/"); 1114 uri = uri 1115 .mutate() 1116 .setUserPass("") 1117 .setUsername("") 1118 .setPassword("") 1119 .setPort(-1) 1120 .finalize(); 1121 Assert.equal(uri.spec, "resource:///components/"); 1122 1123 Assert.throws(() => { 1124 uri = uri.mutate().setUserPass("a:b").finalize(); 1125 }, /NS_ERROR_UNEXPECTED/); 1126 Assert.throws(() => { 1127 uri = uri.mutate().setUsername("a").finalize(); 1128 }, /NS_ERROR_UNEXPECTED/); 1129 Assert.throws(() => { 1130 uri = uri.mutate().setPassword("b").finalize(); 1131 }, /NS_ERROR_UNEXPECTED/); 1132 Assert.throws(() => { 1133 uri = uri.mutate().setPort(10).finalize(); 1134 }, /NS_ERROR_UNEXPECTED/); 1135 1136 // username, password and port doesn't really make sense for a resource URL 1137 // but they still behave as regular URLs so this should be valid. 1138 uri = uri.mutate().setHost("gre").finalize(); 1139 Assert.equal(uri.spec, "resource://gre/components/"); 1140 uri = uri.mutate().setUserPass("a:b").finalize(); 1141 Assert.equal(uri.spec, "resource://a:b@gre/components/"); 1142 uri = uri.mutate().setUsername("user").finalize(); 1143 Assert.equal(uri.spec, "resource://user:b@gre/components/"); 1144 uri = uri.mutate().setPassword("pass").finalize(); 1145 Assert.equal(uri.spec, "resource://user:pass@gre/components/"); 1146 uri = uri.mutate().setPort(10).finalize(); 1147 Assert.equal(uri.spec, "resource://user:pass@gre:10/components/"); 1148 1149 // Clearing the host should fail, as there are still user, port, pass in play. 1150 Assert.throws(() => { 1151 uri = uri.mutate().setHost("").finalize(); 1152 }, /NS_ERROR_MALFORMED_URI/); 1153 1154 uri = uri 1155 .mutate() 1156 .setUserPass("") 1157 .setUsername("") 1158 .setPassword("") 1159 .setPort(-1) 1160 .setHost("") 1161 .finalize(); 1162 1163 Assert.equal(uri.spec, "resource:///components/"); 1164 });