Bug 1931425 - Limit how often moz-label's #setStyles runs r=reusable-components-revie...
[gecko.git] / netwerk / test / unit / test_URIs.js
blobc7df0d1ebd82056d37db976bd909c7dfac89a92e
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/. */
6 "use strict";
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
11 // See also test_URIs2.js.
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/
17 // TEST DATA
18 // ---------
19 var gTests = [
21 spec: "about:blank",
22 scheme: "about",
23 prePath: "about:",
24 pathQueryRef: "blank",
25 ref: "",
26 nsIURL: false,
27 nsINestedURI: true,
28 immutable: true,
31 spec: "about:foobar",
32 scheme: "about",
33 prePath: "about:",
34 pathQueryRef: "foobar",
35 ref: "",
36 nsIURL: false,
37 nsINestedURI: false,
38 immutable: true,
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,
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,
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,
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,
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,
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,
97 spec: "file://",
98 scheme: "file",
99 prePath: "file://",
100 pathQueryRef: "/",
101 ref: "",
102 nsIURL: true,
103 nsINestedURI: false,
106 spec: "file:///",
107 scheme: "file",
108 prePath: "file://",
109 pathQueryRef: "/",
110 ref: "",
111 nsIURL: true,
112 nsINestedURI: false,
115 spec: "file:///myFile.html",
116 scheme: "file",
117 prePath: "file://",
118 pathQueryRef: "/myFile.html",
119 ref: "",
120 nsIURL: true,
121 nsINestedURI: false,
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,
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,
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,
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,
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,
176 //Bug 706249
178 spec: "gopher://mozilla.org/",
179 scheme: "gopher",
180 prePath: "gopher://mozilla.org",
181 pathQueryRef: "/",
182 ref: "",
183 nsIURL: false,
184 nsINestedURI: false,
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,
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,
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,
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,
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,
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,
249 spec: "jar:resource://!/",
250 scheme: "jar",
251 prePath: "jar:",
252 pathQueryRef: "resource:///!/",
253 ref: "",
254 nsIURL: true,
255 nsINestedURI: true,
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,
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,
276 spec: "javascript:new Date()",
277 scheme: "javascript",
278 prePath: "javascript:",
279 pathQueryRef: "new Date()",
280 ref: "",
281 nsIURL: false,
282 nsINestedURI: false,
285 spec: "blob:123456",
286 scheme: "blob",
287 prePath: "blob:",
288 pathQueryRef: "123456",
289 ref: "",
290 nsIURL: false,
291 nsINestedURI: false,
292 immutable: true,
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,
304 spec: "resource://gre/",
305 scheme: "resource",
306 prePath: "resource://gre",
307 pathQueryRef: "/",
308 ref: "",
309 nsIURL: true,
310 nsINestedURI: false,
313 spec: "resource://gre/components/",
314 scheme: "resource",
315 prePath: "resource://gre",
316 pathQueryRef: "/components/",
317 ref: "",
318 nsIURL: true,
319 nsINestedURI: false,
322 // Adding more? Consider adding to test_URIs2.js instead, so that neither
323 // test runs for *too* long, risking timeouts on slow platforms.
326 var gHashSuffixes = ["#", "#myRef", "#myRef?a=b", "#myRef#", "#myRef#x:yz"];
328 // TEST HELPER FUNCTIONS
329 // ---------------------
330 function do_info(text, stack) {
331 if (!stack) {
332 stack = Components.stack.caller;
335 dump(
336 "\n" +
337 "TEST-INFO | " +
338 stack.filename +
339 " | [" +
340 stack.name +
341 " : " +
342 stack.lineNumber +
343 "] " +
344 text +
345 "\n"
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.
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));
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);
369 // Checks that the URIs satisfy equalsExceptRef(), in both possible orderings.
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 + "')"
377 aCheckTrueFunc(aURI1.equalsExceptRef(aURI2));
378 do_info(
379 "(uri equalsExceptRef check: '" + aURI2.spec + "' == '" + aURI1.spec + "')"
381 aCheckTrueFunc(aURI2.equalsExceptRef(aURI1));
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];
393 do_info(
394 "testing " +
395 aPropertyName +
396 " of " +
397 (aTestFunctor ? "modified '" : "'") +
398 aTest.spec +
399 "' is '" +
400 expectedVal +
403 Assert.equal(aURI[aPropertyName], expectedVal);
407 // Test that a given URI parses correctly into its various components.
408 function do_test_uri_basic(aTest) {
409 var URI;
411 do_info(
412 "Basic tests for " +
413 aTest.spec +
414 " relative URI: " +
415 (aTest.relativeURI === undefined ? "(none)" : aTest.relativeURI)
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;
426 do_throw(e.result);
429 if (aTest.relativeURI) {
430 var relURI;
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
443 if (aTest.relativeFail) {
444 Assert.equal(e.result, aTest.relativeFail);
445 return;
447 do_throw(e.result);
449 do_info(
450 "relURI.pathQueryRef = " +
451 relURI.pathQueryRef +
452 ", was " +
453 URI.pathQueryRef
455 URI = relURI;
456 do_info("URI.pathQueryRef now = " + URI.pathQueryRef);
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);
468 do_info(
469 "testing that " +
470 aTest.spec +
471 " throws or returns false " +
472 "from equals(null)"
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;
483 Assert.ok(threw || !isEqualToNull);
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");
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"
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], "#");
512 var origURI = NetUtil.newURI(aTest.spec);
513 var testURI;
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
527 return;
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
542 return;
544 } else {
545 testURI = NetUtil.newURI(aTest.spec + aSuffix);
548 do_info(
549 "testing " +
550 aTest.spec +
551 " with '" +
552 aSuffix +
553 "' appended " +
554 "equals a clone of itself"
556 do_check_uri_eq(testURI, testURI.mutate().finalize());
558 do_info(
559 "testing " +
560 aTest.spec +
561 " doesn't equal self with '" +
562 aSuffix +
563 "' appended"
566 Assert.ok(!origURI.equals(testURI));
568 do_info(
569 "testing " +
570 aTest.spec +
571 " is equalExceptRef to self with '" +
572 aSuffix +
573 "' appended"
575 do_check_uri_eqExceptRef(origURI, testURI);
577 Assert.equal(testURI.hasRef, true);
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"
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));
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"
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));
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"
607 cloneNewRef = origURI.mutate().setRef(aSuffix).finalize();
608 do_check_uri_eq(cloneNewRef, testURI);
609 Assert.ok(cloneNewRef.equals(testURI));
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;
619 do_check_property(aTest, testURI, "ref", function () {
620 return aSuffix.substr(1);
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], "#");
630 var refURIWithSuffix = NetUtil.newURI(aTest.spec + aSuffix);
631 var refURIWithoutSuffix = NetUtil.newURI(aTest.spec);
633 var testURI = NetUtil.newURI(aTest.spec);
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"
643 testURI = testURI.mutate().setRef(aSuffix).finalize();
644 do_check_uri_eq(testURI, refURIWithSuffix);
645 do_check_uri_eqExceptRef(testURI, refURIWithoutSuffix);
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"
658 testURI = testURI.mutate().setRef(suffixLackingHash).finalize();
659 do_check_uri_eq(testURI, refURIWithSuffix);
660 do_check_uri_eqExceptRef(testURI, refURIWithoutSuffix);
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"
667 testURI = testURI.mutate().setRef("").finalize();
668 do_check_uri_eq(testURI, refURIWithoutSuffix);
669 do_check_uri_eqExceptRef(testURI, refURIWithSuffix);
671 if (!aTest.relativeURI) {
672 // TODO: These tests don't work as-is for relative URIs.
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"
682 testURI = testURI.mutate().setSpec(specWithSuffix).setRef("").finalize();
683 do_check_uri_eq(testURI, refURIWithoutSuffix);
684 do_check_uri_eqExceptRef(testURI, refURIWithSuffix);
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);
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"
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);
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"
713 testURI = testURI.mutate().setPathQueryRef("").finalize();
714 Assert.equal(testURI.ref, "");
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);
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);
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);
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);
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);
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);
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);
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);
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);
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");
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");
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 #");
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#");
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");
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");
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");
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");
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");
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");
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));
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"
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"
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"
883 Assert.equal(uri.query, "u=https%3A%2F%2Fnews.ycombinator.com%2F");
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");
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");
897 // dat://
898 url = Services.io.newURI(
899 "dat://41f8a987cfeba80a037e51cc8357d513b62514de36f2f9b3d3eeec7a8fb3b5a5/"
901 Assert.equal(
902 url.host,
903 "41f8a987cfeba80a037e51cc8357d513b62514de36f2f9b3d3eeec7a8fb3b5a5"
905 url = Services.io.newURI("dat://example.com/test");
906 Assert.equal(url.host, "example.com");
908 // ipfs://
909 url = Services.io.newURI(
910 "ipfs://bafybeiccfclkdtucu6y4yc5cpr6y3yuinr67svmii46v5cfcrkp47ihehy/frontend/license.txt"
912 Assert.equal(url.scheme, "ipfs");
913 Assert.equal(
914 url.host,
915 "bafybeiccfclkdtucu6y4yc5cpr6y3yuinr67svmii46v5cfcrkp47ihehy"
917 Assert.equal(url.filePath, "/frontend/license.txt");
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");
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");
931 // wtp://
932 url = Services.io.newURI(
933 "wtp://951ead31d09e4049fc1f21f137e233dd0589fcbd/blog/vim-tips/"
935 Assert.equal(url.scheme, "wtp");
936 Assert.equal(url.host, "951ead31d09e4049fc1f21f137e233dd0589fcbd");
937 Assert.equal(url.filePath, "/blog/vim-tips/");
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
951 Assert.ok(resolved.equals(expected));
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
961 Assert.ok(resolved.equals(expected));
963 gTests.forEach(function (aTest) {
964 // Check basic URI functionality
965 do_test_uri_basic(aTest);
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);
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);
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);
993 add_task(function test_iconURI_serialization() {
994 // URIs taken from test_moz_icon_uri.js
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",
1004 tests.forEach(str => check_round_trip_serialization(str));
1007 add_task(function test_jarURI_serialization() {
1008 check_round_trip_serialization("jar:http://example.com/bar.jar!/");
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/");
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/);
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");
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#");
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");
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");
1059 base = Services.io.newURI("file:///C:/");
1060 uri = Services.io.newURI("..", null, base);
1061 Assert.equal(uri.spec, "file:///C:/");
1063 base = Services.io.newURI("file:///");
1064 uri = Services.io.newURI("C|/hello/../../", null, base);
1065 Assert.equal(uri.spec, "file:///C:/");
1067 base = Services.io.newURI("file:///");
1068 uri = Services.io.newURI("/C:/../../", null, base);
1069 Assert.equal(uri.spec, "file:///C:/");
1071 base = Services.io.newURI("file:///");
1072 uri = Services.io.newURI("/C://../../", null, base);
1073 Assert.equal(uri.spec, "file:///C:/");
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");
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");
1084 add_task(async function test_bug1911529() {
1085 let testcases = [
1087 "https://github.com/coder/coder/edit/main/docs/./enterprise.md",
1088 "https://github.com/coder/coder/edit/main/docs/enterprise.md",
1089 "enterprise",
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"],
1097 "https://domain.com/dir/sub/%2e%2e/%2e/test.md",
1098 "https://domain.com/dir/test.md",
1099 "test",
1101 ["https://domain.com/dir/..", "https://domain.com/", ""],
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);
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/");
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/);
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/");
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/);
1154 uri = uri
1155 .mutate()
1156 .setUserPass("")
1157 .setUsername("")
1158 .setPassword("")
1159 .setPort(-1)
1160 .setHost("")
1161 .finalize();
1163 Assert.equal(uri.spec, "resource:///components/");