Bug 1857386 [wpt PR 42383] - Update wpt metadata, a=testonly
[gecko.git] / netwerk / test / unit / test_standardurl.js
blobcf3f7369291485625ac4e8ffd08feaca8e6e3b94
1 "use strict";
3 const gPrefs = Services.prefs;
5 function symmetricEquality(expect, a, b) {
6   /* Use if/else instead of |do_check_eq(expect, a.spec == b.spec)| so
7      that we get the specs output on the console if the check fails.
8    */
9   if (expect) {
10     /* Check all the sub-pieces too, since that can help with
11        debugging cases when equals() returns something unexpected */
12     /* We don't check port in the loop, because it can be defaulted in
13        some cases. */
14     [
15       "spec",
16       "prePath",
17       "scheme",
18       "userPass",
19       "username",
20       "password",
21       "hostPort",
22       "host",
23       "pathQueryRef",
24       "filePath",
25       "query",
26       "ref",
27       "directory",
28       "fileName",
29       "fileBaseName",
30       "fileExtension",
31     ].map(function (prop) {
32       dump("Testing '" + prop + "'\n");
33       Assert.equal(a[prop], b[prop]);
34     });
35   } else {
36     Assert.notEqual(a.spec, b.spec);
37   }
38   Assert.equal(expect, a.equals(b));
39   Assert.equal(expect, b.equals(a));
42 function stringToURL(str) {
43   return Cc["@mozilla.org/network/standard-url-mutator;1"]
44     .createInstance(Ci.nsIStandardURLMutator)
45     .init(Ci.nsIStandardURL.URLTYPE_AUTHORITY, 80, str, "UTF-8", null)
46     .finalize()
47     .QueryInterface(Ci.nsIURL);
50 function pairToURLs(pair) {
51   Assert.equal(pair.length, 2);
52   return pair.map(stringToURL);
55 add_test(function test_setEmptyPath() {
56   var pairs = [
57     ["http://example.com", "http://example.com/tests/dom/tests"],
58     ["http://example.com:80", "http://example.com/tests/dom/tests"],
59     ["http://example.com:80/", "http://example.com/tests/dom/test"],
60     ["http://example.com/", "http://example.com/tests/dom/tests"],
61     ["http://example.com/a", "http://example.com/tests/dom/tests"],
62     ["http://example.com:80/a", "http://example.com/tests/dom/tests"],
63   ].map(pairToURLs);
65   for (var [provided, target] of pairs) {
66     symmetricEquality(false, target, provided);
68     provided = provided.mutate().setPathQueryRef("").finalize();
69     target = target.mutate().setPathQueryRef("").finalize();
71     Assert.equal(provided.spec, target.spec);
72     symmetricEquality(true, target, provided);
73   }
74   run_next_test();
75 });
77 add_test(function test_setQuery() {
78   var pairs = [
79     ["http://example.com", "http://example.com/?foo"],
80     ["http://example.com/bar", "http://example.com/bar?foo"],
81     ["http://example.com#bar", "http://example.com/?foo#bar"],
82     ["http://example.com/#bar", "http://example.com/?foo#bar"],
83     ["http://example.com/?longerthanfoo#bar", "http://example.com/?foo#bar"],
84     ["http://example.com/?longerthanfoo", "http://example.com/?foo"],
85     /* And one that's nonempty but shorter than "foo" */
86     ["http://example.com/?f#bar", "http://example.com/?foo#bar"],
87     ["http://example.com/?f", "http://example.com/?foo"],
88   ].map(pairToURLs);
90   for (var [provided, target] of pairs) {
91     symmetricEquality(false, provided, target);
93     provided = provided
94       .mutate()
95       .setQuery("foo")
96       .finalize()
97       .QueryInterface(Ci.nsIURL);
99     Assert.equal(provided.spec, target.spec);
100     symmetricEquality(true, provided, target);
101   }
103   [provided, target] = [
104     "http://example.com/#",
105     "http://example.com/?foo#bar",
106   ].map(stringToURL);
107   symmetricEquality(false, provided, target);
108   provided = provided
109     .mutate()
110     .setQuery("foo")
111     .finalize()
112     .QueryInterface(Ci.nsIURL);
113   symmetricEquality(false, provided, target);
115   var newProvided = Services.io
116     .newURI("#bar", null, provided)
117     .QueryInterface(Ci.nsIURL);
119   Assert.equal(newProvided.spec, target.spec);
120   symmetricEquality(true, newProvided, target);
121   run_next_test();
124 add_test(function test_setRef() {
125   var tests = [
126     ["http://example.com", "", "http://example.com/"],
127     ["http://example.com:80", "", "http://example.com:80/"],
128     ["http://example.com:80/", "", "http://example.com:80/"],
129     ["http://example.com/", "", "http://example.com/"],
130     ["http://example.com/a", "", "http://example.com/a"],
131     ["http://example.com:80/a", "", "http://example.com:80/a"],
133     ["http://example.com", "x", "http://example.com/#x"],
134     ["http://example.com:80", "x", "http://example.com:80/#x"],
135     ["http://example.com:80/", "x", "http://example.com:80/#x"],
136     ["http://example.com/", "x", "http://example.com/#x"],
137     ["http://example.com/a", "x", "http://example.com/a#x"],
138     ["http://example.com:80/a", "x", "http://example.com:80/a#x"],
140     ["http://example.com", "xx", "http://example.com/#xx"],
141     ["http://example.com:80", "xx", "http://example.com:80/#xx"],
142     ["http://example.com:80/", "xx", "http://example.com:80/#xx"],
143     ["http://example.com/", "xx", "http://example.com/#xx"],
144     ["http://example.com/a", "xx", "http://example.com/a#xx"],
145     ["http://example.com:80/a", "xx", "http://example.com:80/a#xx"],
147     [
148       "http://example.com",
149       "xxxxxxxxxxxxxx",
150       "http://example.com/#xxxxxxxxxxxxxx",
151     ],
152     [
153       "http://example.com:80",
154       "xxxxxxxxxxxxxx",
155       "http://example.com:80/#xxxxxxxxxxxxxx",
156     ],
157     [
158       "http://example.com:80/",
159       "xxxxxxxxxxxxxx",
160       "http://example.com:80/#xxxxxxxxxxxxxx",
161     ],
162     [
163       "http://example.com/",
164       "xxxxxxxxxxxxxx",
165       "http://example.com/#xxxxxxxxxxxxxx",
166     ],
167     [
168       "http://example.com/a",
169       "xxxxxxxxxxxxxx",
170       "http://example.com/a#xxxxxxxxxxxxxx",
171     ],
172     [
173       "http://example.com:80/a",
174       "xxxxxxxxxxxxxx",
175       "http://example.com:80/a#xxxxxxxxxxxxxx",
176     ],
177   ];
179   for (var [before, ref, result] of tests) {
180     /* Test1: starting with empty ref */
181     var a = stringToURL(before);
182     a = a.mutate().setRef(ref).finalize().QueryInterface(Ci.nsIURL);
183     var b = stringToURL(result);
185     Assert.equal(a.spec, b.spec);
186     Assert.equal(ref, b.ref);
187     symmetricEquality(true, a, b);
189     /* Test2: starting with non-empty */
190     a = a.mutate().setRef("yyyy").finalize().QueryInterface(Ci.nsIURL);
191     var c = stringToURL(before);
192     c = c.mutate().setRef("yyyy").finalize().QueryInterface(Ci.nsIURL);
193     symmetricEquality(true, a, c);
195     /* Test3: reset the ref */
196     a = a.mutate().setRef("").finalize().QueryInterface(Ci.nsIURL);
197     symmetricEquality(true, a, stringToURL(before));
199     /* Test4: verify again after reset */
200     a = a.mutate().setRef(ref).finalize().QueryInterface(Ci.nsIURL);
201     symmetricEquality(true, a, b);
202   }
203   run_next_test();
206 // Bug 960014 - Make nsStandardURL::SetHost less magical around IPv6
207 add_test(function test_ipv6() {
208   var url = stringToURL("http://example.com");
209   url = url.mutate().setHost("[2001::1]").finalize();
210   Assert.equal(url.host, "2001::1");
212   url = stringToURL("http://example.com");
213   url = url.mutate().setHostPort("[2001::1]:30").finalize();
214   Assert.equal(url.host, "2001::1");
215   Assert.equal(url.port, 30);
216   Assert.equal(url.hostPort, "[2001::1]:30");
218   url = stringToURL("http://example.com");
219   url = url.mutate().setHostPort("2001:1").finalize();
220   Assert.equal(url.host, "0.0.7.209");
221   Assert.equal(url.port, 1);
222   Assert.equal(url.hostPort, "0.0.7.209:1");
223   run_next_test();
226 add_test(function test_ipv6_fail() {
227   var url = stringToURL("http://example.com");
229   Assert.throws(
230     () => {
231       url = url.mutate().setHost("2001::1").finalize();
232     },
233     /NS_ERROR_MALFORMED_URI/,
234     "missing brackets"
235   );
236   Assert.throws(
237     () => {
238       url = url.mutate().setHost("[2001::1]:20").finalize();
239     },
240     /NS_ERROR_MALFORMED_URI/,
241     "url.host with port"
242   );
243   Assert.throws(
244     () => {
245       url = url.mutate().setHost("[2001::1").finalize();
246     },
247     /NS_ERROR_MALFORMED_URI/,
248     "missing last bracket"
249   );
250   Assert.throws(
251     () => {
252       url = url.mutate().setHost("2001::1]").finalize();
253     },
254     /NS_ERROR_MALFORMED_URI/,
255     "missing first bracket"
256   );
257   Assert.throws(
258     () => {
259       url = url.mutate().setHost("2001[::1]").finalize();
260     },
261     /NS_ERROR_MALFORMED_URI/,
262     "bad bracket position"
263   );
264   Assert.throws(
265     () => {
266       url = url.mutate().setHost("[]").finalize();
267     },
268     /NS_ERROR_MALFORMED_URI/,
269     "empty IPv6 address"
270   );
271   Assert.throws(
272     () => {
273       url = url.mutate().setHost("[hello]").finalize();
274     },
275     /NS_ERROR_MALFORMED_URI/,
276     "bad IPv6 address"
277   );
278   Assert.throws(
279     () => {
280       url = url.mutate().setHost("[192.168.1.1]").finalize();
281     },
282     /NS_ERROR_MALFORMED_URI/,
283     "bad IPv6 address"
284   );
285   Assert.throws(
286     () => {
287       url = url.mutate().setHostPort("2001::1").finalize();
288     },
289     /NS_ERROR_MALFORMED_URI/,
290     "missing brackets"
291   );
292   Assert.throws(
293     () => {
294       url = url.mutate().setHostPort("[2001::1]30").finalize();
295     },
296     /NS_ERROR_MALFORMED_URI/,
297     "missing : after IP"
298   );
299   Assert.throws(
300     () => {
301       url = url.mutate().setHostPort("[2001:1]").finalize();
302     },
303     /NS_ERROR_MALFORMED_URI/,
304     "bad IPv6 address"
305   );
306   Assert.throws(
307     () => {
308       url = url.mutate().setHostPort("[2001:1]10").finalize();
309     },
310     /NS_ERROR_MALFORMED_URI/,
311     "bad IPv6 address"
312   );
313   Assert.throws(
314     () => {
315       url = url.mutate().setHostPort("[2001:1]10:20").finalize();
316     },
317     /NS_ERROR_MALFORMED_URI/,
318     "bad IPv6 address"
319   );
320   Assert.throws(
321     () => {
322       url = url.mutate().setHostPort("[2001:1]:10:20").finalize();
323     },
324     /NS_ERROR_MALFORMED_URI/,
325     "bad IPv6 address"
326   );
327   Assert.throws(
328     () => {
329       url = url.mutate().setHostPort("[2001:1").finalize();
330     },
331     /NS_ERROR_MALFORMED_URI/,
332     "bad IPv6 address"
333   );
334   Assert.throws(
335     () => {
336       url = url.mutate().setHostPort("2001]:1").finalize();
337     },
338     /NS_ERROR_MALFORMED_URI/,
339     "bad IPv6 address"
340   );
341   Assert.throws(
342     () => {
343       url = url.mutate().setHostPort("2001:1]").finalize();
344     },
345     /NS_ERROR_MALFORMED_URI/,
346     "bad IPv6 address"
347   );
348   Assert.throws(
349     () => {
350       url = url.mutate().setHostPort("").finalize();
351     },
352     /NS_ERROR_UNEXPECTED/,
353     "Empty hostPort should fail"
354   );
356   // These checks used to fail, but now don't (see bug 1433958 comment 57)
357   url = url.mutate().setHostPort("[2001::1]:").finalize();
358   Assert.equal(url.spec, "http://[2001::1]/");
359   url = url.mutate().setHostPort("[2002::1]:bad").finalize();
360   Assert.equal(url.spec, "http://[2002::1]/");
362   run_next_test();
365 add_test(function test_clearedSpec() {
366   var url = stringToURL("http://example.com/path");
367   Assert.throws(
368     () => {
369       url = url.mutate().setSpec("http: example").finalize();
370     },
371     /NS_ERROR_MALFORMED_URI/,
372     "set bad spec"
373   );
374   Assert.throws(
375     () => {
376       url = url.mutate().setSpec("").finalize();
377     },
378     /NS_ERROR_MALFORMED_URI/,
379     "set empty spec"
380   );
381   Assert.equal(url.spec, "http://example.com/path");
382   url = url
383     .mutate()
384     .setHost("allizom.org")
385     .finalize()
386     .QueryInterface(Ci.nsIURL);
388   var ref = stringToURL("http://allizom.org/path");
389   symmetricEquality(true, url, ref);
390   run_next_test();
393 add_test(function test_escapeBrackets() {
394   // Query
395   var url = stringToURL("http://example.com/?a[x]=1");
396   Assert.equal(url.spec, "http://example.com/?a[x]=1");
398   url = stringToURL("http://example.com/?a%5Bx%5D=1");
399   Assert.equal(url.spec, "http://example.com/?a%5Bx%5D=1");
401   url = stringToURL("http://[2001::1]/?a[x]=1");
402   Assert.equal(url.spec, "http://[2001::1]/?a[x]=1");
404   url = stringToURL("http://[2001::1]/?a%5Bx%5D=1");
405   Assert.equal(url.spec, "http://[2001::1]/?a%5Bx%5D=1");
407   // Path
408   url = stringToURL("http://example.com/brackets[x]/test");
409   Assert.equal(url.spec, "http://example.com/brackets[x]/test");
411   url = stringToURL("http://example.com/a%5Bx%5D/test");
412   Assert.equal(url.spec, "http://example.com/a%5Bx%5D/test");
413   run_next_test();
416 add_test(function test_escapeQuote() {
417   var url = stringToURL("http://example.com/#'");
418   Assert.equal(url.spec, "http://example.com/#'");
419   Assert.equal(url.ref, "'");
420   url = url.mutate().setRef("test'test").finalize();
421   Assert.equal(url.spec, "http://example.com/#test'test");
422   Assert.equal(url.ref, "test'test");
423   run_next_test();
426 add_test(function test_apostropheEncoding() {
427   // For now, single quote is escaped everywhere _except_ the path.
428   // This policy is controlled by the bitmask in nsEscape.cpp::EscapeChars[]
429   var url = stringToURL("http://example.com/dir'/file'.ext'");
430   Assert.equal(url.spec, "http://example.com/dir'/file'.ext'");
431   run_next_test();
434 add_test(function test_accentEncoding() {
435   var url = stringToURL("http://example.com/?hello=`");
436   Assert.equal(url.spec, "http://example.com/?hello=`");
437   Assert.equal(url.query, "hello=`");
439   url = stringToURL("http://example.com/?hello=%2C");
440   Assert.equal(url.spec, "http://example.com/?hello=%2C");
441   Assert.equal(url.query, "hello=%2C");
442   run_next_test();
445 add_test(
446   { skip_if: () => AppConstants.MOZ_APP_NAME == "thunderbird" },
447   function test_percentDecoding() {
448     var url = stringToURL("http://%70%61%73%74%65%62%69%6E.com");
449     Assert.equal(url.spec, "http://pastebin.com/");
451     // Disallowed hostname characters are rejected even when percent encoded
452     Assert.throws(
453       () => {
454         url = stringToURL("http://example.com%0a%23.google.com/");
455       },
456       /NS_ERROR_MALFORMED_URI/,
457       "invalid characters are not allowed"
458     );
459     run_next_test();
460   }
463 add_test(function test_hugeStringThrows() {
464   let prefs = Services.prefs;
465   let maxLen = prefs.getIntPref("network.standard-url.max-length");
466   let url = stringToURL("http://test:test@example.com");
468   let hugeString = new Array(maxLen + 1).fill("a").join("");
469   let setters = [
470     { method: "setSpec", qi: Ci.nsIURIMutator },
471     { method: "setUsername", qi: Ci.nsIURIMutator },
472     { method: "setPassword", qi: Ci.nsIURIMutator },
473     { method: "setFilePath", qi: Ci.nsIURIMutator },
474     { method: "setHostPort", qi: Ci.nsIURIMutator },
475     { method: "setHost", qi: Ci.nsIURIMutator },
476     { method: "setUserPass", qi: Ci.nsIURIMutator },
477     { method: "setPathQueryRef", qi: Ci.nsIURIMutator },
478     { method: "setQuery", qi: Ci.nsIURIMutator },
479     { method: "setRef", qi: Ci.nsIURIMutator },
480     { method: "setScheme", qi: Ci.nsIURIMutator },
481     { method: "setFileName", qi: Ci.nsIURLMutator },
482     { method: "setFileExtension", qi: Ci.nsIURLMutator },
483     { method: "setFileBaseName", qi: Ci.nsIURLMutator },
484   ];
486   for (let prop of setters) {
487     Assert.throws(
488       () =>
489         (url = url
490           .mutate()
491           .QueryInterface(prop.qi)
492           [prop.method](hugeString)
493           .finalize()),
494       /NS_ERROR_MALFORMED_URI/,
495       `Passing a huge string to "${prop.method}" should throw`
496     );
497   }
499   run_next_test();
502 add_test(function test_filterWhitespace() {
503   let url = stringToURL(
504     " \r\n\th\nt\rt\tp://ex\r\n\tample.com/path\r\n\t/\r\n\tto the/fil\r\n\te.e\r\n\txt?que\r\n\try#ha\r\n\tsh \r\n\t "
505   );
506   Assert.equal(
507     url.spec,
508     "http://example.com/path/to%20the/file.ext?query#hash"
509   );
511   // These setters should filter \r\n\t.
512   url = stringToURL("http://test.com/path?query#hash");
513   url = url.mutate().setFilePath("pa\r\n\tth").finalize();
514   Assert.equal(url.spec, "http://test.com/path?query#hash");
515   url = url.mutate().setQuery("que\r\n\try").finalize();
516   Assert.equal(url.spec, "http://test.com/path?query#hash");
517   url = url.mutate().setRef("ha\r\n\tsh").finalize();
518   Assert.equal(url.spec, "http://test.com/path?query#hash");
519   url = url
520     .mutate()
521     .QueryInterface(Ci.nsIURLMutator)
522     .setFileName("fi\r\n\tle.name")
523     .finalize();
524   Assert.equal(url.spec, "http://test.com/fi%0D%0A%09le.name?query#hash");
526   run_next_test();
529 add_test(function test_backslashReplacement() {
530   var url = stringToURL(
531     "http:\\\\test.com\\path/to\\file?query\\backslash#hash\\"
532   );
533   Assert.equal(
534     url.spec,
535     "http://test.com/path/to/file?query\\backslash#hash\\"
536   );
538   url = stringToURL("http:\\\\test.com\\example.org/path\\to/file");
539   Assert.equal(url.spec, "http://test.com/example.org/path/to/file");
540   Assert.equal(url.host, "test.com");
541   Assert.equal(url.pathQueryRef, "/example.org/path/to/file");
543   run_next_test();
546 add_test(function test_authority_host() {
547   Assert.throws(
548     () => {
549       stringToURL("http:");
550     },
551     /NS_ERROR_MALFORMED_URI/,
552     "TYPE_AUTHORITY should have host"
553   );
554   Assert.throws(
555     () => {
556       stringToURL("http:///");
557     },
558     /NS_ERROR_MALFORMED_URI/,
559     "TYPE_AUTHORITY should have host"
560   );
562   run_next_test();
565 add_test(function test_trim_C0_and_space() {
566   var url = stringToURL(
567     "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f http://example.com/ \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f "
568   );
569   Assert.equal(url.spec, "http://example.com/");
570   url = url
571     .mutate()
572     .setSpec(
573       "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f http://test.com/ \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f "
574     )
575     .finalize();
576   Assert.equal(url.spec, "http://test.com/");
577   Assert.throws(
578     () => {
579       url = url
580         .mutate()
581         .setSpec(
582           "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19 "
583         )
584         .finalize();
585     },
586     /NS_ERROR_MALFORMED_URI/,
587     "set empty spec"
588   );
589   run_next_test();
592 // This tests that C0-and-space characters in the path, query and ref are
593 // percent encoded.
594 add_test(function test_encode_C0_and_space() {
595   function toHex(d) {
596     var hex = d.toString(16);
597     if (hex.length == 1) {
598       hex = "0" + hex;
599     }
600     return hex.toUpperCase();
601   }
603   for (var i = 0x0; i <= 0x20; i++) {
604     // These characters get filtered - they are not encoded.
605     if (
606       String.fromCharCode(i) == "\r" ||
607       String.fromCharCode(i) == "\n" ||
608       String.fromCharCode(i) == "\t"
609     ) {
610       continue;
611     }
612     let url = stringToURL(
613       "http://example.com/pa" +
614         String.fromCharCode(i) +
615         "th?qu" +
616         String.fromCharCode(i) +
617         "ery#ha" +
618         String.fromCharCode(i) +
619         "sh"
620     );
621     Assert.equal(
622       url.spec,
623       "http://example.com/pa%" +
624         toHex(i) +
625         "th?qu%" +
626         toHex(i) +
627         "ery#ha%" +
628         toHex(i) +
629         "sh"
630     );
631   }
633   // Additionally, we need to check the setters.
634   let url = stringToURL("http://example.com/path?query#hash");
635   url = url.mutate().setFilePath("pa\0th").finalize();
636   Assert.equal(url.spec, "http://example.com/pa%00th?query#hash");
637   url = url.mutate().setQuery("qu\0ery").finalize();
638   Assert.equal(url.spec, "http://example.com/pa%00th?qu%00ery#hash");
639   url = url.mutate().setRef("ha\0sh").finalize();
640   Assert.equal(url.spec, "http://example.com/pa%00th?qu%00ery#ha%00sh");
641   url = url
642     .mutate()
643     .QueryInterface(Ci.nsIURLMutator)
644     .setFileName("fi\0le.name")
645     .finalize();
646   Assert.equal(url.spec, "http://example.com/fi%00le.name?qu%00ery#ha%00sh");
648   run_next_test();
651 add_test(function test_ipv4Normalize() {
652   var localIPv4s = [
653     "http://127.0.0.1",
654     "http://127.0.1",
655     "http://127.1",
656     "http://2130706433",
657     "http://0177.00.00.01",
658     "http://0177.00.01",
659     "http://0177.01",
660     "http://00000000000000000000000000177.0000000.0000000.0001",
661     "http://000000177.0000001",
662     "http://017700000001",
663     "http://0x7f.0x00.0x00.0x01",
664     "http://0x7f.0x01",
665     "http://0x7f000001",
666     "http://0x007f.0x0000.0x0000.0x0001",
667     "http://000177.0.00000.0x0001",
668     "http://127.0.0.1.",
669   ].map(stringToURL);
671   let url;
672   for (url of localIPv4s) {
673     Assert.equal(url.spec, "http://127.0.0.1/");
674   }
676   // These should treated as a domain instead of an IPv4.
677   var nonIPv4s = [
678     "http://2+3/",
679     "http://0.0.0.-1/",
680     "http://1.2.3.4../",
681     "resource://123/",
682     "resource://4294967296/",
683   ];
684   var spec;
685   for (spec of nonIPv4s) {
686     url = stringToURL(spec);
687     Assert.equal(url.spec, spec);
688   }
690   url = stringToURL("resource://path/to/resource/");
691   url = url.mutate().setHost("123").finalize();
692   Assert.equal(url.host, "123");
694   run_next_test();
697 add_test(function test_invalidHostChars() {
698   var url = stringToURL("http://example.org/");
699   for (let i = 0; i <= 0x20; i++) {
700     // These characters get filtered.
701     if (
702       String.fromCharCode(i) == "\r" ||
703       String.fromCharCode(i) == "\n" ||
704       String.fromCharCode(i) == "\t"
705     ) {
706       continue;
707     }
708     Assert.throws(
709       () => {
710         url = url
711           .mutate()
712           .setHost("a" + String.fromCharCode(i) + "b")
713           .finalize();
714       },
715       /NS_ERROR_MALFORMED_URI/,
716       "Trying to set hostname containing char code: " + i
717     );
718   }
719   for (let c of '@[]*<>|:"') {
720     Assert.throws(
721       () => {
722         url = url
723           .mutate()
724           .setHost("a" + c)
725           .finalize();
726       },
727       /NS_ERROR_MALFORMED_URI/,
728       "Trying to set hostname containing char: " + c
729     );
730   }
732   // It also can't contain /, \, #, ?, but we treat these characters as
733   // hostname separators, so there is no way to set them and fail.
734   run_next_test();
737 add_test(function test_normalize_ipv6() {
738   var url = stringToURL("http://example.com");
739   url = url.mutate().setHost("[::192.9.5.5]").finalize();
740   Assert.equal(url.spec, "http://[::c009:505]/");
742   run_next_test();
745 add_test(function test_emptyPassword() {
746   var url = stringToURL("http://a:@example.com");
747   Assert.equal(url.spec, "http://a@example.com/");
748   url = url.mutate().setPassword("pp").finalize();
749   Assert.equal(url.spec, "http://a:pp@example.com/");
750   url = url.mutate().setPassword("").finalize();
751   Assert.equal(url.spec, "http://a@example.com/");
752   url = url.mutate().setUserPass("xxx:").finalize();
753   Assert.equal(url.spec, "http://xxx@example.com/");
754   url = url.mutate().setPassword("zzzz").finalize();
755   Assert.equal(url.spec, "http://xxx:zzzz@example.com/");
756   url = url.mutate().setUserPass("xxxxx:yyyyyy").finalize();
757   Assert.equal(url.spec, "http://xxxxx:yyyyyy@example.com/");
758   url = url.mutate().setUserPass("z:").finalize();
759   Assert.equal(url.spec, "http://z@example.com/");
760   url = url.mutate().setPassword("ppppppppppp").finalize();
761   Assert.equal(url.spec, "http://z:ppppppppppp@example.com/");
763   url = stringToURL("http://example.com");
764   url = url.mutate().setPassword("").finalize(); // Still empty. Should work.
765   Assert.equal(url.spec, "http://example.com/");
767   run_next_test();
770 add_test(function test_emptyUser() {
771   let url = stringToURL("http://:a@example.com/path/to/something?query#hash");
772   Assert.equal(url.spec, "http://:a@example.com/path/to/something?query#hash");
773   url = stringToURL("http://:@example.com/path/to/something?query#hash");
774   Assert.equal(url.spec, "http://example.com/path/to/something?query#hash");
776   const kurl = stringToURL(
777     "http://user:pass@example.com:8888/path/to/something?query#hash"
778   );
779   url = kurl.mutate().setUsername("").finalize();
780   Assert.equal(
781     url.spec,
782     "http://:pass@example.com:8888/path/to/something?query#hash"
783   );
784   Assert.equal(url.host, "example.com");
785   Assert.equal(url.hostPort, "example.com:8888");
786   Assert.equal(url.filePath, "/path/to/something");
787   Assert.equal(url.query, "query");
788   Assert.equal(url.ref, "hash");
789   url = kurl.mutate().setUserPass(":pass1").finalize();
790   Assert.equal(
791     url.spec,
792     "http://:pass1@example.com:8888/path/to/something?query#hash"
793   );
794   Assert.equal(url.host, "example.com");
795   Assert.equal(url.hostPort, "example.com:8888");
796   Assert.equal(url.filePath, "/path/to/something");
797   Assert.equal(url.query, "query");
798   Assert.equal(url.ref, "hash");
799   url = url.mutate().setUsername("user2").finalize();
800   Assert.equal(
801     url.spec,
802     "http://user2:pass1@example.com:8888/path/to/something?query#hash"
803   );
804   Assert.equal(url.host, "example.com");
805   url = url.mutate().setUserPass(":pass234").finalize();
806   Assert.equal(
807     url.spec,
808     "http://:pass234@example.com:8888/path/to/something?query#hash"
809   );
810   Assert.equal(url.host, "example.com");
811   url = url.mutate().setUserPass("").finalize();
812   Assert.equal(
813     url.spec,
814     "http://example.com:8888/path/to/something?query#hash"
815   );
816   Assert.equal(url.host, "example.com");
817   url = url.mutate().setPassword("pa").finalize();
818   Assert.equal(
819     url.spec,
820     "http://:pa@example.com:8888/path/to/something?query#hash"
821   );
822   Assert.equal(url.host, "example.com");
823   url = url.mutate().setUserPass("user:pass").finalize();
824   symmetricEquality(true, url.QueryInterface(Ci.nsIURL), kurl);
826   url = stringToURL("http://example.com:8888/path/to/something?query#hash");
827   url = url.mutate().setPassword("pass").finalize();
828   Assert.equal(
829     url.spec,
830     "http://:pass@example.com:8888/path/to/something?query#hash"
831   );
832   url = url.mutate().setUsername("").finalize();
833   Assert.equal(
834     url.spec,
835     "http://:pass@example.com:8888/path/to/something?query#hash"
836   );
838   url = stringToURL("http://example.com:8888");
839   url = url.mutate().setUsername("user").finalize();
840   url = url.mutate().setUsername("").finalize();
841   Assert.equal(url.spec, "http://example.com:8888/");
843   url = stringToURL("http://:pass@example.com");
844   Assert.equal(url.spec, "http://:pass@example.com/");
845   url = url.mutate().setPassword("").finalize();
846   Assert.equal(url.spec, "http://example.com/");
847   url = url.mutate().setUserPass("user:pass").finalize();
848   Assert.equal(url.spec, "http://user:pass@example.com/");
849   Assert.equal(url.host, "example.com");
850   url = url.mutate().setUserPass("u:p").finalize();
851   Assert.equal(url.spec, "http://u:p@example.com/");
852   Assert.equal(url.host, "example.com");
853   url = url.mutate().setUserPass("u1:p23").finalize();
854   Assert.equal(url.spec, "http://u1:p23@example.com/");
855   Assert.equal(url.host, "example.com");
856   url = url.mutate().setUsername("u").finalize();
857   Assert.equal(url.spec, "http://u:p23@example.com/");
858   Assert.equal(url.host, "example.com");
859   url = url.mutate().setPassword("p").finalize();
860   Assert.equal(url.spec, "http://u:p@example.com/");
861   Assert.equal(url.host, "example.com");
863   url = url.mutate().setUserPass("u2:p2").finalize();
864   Assert.equal(url.spec, "http://u2:p2@example.com/");
865   Assert.equal(url.host, "example.com");
866   url = url.mutate().setUserPass("u23:p23").finalize();
867   Assert.equal(url.spec, "http://u23:p23@example.com/");
868   Assert.equal(url.host, "example.com");
870   run_next_test();
873 registerCleanupFunction(function () {
874   gPrefs.clearUserPref("network.standard-url.punycode-host");
877 add_test(function test_idna_host() {
878   // See bug 945240 - this test makes sure that URLs return a punycode hostname
879   let url = stringToURL(
880     "http://user:password@ält.example.org:8080/path?query#etc"
881   );
882   equal(url.host, "xn--lt-uia.example.org");
883   equal(url.hostPort, "xn--lt-uia.example.org:8080");
884   equal(url.prePath, "http://user:password@xn--lt-uia.example.org:8080");
885   equal(
886     url.spec,
887     "http://user:password@xn--lt-uia.example.org:8080/path?query#etc"
888   );
889   equal(
890     url.specIgnoringRef,
891     "http://user:password@xn--lt-uia.example.org:8080/path?query"
892   );
893   equal(
894     url
895       .QueryInterface(Ci.nsISensitiveInfoHiddenURI)
896       .getSensitiveInfoHiddenSpec(),
897     "http://user:****@xn--lt-uia.example.org:8080/path?query#etc"
898   );
900   equal(url.displayHost, "ält.example.org");
901   equal(url.displayHostPort, "ält.example.org:8080");
902   equal(
903     url.displaySpec,
904     "http://user:password@ält.example.org:8080/path?query#etc"
905   );
907   equal(url.asciiHost, "xn--lt-uia.example.org");
908   equal(url.asciiHostPort, "xn--lt-uia.example.org:8080");
909   equal(
910     url.asciiSpec,
911     "http://user:password@xn--lt-uia.example.org:8080/path?query#etc"
912   );
914   url = url.mutate().setRef("").finalize(); // SetRef calls InvalidateCache()
915   equal(
916     url.spec,
917     "http://user:password@xn--lt-uia.example.org:8080/path?query"
918   );
919   equal(
920     url.displaySpec,
921     "http://user:password@ält.example.org:8080/path?query"
922   );
923   equal(
924     url.asciiSpec,
925     "http://user:password@xn--lt-uia.example.org:8080/path?query"
926   );
928   url = stringToURL("http://user:password@www.ält.com:8080/path?query#etc");
929   url = url.mutate().setRef("").finalize();
930   equal(url.spec, "http://user:password@www.xn--lt-uia.com:8080/path?query");
932   run_next_test();
935 add_test(
936   { skip_if: () => AppConstants.MOZ_APP_NAME == "thunderbird" },
937   function test_bug1517025() {
938     Assert.throws(
939       () => {
940         stringToURL("https://b%9a/");
941       },
942       /NS_ERROR_MALFORMED_URI/,
943       "bad URI"
944     );
946     Assert.throws(
947       () => {
948         stringToURL("https://b%9ª/");
949       },
950       /NS_ERROR_MALFORMED_URI/,
951       "bad URI"
952     );
954     let base = stringToURL(
955       "https://bug1517025.bmoattachments.org/attachment.cgi?id=9033787"
956     );
957     Assert.throws(
958       () => {
959         Services.io.newURI("/\\b%9ª", "windows-1252", base);
960       },
961       /NS_ERROR_MALFORMED_URI/,
962       "bad URI"
963     );
965     run_next_test();
966   }
969 add_task(async function test_emptyHostWithURLType() {
970   let makeURL = (str, type) => {
971     return Cc["@mozilla.org/network/standard-url-mutator;1"]
972       .createInstance(Ci.nsIStandardURLMutator)
973       .init(type, 80, str, "UTF-8", null)
974       .finalize()
975       .QueryInterface(Ci.nsIURL);
976   };
978   let url = makeURL("http://foo.com/bar/", Ci.nsIStandardURL.URLTYPE_AUTHORITY);
979   Assert.throws(
980     () => url.mutate().setHost("").finalize().spec,
981     /NS_ERROR_UNEXPECTED/,
982     "Empty host is not allowed for URLTYPE_AUTHORITY"
983   );
985   url = makeURL("http://foo.com/bar/", Ci.nsIStandardURL.URLTYPE_STANDARD);
986   Assert.throws(
987     () => url.mutate().setHost("").finalize().spec,
988     /NS_ERROR_UNEXPECTED/,
989     "Empty host is not allowed for URLTYPE_STANDARD"
990   );
992   url = makeURL("http://foo.com/bar/", Ci.nsIStandardURL.URLTYPE_NO_AUTHORITY);
993   equal(
994     url.spec,
995     "http:///bar/",
996     "Host is removed when parsing URLTYPE_NO_AUTHORITY"
997   );
998   equal(
999     url.mutate().setHost("").finalize().spec,
1000     "http:///bar/",
1001     "Setting an empty host does nothing for URLTYPE_NO_AUTHORITY"
1002   );
1003   Assert.throws(
1004     () => url.mutate().setHost("something").finalize().spec,
1005     /NS_ERROR_UNEXPECTED/,
1006     "Setting a non-empty host is not allowed for URLTYPE_NO_AUTHORITY"
1007   );
1008   equal(
1009     url.mutate().setHost("#j").finalize().spec,
1010     "http:///bar/",
1011     "Setting a pseudo-empty host does nothing for URLTYPE_NO_AUTHORITY"
1012   );
1014   url = makeURL(
1015     "http://example.org:123/foo?bar#baz",
1016     Ci.nsIStandardURL.URLTYPE_AUTHORITY
1017   );
1018   Assert.throws(
1019     () => url.mutate().setHost("#j").finalize().spec,
1020     /NS_ERROR_UNEXPECTED/,
1021     "A pseudo-empty host is not allowed for URLTYPE_AUTHORITY"
1022   );
1025 add_task(async function test_fuzz() {
1026   let makeURL = str => {
1027     return (
1028       Cc["@mozilla.org/network/standard-url-mutator;1"]
1029         .createInstance(Ci.nsIStandardURLMutator)
1030         .QueryInterface(Ci.nsIURIMutator)
1031         // .init(type, 80, str, "UTF-8", null)
1032         .setSpec(str)
1033         .finalize()
1034         .QueryInterface(Ci.nsIURL)
1035     );
1036   };
1038   Assert.throws(() => {
1039     let url = makeURL("/");
1040     url.mutate().setHost("(").finalize();
1041   }, /NS_ERROR_MALFORMED_URI/);
1044 add_task(async function test_bug1648493() {
1045   let url = stringToURL("https://example.com/");
1046   url = url.mutate().setScheme("file").finalize();
1047   url = url.mutate().setScheme("resource").finalize();
1048   url = url.mutate().setPassword("ê").finalize();
1049   url = url.mutate().setUsername("ç").finalize();
1050   url = url.mutate().setScheme("t").finalize();
1051   equal(url.spec, "t://%C3%83%C2%A7:%C3%83%C2%AA@example.com/");
1052   equal(url.username, "%C3%83%C2%A7");