Merge autoland to mozilla-central. a=merge
[gecko.git] / netwerk / test / unit / test_standardurl.js
blob4d02fb868307be0736a5e69224ab73527e36d85b
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_verticalBar() {
503   var url = Services.io.newURI("file:///w|m");
504   Assert.equal(url.spec, "file:///w|m");
506   url = Services.io.newURI("file:///w||m");
507   Assert.equal(url.spec, "file:///w||m");
509   url = Services.io.newURI("file:///w|/m");
510   Assert.equal(url.spec, "file:///w:/m");
512   url = Services.io.newURI("file:C|/m/");
513   Assert.equal(url.spec, "file:///C:/m/");
515   url = Services.io.newURI("file:C||/m/");
516   Assert.equal(url.spec, "file:///C||/m/");
518   run_next_test();
521 add_test(function test_pathPercentEncodedDot() {
522   var url = stringToURL("http://example.com/hello/%2e%2E/%2e");
523   Assert.equal(url.spec, "http://example.com/");
524   Assert.equal(url.directory, "/");
525   Assert.equal(url.fileName, "");
526   Assert.equal(url.fileBaseName, "");
527   Assert.equal(url.fileExtension, "");
529   url = stringToURL("http://example.com/hello/%2e%2E/%");
530   Assert.equal(url.spec, "http://example.com/%");
531   Assert.equal(url.directory, "/");
532   Assert.equal(url.fileName, "%");
533   Assert.equal(url.fileBaseName, "%");
534   Assert.equal(url.fileExtension, "");
536   url = stringToURL("http://example.com/hello/%2e%2E/%2");
537   Assert.equal(url.spec, "http://example.com/%2");
538   Assert.equal(url.directory, "/");
539   Assert.equal(url.fileName, "%2");
540   Assert.equal(url.fileBaseName, "%2");
541   Assert.equal(url.fileExtension, "");
543   url = stringToURL("http://example.com/hello/%2e%2E/%#");
544   Assert.equal(url.spec, "http://example.com/%#");
545   Assert.equal(url.directory, "/");
546   Assert.equal(url.fileName, "%");
547   Assert.equal(url.fileBaseName, "%");
548   Assert.equal(url.fileExtension, "");
550   url = stringToURL("http://example.com/hello/%2e%2E/%2?");
551   Assert.equal(url.spec, "http://example.com/%2?");
552   Assert.equal(url.directory, "/");
553   Assert.equal(url.fileName, "%2");
554   Assert.equal(url.fileBaseName, "%2");
555   Assert.equal(url.fileExtension, "");
557   url = stringToURL("http://example.com/hello/%2e/");
558   Assert.equal(url.spec, "http://example.com/hello/");
559   Assert.equal(url.directory, "/hello/");
560   Assert.equal(url.fileName, "");
561   Assert.equal(url.fileBaseName, "");
562   Assert.equal(url.fileExtension, "");
564   url = stringToURL("http://example.com/%2e");
565   Assert.equal(url.spec, "http://example.com/");
566   Assert.equal(url.directory, "/");
567   Assert.equal(url.fileName, "");
568   Assert.equal(url.fileBaseName, "");
569   Assert.equal(url.fileExtension, "");
571   url = stringToURL("http://example.com/.%2e");
572   Assert.equal(url.spec, "http://example.com/");
573   Assert.equal(url.directory, "/");
574   Assert.equal(url.fileName, "");
575   Assert.equal(url.fileBaseName, "");
576   Assert.equal(url.fileExtension, "");
578   url = stringToURL("http://example.com/%2e.");
579   Assert.equal(url.spec, "http://example.com/");
580   Assert.equal(url.directory, "/");
581   Assert.equal(url.fileName, "");
582   Assert.equal(url.fileBaseName, "");
583   Assert.equal(url.fileExtension, "");
585   url = stringToURL("http://example.com/%2e%2e");
586   Assert.equal(url.spec, "http://example.com/");
587   Assert.equal(url.directory, "/");
588   Assert.equal(url.fileName, "");
589   Assert.equal(url.fileBaseName, "");
590   Assert.equal(url.fileExtension, "");
592   url = stringToURL("http://example.com/%2e%2e%2e");
593   Assert.equal(url.spec, "http://example.com/%2e%2e%2e");
594   Assert.equal(url.directory, "/");
595   Assert.equal(url.fileName, "%2e%2e%2e");
596   Assert.equal(url.fileBaseName, "%2e%2e%2e");
597   Assert.equal(url.fileExtension, "");
599   url = stringToURL("http://example.com/%2e%2e%2e%2e");
600   Assert.equal(url.spec, "http://example.com/%2e%2e%2e%2e");
601   Assert.equal(url.directory, "/");
602   Assert.equal(url.fileName, "%2e%2e%2e%2e");
603   Assert.equal(url.fileBaseName, "%2e%2e%2e%2e");
604   Assert.equal(url.fileExtension, "");
606   url = stringToURL("http://example.com/hello/%2e%2");
607   Assert.equal(url.spec, "http://example.com/hello/%2e%2");
608   Assert.equal(url.directory, "/hello/");
609   Assert.equal(url.fileName, "%2e%2");
610   Assert.equal(url.fileBaseName, "%2e%2");
611   Assert.equal(url.fileExtension, "");
613   url = stringToURL("http://example.com/hello/%2e./%2e%2e/.%2e/%2e.bar");
614   Assert.equal(url.spec, "http://example.com/%2e.bar");
615   Assert.equal(url.directory, "/");
616   Assert.equal(url.fileName, "%2e.bar");
617   Assert.equal(url.fileBaseName, "%2e");
618   Assert.equal(url.fileExtension, "bar");
620   url = stringToURL("http://example.com/%2eX/X%2e/%2eX");
621   Assert.equal(url.spec, "http://example.com/%2eX/X%2e/%2eX");
622   Assert.equal(url.directory, "/%2eX/X%2e/");
623   Assert.equal(url.fileName, "%2eX");
624   Assert.equal(url.fileBaseName, "%2eX");
625   Assert.equal(url.fileExtension, "");
627   run_next_test();
630 add_test(function test_filterWhitespace() {
631   let url = stringToURL(
632     " \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 "
633   );
634   Assert.equal(
635     url.spec,
636     "http://example.com/path/to%20the/file.ext?query#hash"
637   );
639   // These setters should filter \r\n\t.
640   url = stringToURL("http://test.com/path?query#hash");
641   url = url.mutate().setFilePath("pa\r\n\tth").finalize();
642   Assert.equal(url.spec, "http://test.com/path?query#hash");
643   url = url.mutate().setQuery("que\r\n\try").finalize();
644   Assert.equal(url.spec, "http://test.com/path?query#hash");
645   url = url.mutate().setRef("ha\r\n\tsh").finalize();
646   Assert.equal(url.spec, "http://test.com/path?query#hash");
647   url = url
648     .mutate()
649     .QueryInterface(Ci.nsIURLMutator)
650     .setFileName("fi\r\n\tle.name")
651     .finalize();
652   Assert.equal(url.spec, "http://test.com/fi%0D%0A%09le.name?query#hash");
654   run_next_test();
657 add_test(function test_backslashReplacement() {
658   var url = stringToURL(
659     "http:\\\\test.com\\path/to\\file?query\\backslash#hash\\"
660   );
661   Assert.equal(
662     url.spec,
663     "http://test.com/path/to/file?query\\backslash#hash\\"
664   );
666   url = stringToURL("http:\\\\test.com\\example.org/path\\to/file");
667   Assert.equal(url.spec, "http://test.com/example.org/path/to/file");
668   Assert.equal(url.host, "test.com");
669   Assert.equal(url.pathQueryRef, "/example.org/path/to/file");
671   run_next_test();
674 add_test(function test_authority_host() {
675   Assert.throws(
676     () => {
677       stringToURL("http:");
678     },
679     /NS_ERROR_MALFORMED_URI/,
680     "TYPE_AUTHORITY should have host"
681   );
682   Assert.throws(
683     () => {
684       stringToURL("http:///");
685     },
686     /NS_ERROR_MALFORMED_URI/,
687     "TYPE_AUTHORITY should have host"
688   );
690   run_next_test();
693 add_test(function test_trim_C0_and_space() {
694   var url = stringToURL(
695     "\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 "
696   );
697   Assert.equal(url.spec, "http://example.com/");
698   url = url
699     .mutate()
700     .setSpec(
701       "\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 "
702     )
703     .finalize();
704   Assert.equal(url.spec, "http://test.com/");
705   Assert.throws(
706     () => {
707       url = url
708         .mutate()
709         .setSpec(
710           "\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 "
711         )
712         .finalize();
713     },
714     /NS_ERROR_MALFORMED_URI/,
715     "set empty spec"
716   );
717   run_next_test();
720 // This tests that C0-and-space characters in the path, query and ref are
721 // percent encoded.
722 add_test(function test_encode_C0_and_space() {
723   function toHex(d) {
724     var hex = d.toString(16);
725     if (hex.length == 1) {
726       hex = "0" + hex;
727     }
728     return hex.toUpperCase();
729   }
731   for (var i = 0x0; i <= 0x20; i++) {
732     // These characters get filtered - they are not encoded.
733     if (
734       String.fromCharCode(i) == "\r" ||
735       String.fromCharCode(i) == "\n" ||
736       String.fromCharCode(i) == "\t"
737     ) {
738       continue;
739     }
740     let url = stringToURL(
741       "http://example.com/pa" +
742         String.fromCharCode(i) +
743         "th?qu" +
744         String.fromCharCode(i) +
745         "ery#ha" +
746         String.fromCharCode(i) +
747         "sh"
748     );
749     Assert.equal(
750       url.spec,
751       "http://example.com/pa%" +
752         toHex(i) +
753         "th?qu%" +
754         toHex(i) +
755         "ery#ha%" +
756         toHex(i) +
757         "sh"
758     );
759   }
761   // Additionally, we need to check the setters.
762   let url = stringToURL("http://example.com/path?query#hash");
763   url = url.mutate().setFilePath("pa\0th").finalize();
764   Assert.equal(url.spec, "http://example.com/pa%00th?query#hash");
765   url = url.mutate().setQuery("qu\0ery").finalize();
766   Assert.equal(url.spec, "http://example.com/pa%00th?qu%00ery#hash");
767   url = url.mutate().setRef("ha\0sh").finalize();
768   Assert.equal(url.spec, "http://example.com/pa%00th?qu%00ery#ha%00sh");
769   url = url
770     .mutate()
771     .QueryInterface(Ci.nsIURLMutator)
772     .setFileName("fi\0le.name")
773     .finalize();
774   Assert.equal(url.spec, "http://example.com/fi%00le.name?qu%00ery#ha%00sh");
776   run_next_test();
779 add_test(function test_ipv4Normalize() {
780   var localIPv4s = [
781     "http://127.0.0.1",
782     "http://127.0.1",
783     "http://127.1",
784     "http://2130706433",
785     "http://0177.00.00.01",
786     "http://0177.00.01",
787     "http://0177.01",
788     "http://00000000000000000000000000177.0000000.0000000.0001",
789     "http://000000177.0000001",
790     "http://017700000001",
791     "http://0x7f.0x00.0x00.0x01",
792     "http://0x7f.0x01",
793     "http://0x7f000001",
794     "http://0x007f.0x0000.0x0000.0x0001",
795     "http://000177.0.00000.0x0001",
796     "http://127.0.0.1.",
797   ].map(stringToURL);
799   let url;
800   for (url of localIPv4s) {
801     Assert.equal(url.spec, "http://127.0.0.1/");
802   }
804   // These should treated as a domain instead of an IPv4.
805   var nonIPv4s = [
806     "http://2+3/",
807     "http://0.0.0.-1/",
808     "http://1.2.3.4../",
809     "resource://123/",
810     "resource://4294967296/",
811   ];
812   var spec;
813   for (spec of nonIPv4s) {
814     url = stringToURL(spec);
815     Assert.equal(url.spec, spec);
816   }
818   url = stringToURL("resource://path/to/resource/");
819   url = url.mutate().setHost("123").finalize();
820   Assert.equal(url.host, "123");
822   run_next_test();
825 add_test(function test_invalidHostChars() {
826   var url = stringToURL("http://example.org/");
827   for (let i = 0; i <= 0x20; i++) {
828     // These characters get filtered.
829     if (
830       String.fromCharCode(i) == "\r" ||
831       String.fromCharCode(i) == "\n" ||
832       String.fromCharCode(i) == "\t"
833     ) {
834       continue;
835     }
836     Assert.throws(
837       () => {
838         url = url
839           .mutate()
840           .setHost("a" + String.fromCharCode(i) + "b")
841           .finalize();
842       },
843       /NS_ERROR_MALFORMED_URI/,
844       "Trying to set hostname containing char code: " + i
845     );
846   }
847   for (let c of '@[]*<>|:"') {
848     Assert.throws(
849       () => {
850         url = url
851           .mutate()
852           .setHost("a" + c)
853           .finalize();
854       },
855       /NS_ERROR_MALFORMED_URI/,
856       "Trying to set hostname containing char: " + c
857     );
858   }
860   // It also can't contain /, \, #, ?, but we treat these characters as
861   // hostname separators, so there is no way to set them and fail.
862   run_next_test();
865 add_test(function test_normalize_ipv6() {
866   var url = stringToURL("http://example.com");
867   url = url.mutate().setHost("[::192.9.5.5]").finalize();
868   Assert.equal(url.spec, "http://[::c009:505]/");
870   run_next_test();
873 add_test(function test_emptyPassword() {
874   var url = stringToURL("http://a:@example.com");
875   Assert.equal(url.spec, "http://a@example.com/");
876   url = url.mutate().setPassword("pp").finalize();
877   Assert.equal(url.spec, "http://a:pp@example.com/");
878   url = url.mutate().setPassword("").finalize();
879   Assert.equal(url.spec, "http://a@example.com/");
880   url = url.mutate().setUserPass("xxx:").finalize();
881   Assert.equal(url.spec, "http://xxx@example.com/");
882   url = url.mutate().setPassword("zzzz").finalize();
883   Assert.equal(url.spec, "http://xxx:zzzz@example.com/");
884   url = url.mutate().setUserPass("xxxxx:yyyyyy").finalize();
885   Assert.equal(url.spec, "http://xxxxx:yyyyyy@example.com/");
886   url = url.mutate().setUserPass("z:").finalize();
887   Assert.equal(url.spec, "http://z@example.com/");
888   url = url.mutate().setPassword("ppppppppppp").finalize();
889   Assert.equal(url.spec, "http://z:ppppppppppp@example.com/");
891   url = stringToURL("http://example.com");
892   url = url.mutate().setPassword("").finalize(); // Still empty. Should work.
893   Assert.equal(url.spec, "http://example.com/");
895   run_next_test();
898 add_test(function test_emptyUser() {
899   let url = stringToURL("http://:a@example.com/path/to/something?query#hash");
900   Assert.equal(url.spec, "http://:a@example.com/path/to/something?query#hash");
901   url = stringToURL("http://:@example.com/path/to/something?query#hash");
902   Assert.equal(url.spec, "http://example.com/path/to/something?query#hash");
904   const kurl = stringToURL(
905     "http://user:pass@example.com:8888/path/to/something?query#hash"
906   );
907   url = kurl.mutate().setUsername("").finalize();
908   Assert.equal(
909     url.spec,
910     "http://:pass@example.com:8888/path/to/something?query#hash"
911   );
912   Assert.equal(url.host, "example.com");
913   Assert.equal(url.hostPort, "example.com:8888");
914   Assert.equal(url.filePath, "/path/to/something");
915   Assert.equal(url.query, "query");
916   Assert.equal(url.ref, "hash");
917   url = kurl.mutate().setUserPass(":pass1").finalize();
918   Assert.equal(
919     url.spec,
920     "http://:pass1@example.com:8888/path/to/something?query#hash"
921   );
922   Assert.equal(url.host, "example.com");
923   Assert.equal(url.hostPort, "example.com:8888");
924   Assert.equal(url.filePath, "/path/to/something");
925   Assert.equal(url.query, "query");
926   Assert.equal(url.ref, "hash");
927   url = url.mutate().setUsername("user2").finalize();
928   Assert.equal(
929     url.spec,
930     "http://user2:pass1@example.com:8888/path/to/something?query#hash"
931   );
932   Assert.equal(url.host, "example.com");
933   url = url.mutate().setUserPass(":pass234").finalize();
934   Assert.equal(
935     url.spec,
936     "http://:pass234@example.com:8888/path/to/something?query#hash"
937   );
938   Assert.equal(url.host, "example.com");
939   url = url.mutate().setUserPass("").finalize();
940   Assert.equal(
941     url.spec,
942     "http://example.com:8888/path/to/something?query#hash"
943   );
944   Assert.equal(url.host, "example.com");
945   url = url.mutate().setPassword("pa").finalize();
946   Assert.equal(
947     url.spec,
948     "http://:pa@example.com:8888/path/to/something?query#hash"
949   );
950   Assert.equal(url.host, "example.com");
951   url = url.mutate().setUserPass("user:pass").finalize();
952   symmetricEquality(true, url.QueryInterface(Ci.nsIURL), kurl);
954   url = stringToURL("http://example.com:8888/path/to/something?query#hash");
955   url = url.mutate().setPassword("pass").finalize();
956   Assert.equal(
957     url.spec,
958     "http://:pass@example.com:8888/path/to/something?query#hash"
959   );
960   url = url.mutate().setUsername("").finalize();
961   Assert.equal(
962     url.spec,
963     "http://:pass@example.com:8888/path/to/something?query#hash"
964   );
966   url = stringToURL("http://example.com:8888");
967   url = url.mutate().setUsername("user").finalize();
968   url = url.mutate().setUsername("").finalize();
969   Assert.equal(url.spec, "http://example.com:8888/");
971   url = stringToURL("http://:pass@example.com");
972   Assert.equal(url.spec, "http://:pass@example.com/");
973   url = url.mutate().setPassword("").finalize();
974   Assert.equal(url.spec, "http://example.com/");
975   url = url.mutate().setUserPass("user:pass").finalize();
976   Assert.equal(url.spec, "http://user:pass@example.com/");
977   Assert.equal(url.host, "example.com");
978   url = url.mutate().setUserPass("u:p").finalize();
979   Assert.equal(url.spec, "http://u:p@example.com/");
980   Assert.equal(url.host, "example.com");
981   url = url.mutate().setUserPass("u1:p23").finalize();
982   Assert.equal(url.spec, "http://u1:p23@example.com/");
983   Assert.equal(url.host, "example.com");
984   url = url.mutate().setUsername("u").finalize();
985   Assert.equal(url.spec, "http://u:p23@example.com/");
986   Assert.equal(url.host, "example.com");
987   url = url.mutate().setPassword("p").finalize();
988   Assert.equal(url.spec, "http://u:p@example.com/");
989   Assert.equal(url.host, "example.com");
991   url = url.mutate().setUserPass("u2:p2").finalize();
992   Assert.equal(url.spec, "http://u2:p2@example.com/");
993   Assert.equal(url.host, "example.com");
994   url = url.mutate().setUserPass("u23:p23").finalize();
995   Assert.equal(url.spec, "http://u23:p23@example.com/");
996   Assert.equal(url.host, "example.com");
998   run_next_test();
1001 registerCleanupFunction(function () {
1002   gPrefs.clearUserPref("network.standard-url.punycode-host");
1005 add_test(function test_idna_host() {
1006   // See bug 945240 - this test makes sure that URLs return a punycode hostname
1007   let url = stringToURL(
1008     "http://user:password@ält.example.org:8080/path?query#etc"
1009   );
1010   equal(url.host, "xn--lt-uia.example.org");
1011   equal(url.hostPort, "xn--lt-uia.example.org:8080");
1012   equal(url.prePath, "http://user:password@xn--lt-uia.example.org:8080");
1013   equal(
1014     url.spec,
1015     "http://user:password@xn--lt-uia.example.org:8080/path?query#etc"
1016   );
1017   equal(
1018     url.specIgnoringRef,
1019     "http://user:password@xn--lt-uia.example.org:8080/path?query"
1020   );
1021   equal(
1022     url
1023       .QueryInterface(Ci.nsISensitiveInfoHiddenURI)
1024       .getSensitiveInfoHiddenSpec(),
1025     "http://user:****@xn--lt-uia.example.org:8080/path?query#etc"
1026   );
1028   equal(url.displayHost, "ält.example.org");
1029   equal(url.displayHostPort, "ält.example.org:8080");
1030   equal(
1031     url.displaySpec,
1032     "http://user:password@ält.example.org:8080/path?query#etc"
1033   );
1035   equal(url.asciiHost, "xn--lt-uia.example.org");
1036   equal(url.asciiHostPort, "xn--lt-uia.example.org:8080");
1037   equal(
1038     url.asciiSpec,
1039     "http://user:password@xn--lt-uia.example.org:8080/path?query#etc"
1040   );
1042   url = url.mutate().setRef("").finalize(); // SetRef calls InvalidateCache()
1043   equal(
1044     url.spec,
1045     "http://user:password@xn--lt-uia.example.org:8080/path?query"
1046   );
1047   equal(
1048     url.displaySpec,
1049     "http://user:password@ält.example.org:8080/path?query"
1050   );
1051   equal(
1052     url.asciiSpec,
1053     "http://user:password@xn--lt-uia.example.org:8080/path?query"
1054   );
1056   url = stringToURL("http://user:password@www.ält.com:8080/path?query#etc");
1057   url = url.mutate().setRef("").finalize();
1058   equal(url.spec, "http://user:password@www.xn--lt-uia.com:8080/path?query");
1060   run_next_test();
1063 add_test(
1064   { skip_if: () => AppConstants.MOZ_APP_NAME == "thunderbird" },
1065   function test_bug1517025() {
1066     Assert.throws(
1067       () => {
1068         stringToURL("https://b%9a/");
1069       },
1070       /NS_ERROR_MALFORMED_URI/,
1071       "bad URI"
1072     );
1074     Assert.throws(
1075       () => {
1076         stringToURL("https://b%9ª/");
1077       },
1078       /NS_ERROR_MALFORMED_URI/,
1079       "bad URI"
1080     );
1082     let base = stringToURL(
1083       "https://bug1517025.bmoattachments.org/attachment.cgi?id=9033787"
1084     );
1085     Assert.throws(
1086       () => {
1087         Services.io.newURI("/\\b%9ª", "windows-1252", base);
1088       },
1089       /NS_ERROR_MALFORMED_URI/,
1090       "bad URI"
1091     );
1093     run_next_test();
1094   }
1097 add_task(async function test_emptyHostWithURLType() {
1098   let makeURL = (str, type) => {
1099     return Cc["@mozilla.org/network/standard-url-mutator;1"]
1100       .createInstance(Ci.nsIStandardURLMutator)
1101       .init(type, 80, str, "UTF-8", null)
1102       .finalize()
1103       .QueryInterface(Ci.nsIURL);
1104   };
1106   let url = makeURL("http://foo.com/bar/", Ci.nsIStandardURL.URLTYPE_AUTHORITY);
1107   Assert.throws(
1108     () => url.mutate().setHost("").finalize().spec,
1109     /NS_ERROR_UNEXPECTED/,
1110     "Empty host is not allowed for URLTYPE_AUTHORITY"
1111   );
1113   url = makeURL("http://foo.com/bar/", Ci.nsIStandardURL.URLTYPE_STANDARD);
1114   Assert.throws(
1115     () => url.mutate().setHost("").finalize().spec,
1116     /NS_ERROR_UNEXPECTED/,
1117     "Empty host is not allowed for URLTYPE_STANDARD"
1118   );
1120   url = makeURL("http://foo.com/bar/", Ci.nsIStandardURL.URLTYPE_NO_AUTHORITY);
1121   equal(
1122     url.spec,
1123     "http:///bar/",
1124     "Host is removed when parsing URLTYPE_NO_AUTHORITY"
1125   );
1126   equal(
1127     url.mutate().setHost("").finalize().spec,
1128     "http:///bar/",
1129     "Setting an empty host does nothing for URLTYPE_NO_AUTHORITY"
1130   );
1131   Assert.throws(
1132     () => url.mutate().setHost("something").finalize().spec,
1133     /NS_ERROR_UNEXPECTED/,
1134     "Setting a non-empty host is not allowed for URLTYPE_NO_AUTHORITY"
1135   );
1136   equal(
1137     url.mutate().setHost("#j").finalize().spec,
1138     "http:///bar/",
1139     "Setting a pseudo-empty host does nothing for URLTYPE_NO_AUTHORITY"
1140   );
1142   url = makeURL(
1143     "http://example.org:123/foo?bar#baz",
1144     Ci.nsIStandardURL.URLTYPE_AUTHORITY
1145   );
1146   Assert.throws(
1147     () => url.mutate().setHost("#j").finalize().spec,
1148     /NS_ERROR_UNEXPECTED/,
1149     "A pseudo-empty host is not allowed for URLTYPE_AUTHORITY"
1150   );
1153 add_task(async function test_fuzz() {
1154   let makeURL = str => {
1155     return (
1156       Cc["@mozilla.org/network/standard-url-mutator;1"]
1157         .createInstance(Ci.nsIStandardURLMutator)
1158         .QueryInterface(Ci.nsIURIMutator)
1159         // .init(type, 80, str, "UTF-8", null)
1160         .setSpec(str)
1161         .finalize()
1162         .QueryInterface(Ci.nsIURL)
1163     );
1164   };
1166   Assert.throws(() => {
1167     let url = makeURL("/");
1168     url.mutate().setHost("(").finalize();
1169   }, /NS_ERROR_MALFORMED_URI/);
1172 add_task(async function test_bug1648493() {
1173   let url = stringToURL("https://example.com/");
1174   url = url.mutate().setScheme("file").finalize();
1175   url = url.mutate().setScheme("resource").finalize();
1176   url = url.mutate().setPassword("ê").finalize();
1177   url = url.mutate().setUsername("ç").finalize();
1178   url = url.mutate().setScheme("t").finalize();
1179   equal(url.spec, "t://%C3%83%C2%A7:%C3%83%C2%AA@example.com/");
1180   equal(url.username, "%C3%83%C2%A7");
1183 add_task(async function test_bug1873976() {
1184   let url = Services.io.newURI("file:.");
1185   equal(url.spec, "file:///");
1188 add_task(async function test_bug1890346() {
1189   let url = Services.io.newURI("file:..?/..");
1190   equal(url.spec, "file:///?/..");
1193 add_task(async function test_bug1914141() {
1194   equal(Services.io.isValidHostname("example.com"), true);
1195   equal(Services.io.isValidHostname("example.0"), false);
1197   equal(Services.io.isValidHostname("192.168.0.1"), true);
1198   equal(Services.io.isValidHostname("192.168.0"), true);
1199   equal(Services.io.isValidHostname("1.192.168.0.1"), false);
1200   equal(Services.io.isValidHostname("invalid.192.168.0.1"), false);
1202   equal(Services.io.isValidHostname("::1"), true);
1203   equal(Services.io.isValidHostname("abcd::zz::00"), false);
1204   equal(Services.io.isValidHostname("zzzz::1.2.3.4"), false);
1206   equal(Services.io.isValidHostname("::1.2.3.4"), true);