tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_standardurl.js (38041B)


      1 "use strict";
      2 
      3 const { AppConstants } = ChromeUtils.importESModule(
      4  "resource://gre/modules/AppConstants.sys.mjs"
      5 );
      6 
      7 const gPrefs = Services.prefs;
      8 
      9 function symmetricEquality(expect, a, b) {
     10  /* Use if/else instead of |do_check_eq(expect, a.spec == b.spec)| so
     11     that we get the specs output on the console if the check fails.
     12   */
     13  if (expect) {
     14    /* Check all the sub-pieces too, since that can help with
     15       debugging cases when equals() returns something unexpected */
     16    /* We don't check port in the loop, because it can be defaulted in
     17       some cases. */
     18    [
     19      "spec",
     20      "prePath",
     21      "scheme",
     22      "userPass",
     23      "username",
     24      "password",
     25      "hostPort",
     26      "host",
     27      "pathQueryRef",
     28      "filePath",
     29      "query",
     30      "ref",
     31      "directory",
     32      "fileName",
     33      "fileBaseName",
     34      "fileExtension",
     35    ].map(function (prop) {
     36      dump("Testing '" + prop + "'\n");
     37      Assert.equal(a[prop], b[prop]);
     38    });
     39  } else {
     40    Assert.notEqual(a.spec, b.spec);
     41  }
     42  Assert.equal(expect, a.equals(b));
     43  Assert.equal(expect, b.equals(a));
     44 }
     45 
     46 function stringToURL(str) {
     47  return Cc["@mozilla.org/network/standard-url-mutator;1"]
     48    .createInstance(Ci.nsIStandardURLMutator)
     49    .init(Ci.nsIStandardURL.URLTYPE_AUTHORITY, 80, str, "UTF-8", null)
     50    .finalize()
     51    .QueryInterface(Ci.nsIURL);
     52 }
     53 
     54 function pairToURLs(pair) {
     55  Assert.equal(pair.length, 2);
     56  return pair.map(stringToURL);
     57 }
     58 
     59 add_test(function test_setEmptyPath() {
     60  var pairs = [
     61    ["http://example.com", "http://example.com/tests/dom/tests"],
     62    ["http://example.com:80", "http://example.com/tests/dom/tests"],
     63    ["http://example.com:80/", "http://example.com/tests/dom/test"],
     64    ["http://example.com/", "http://example.com/tests/dom/tests"],
     65    ["http://example.com/a", "http://example.com/tests/dom/tests"],
     66    ["http://example.com:80/a", "http://example.com/tests/dom/tests"],
     67  ].map(pairToURLs);
     68 
     69  for (var [provided, target] of pairs) {
     70    symmetricEquality(false, target, provided);
     71 
     72    provided = provided.mutate().setPathQueryRef("").finalize();
     73    target = target.mutate().setPathQueryRef("").finalize();
     74 
     75    Assert.equal(provided.spec, target.spec);
     76    symmetricEquality(true, target, provided);
     77  }
     78  run_next_test();
     79 });
     80 
     81 add_test(function test_setQuery() {
     82  var pairs = [
     83    ["http://example.com", "http://example.com/?foo"],
     84    ["http://example.com/bar", "http://example.com/bar?foo"],
     85    ["http://example.com#bar", "http://example.com/?foo#bar"],
     86    ["http://example.com/#bar", "http://example.com/?foo#bar"],
     87    ["http://example.com/?longerthanfoo#bar", "http://example.com/?foo#bar"],
     88    ["http://example.com/?longerthanfoo", "http://example.com/?foo"],
     89    /* And one that's nonempty but shorter than "foo" */
     90    ["http://example.com/?f#bar", "http://example.com/?foo#bar"],
     91    ["http://example.com/?f", "http://example.com/?foo"],
     92  ].map(pairToURLs);
     93 
     94  for (var [provided, target] of pairs) {
     95    symmetricEquality(false, provided, target);
     96 
     97    provided = provided
     98      .mutate()
     99      .setQuery("foo")
    100      .finalize()
    101      .QueryInterface(Ci.nsIURL);
    102 
    103    Assert.equal(provided.spec, target.spec);
    104    symmetricEquality(true, provided, target);
    105  }
    106 
    107  [provided, target] = [
    108    "http://example.com/#",
    109    "http://example.com/?foo#bar",
    110  ].map(stringToURL);
    111  symmetricEquality(false, provided, target);
    112  provided = provided
    113    .mutate()
    114    .setQuery("foo")
    115    .finalize()
    116    .QueryInterface(Ci.nsIURL);
    117  symmetricEquality(false, provided, target);
    118 
    119  var newProvided = Services.io
    120    .newURI("#bar", null, provided)
    121    .QueryInterface(Ci.nsIURL);
    122 
    123  Assert.equal(newProvided.spec, target.spec);
    124  symmetricEquality(true, newProvided, target);
    125  run_next_test();
    126 });
    127 
    128 add_test(function test_setRef() {
    129  var tests = [
    130    ["http://example.com", "", "http://example.com/"],
    131    ["http://example.com:80", "", "http://example.com:80/"],
    132    ["http://example.com:80/", "", "http://example.com:80/"],
    133    ["http://example.com/", "", "http://example.com/"],
    134    ["http://example.com/a", "", "http://example.com/a"],
    135    ["http://example.com:80/a", "", "http://example.com:80/a"],
    136 
    137    ["http://example.com", "x", "http://example.com/#x"],
    138    ["http://example.com:80", "x", "http://example.com:80/#x"],
    139    ["http://example.com:80/", "x", "http://example.com:80/#x"],
    140    ["http://example.com/", "x", "http://example.com/#x"],
    141    ["http://example.com/a", "x", "http://example.com/a#x"],
    142    ["http://example.com:80/a", "x", "http://example.com:80/a#x"],
    143 
    144    ["http://example.com", "xx", "http://example.com/#xx"],
    145    ["http://example.com:80", "xx", "http://example.com:80/#xx"],
    146    ["http://example.com:80/", "xx", "http://example.com:80/#xx"],
    147    ["http://example.com/", "xx", "http://example.com/#xx"],
    148    ["http://example.com/a", "xx", "http://example.com/a#xx"],
    149    ["http://example.com:80/a", "xx", "http://example.com:80/a#xx"],
    150 
    151    [
    152      "http://example.com",
    153      "xxxxxxxxxxxxxx",
    154      "http://example.com/#xxxxxxxxxxxxxx",
    155    ],
    156    [
    157      "http://example.com:80",
    158      "xxxxxxxxxxxxxx",
    159      "http://example.com:80/#xxxxxxxxxxxxxx",
    160    ],
    161    [
    162      "http://example.com:80/",
    163      "xxxxxxxxxxxxxx",
    164      "http://example.com:80/#xxxxxxxxxxxxxx",
    165    ],
    166    [
    167      "http://example.com/",
    168      "xxxxxxxxxxxxxx",
    169      "http://example.com/#xxxxxxxxxxxxxx",
    170    ],
    171    [
    172      "http://example.com/a",
    173      "xxxxxxxxxxxxxx",
    174      "http://example.com/a#xxxxxxxxxxxxxx",
    175    ],
    176    [
    177      "http://example.com:80/a",
    178      "xxxxxxxxxxxxxx",
    179      "http://example.com:80/a#xxxxxxxxxxxxxx",
    180    ],
    181  ];
    182 
    183  for (var [before, ref, result] of tests) {
    184    /* Test1: starting with empty ref */
    185    var a = stringToURL(before);
    186    a = a.mutate().setRef(ref).finalize().QueryInterface(Ci.nsIURL);
    187    var b = stringToURL(result);
    188 
    189    Assert.equal(a.spec, b.spec);
    190    Assert.equal(ref, b.ref);
    191    symmetricEquality(true, a, b);
    192 
    193    /* Test2: starting with non-empty */
    194    a = a.mutate().setRef("yyyy").finalize().QueryInterface(Ci.nsIURL);
    195    var c = stringToURL(before);
    196    c = c.mutate().setRef("yyyy").finalize().QueryInterface(Ci.nsIURL);
    197    symmetricEquality(true, a, c);
    198 
    199    /* Test3: reset the ref */
    200    a = a.mutate().setRef("").finalize().QueryInterface(Ci.nsIURL);
    201    symmetricEquality(true, a, stringToURL(before));
    202 
    203    /* Test4: verify again after reset */
    204    a = a.mutate().setRef(ref).finalize().QueryInterface(Ci.nsIURL);
    205    symmetricEquality(true, a, b);
    206  }
    207  run_next_test();
    208 });
    209 
    210 // Bug 960014 - Make nsStandardURL::SetHost less magical around IPv6
    211 add_test(function test_ipv6() {
    212  var url = stringToURL("http://example.com");
    213  url = url.mutate().setHost("[2001::1]").finalize();
    214  Assert.equal(url.host, "2001::1");
    215 
    216  url = stringToURL("http://example.com");
    217  url = url.mutate().setHostPort("[2001::1]:30").finalize();
    218  Assert.equal(url.host, "2001::1");
    219  Assert.equal(url.port, 30);
    220  Assert.equal(url.hostPort, "[2001::1]:30");
    221 
    222  url = stringToURL("http://example.com");
    223  url = url.mutate().setHostPort("2001:1").finalize();
    224  Assert.equal(url.host, "0.0.7.209");
    225  Assert.equal(url.port, 1);
    226  Assert.equal(url.hostPort, "0.0.7.209:1");
    227  run_next_test();
    228 });
    229 
    230 add_test(function test_ipv6_fail() {
    231  var url = stringToURL("http://example.com");
    232 
    233  Assert.throws(
    234    () => {
    235      url = url.mutate().setHost("2001::1").finalize();
    236    },
    237    /NS_ERROR_MALFORMED_URI/,
    238    "missing brackets"
    239  );
    240  Assert.throws(
    241    () => {
    242      url = url.mutate().setHost("[2001::1]:20").finalize();
    243    },
    244    /NS_ERROR_MALFORMED_URI/,
    245    "url.host with port"
    246  );
    247  Assert.throws(
    248    () => {
    249      url = url.mutate().setHost("[2001::1").finalize();
    250    },
    251    /NS_ERROR_MALFORMED_URI/,
    252    "missing last bracket"
    253  );
    254  Assert.throws(
    255    () => {
    256      url = url.mutate().setHost("2001::1]").finalize();
    257    },
    258    /NS_ERROR_MALFORMED_URI/,
    259    "missing first bracket"
    260  );
    261  Assert.throws(
    262    () => {
    263      url = url.mutate().setHost("2001[::1]").finalize();
    264    },
    265    /NS_ERROR_MALFORMED_URI/,
    266    "bad bracket position"
    267  );
    268  Assert.throws(
    269    () => {
    270      url = url.mutate().setHost("[]").finalize();
    271    },
    272    /NS_ERROR_MALFORMED_URI/,
    273    "empty IPv6 address"
    274  );
    275  Assert.throws(
    276    () => {
    277      url = url.mutate().setHost("[hello]").finalize();
    278    },
    279    /NS_ERROR_MALFORMED_URI/,
    280    "bad IPv6 address"
    281  );
    282  Assert.throws(
    283    () => {
    284      url = url.mutate().setHost("[192.168.1.1]").finalize();
    285    },
    286    /NS_ERROR_MALFORMED_URI/,
    287    "bad IPv6 address"
    288  );
    289  Assert.throws(
    290    () => {
    291      url = url.mutate().setHostPort("2001::1").finalize();
    292    },
    293    /NS_ERROR_MALFORMED_URI/,
    294    "missing brackets"
    295  );
    296  Assert.throws(
    297    () => {
    298      url = url.mutate().setHostPort("[2001::1]30").finalize();
    299    },
    300    /NS_ERROR_MALFORMED_URI/,
    301    "missing : after IP"
    302  );
    303  Assert.throws(
    304    () => {
    305      url = url.mutate().setHostPort("[2001:1]").finalize();
    306    },
    307    /NS_ERROR_MALFORMED_URI/,
    308    "bad IPv6 address"
    309  );
    310  Assert.throws(
    311    () => {
    312      url = url.mutate().setHostPort("[2001:1]10").finalize();
    313    },
    314    /NS_ERROR_MALFORMED_URI/,
    315    "bad IPv6 address"
    316  );
    317  Assert.throws(
    318    () => {
    319      url = url.mutate().setHostPort("[2001:1]10:20").finalize();
    320    },
    321    /NS_ERROR_MALFORMED_URI/,
    322    "bad IPv6 address"
    323  );
    324  Assert.throws(
    325    () => {
    326      url = url.mutate().setHostPort("[2001:1]:10:20").finalize();
    327    },
    328    /NS_ERROR_MALFORMED_URI/,
    329    "bad IPv6 address"
    330  );
    331  Assert.throws(
    332    () => {
    333      url = url.mutate().setHostPort("[2001:1").finalize();
    334    },
    335    /NS_ERROR_MALFORMED_URI/,
    336    "bad IPv6 address"
    337  );
    338  Assert.throws(
    339    () => {
    340      url = url.mutate().setHostPort("2001]:1").finalize();
    341    },
    342    /NS_ERROR_MALFORMED_URI/,
    343    "bad IPv6 address"
    344  );
    345  Assert.throws(
    346    () => {
    347      url = url.mutate().setHostPort("2001:1]").finalize();
    348    },
    349    /NS_ERROR_MALFORMED_URI/,
    350    "bad IPv6 address"
    351  );
    352  Assert.throws(
    353    () => {
    354      url = url.mutate().setHostPort("").finalize();
    355    },
    356    /NS_ERROR_UNEXPECTED/,
    357    "Empty hostPort should fail"
    358  );
    359 
    360  // These checks used to fail, but now don't (see bug 1433958 comment 57)
    361  url = url.mutate().setHostPort("[2001::1]:").finalize();
    362  Assert.equal(url.spec, "http://[2001::1]/");
    363  url = url.mutate().setHostPort("[2002::1]:bad").finalize();
    364  Assert.equal(url.spec, "http://[2002::1]/");
    365 
    366  run_next_test();
    367 });
    368 
    369 add_test(function test_clearedSpec() {
    370  var url = stringToURL("http://example.com/path");
    371  Assert.throws(
    372    () => {
    373      url = url.mutate().setSpec("http: example").finalize();
    374    },
    375    /NS_ERROR_MALFORMED_URI/,
    376    "set bad spec"
    377  );
    378  Assert.throws(
    379    () => {
    380      url = url.mutate().setSpec("").finalize();
    381    },
    382    /NS_ERROR_MALFORMED_URI/,
    383    "set empty spec"
    384  );
    385  Assert.equal(url.spec, "http://example.com/path");
    386  url = url
    387    .mutate()
    388    .setHost("allizom.org")
    389    .finalize()
    390    .QueryInterface(Ci.nsIURL);
    391 
    392  var ref = stringToURL("http://allizom.org/path");
    393  symmetricEquality(true, url, ref);
    394  run_next_test();
    395 });
    396 
    397 add_test(function test_escapeBrackets() {
    398  // Query
    399  var url = stringToURL("http://example.com/?a[x]=1");
    400  Assert.equal(url.spec, "http://example.com/?a[x]=1");
    401 
    402  url = stringToURL("http://example.com/?a%5Bx%5D=1");
    403  Assert.equal(url.spec, "http://example.com/?a%5Bx%5D=1");
    404 
    405  url = stringToURL("http://[2001::1]/?a[x]=1");
    406  Assert.equal(url.spec, "http://[2001::1]/?a[x]=1");
    407 
    408  url = stringToURL("http://[2001::1]/?a%5Bx%5D=1");
    409  Assert.equal(url.spec, "http://[2001::1]/?a%5Bx%5D=1");
    410 
    411  // Path
    412  url = stringToURL("http://example.com/brackets[x]/test");
    413  Assert.equal(url.spec, "http://example.com/brackets[x]/test");
    414 
    415  url = stringToURL("http://example.com/a%5Bx%5D/test");
    416  Assert.equal(url.spec, "http://example.com/a%5Bx%5D/test");
    417  run_next_test();
    418 });
    419 
    420 add_test(function test_escapeQuote() {
    421  var url = stringToURL("http://example.com/#'");
    422  Assert.equal(url.spec, "http://example.com/#'");
    423  Assert.equal(url.ref, "'");
    424  url = url.mutate().setRef("test'test").finalize();
    425  Assert.equal(url.spec, "http://example.com/#test'test");
    426  Assert.equal(url.ref, "test'test");
    427  run_next_test();
    428 });
    429 
    430 add_test(function test_apostropheEncoding() {
    431  // For now, single quote is escaped everywhere _except_ the path.
    432  // This policy is controlled by the bitmask in nsEscape.cpp::EscapeChars[]
    433  var url = stringToURL("http://example.com/dir'/file'.ext'");
    434  Assert.equal(url.spec, "http://example.com/dir'/file'.ext'");
    435  run_next_test();
    436 });
    437 
    438 add_test(function test_accentEncoding() {
    439  var url = stringToURL("http://example.com/?hello=`");
    440  Assert.equal(url.spec, "http://example.com/?hello=`");
    441  Assert.equal(url.query, "hello=`");
    442 
    443  url = stringToURL("http://example.com/?hello=%2C");
    444  Assert.equal(url.spec, "http://example.com/?hello=%2C");
    445  Assert.equal(url.query, "hello=%2C");
    446  run_next_test();
    447 });
    448 
    449 add_test(
    450  { skip_if: () => AppConstants.MOZ_APP_NAME == "thunderbird" },
    451  function test_percentDecoding() {
    452    var url = stringToURL("http://%70%61%73%74%65%62%69%6E.com");
    453    Assert.equal(url.spec, "http://pastebin.com/");
    454 
    455    // Disallowed hostname characters are rejected even when percent encoded
    456    Assert.throws(
    457      () => {
    458        url = stringToURL("http://example.com%0a%23.google.com/");
    459      },
    460      /NS_ERROR_MALFORMED_URI/,
    461      "invalid characters are not allowed"
    462    );
    463    run_next_test();
    464  }
    465 );
    466 
    467 add_test(function test_hugeStringThrows() {
    468  let prefs = Services.prefs;
    469  let maxLen = prefs.getIntPref("network.standard-url.max-length");
    470  let url = stringToURL("http://test:test@example.com");
    471 
    472  let hugeString = new Array(maxLen + 1).fill("a").join("");
    473  let setters = [
    474    { method: "setSpec", qi: Ci.nsIURIMutator },
    475    { method: "setUsername", qi: Ci.nsIURIMutator },
    476    { method: "setPassword", qi: Ci.nsIURIMutator },
    477    { method: "setFilePath", qi: Ci.nsIURIMutator },
    478    { method: "setHostPort", qi: Ci.nsIURIMutator },
    479    { method: "setHost", qi: Ci.nsIURIMutator },
    480    { method: "setUserPass", qi: Ci.nsIURIMutator },
    481    { method: "setPathQueryRef", qi: Ci.nsIURIMutator },
    482    { method: "setQuery", qi: Ci.nsIURIMutator },
    483    { method: "setRef", qi: Ci.nsIURIMutator },
    484    { method: "setScheme", qi: Ci.nsIURIMutator },
    485    { method: "setFileName", qi: Ci.nsIURLMutator },
    486    { method: "setFileExtension", qi: Ci.nsIURLMutator },
    487    { method: "setFileBaseName", qi: Ci.nsIURLMutator },
    488  ];
    489 
    490  for (let prop of setters) {
    491    Assert.throws(
    492      () =>
    493        (url = url
    494          .mutate()
    495          .QueryInterface(prop.qi)
    496          [prop.method](hugeString)
    497          .finalize()),
    498      /NS_ERROR_MALFORMED_URI/,
    499      `Passing a huge string to "${prop.method}" should throw`
    500    );
    501  }
    502 
    503  run_next_test();
    504 });
    505 
    506 add_test(function test_verticalBar() {
    507  var url = Services.io.newURI("file:///w|m");
    508  Assert.equal(url.spec, "file:///w|m");
    509 
    510  url = Services.io.newURI("file:///w||m");
    511  Assert.equal(url.spec, "file:///w||m");
    512 
    513  url = Services.io.newURI("file:///w|/m");
    514  Assert.equal(url.spec, "file:///w:/m");
    515 
    516  url = Services.io.newURI("file:C|/m/");
    517  Assert.equal(url.spec, "file:///C:/m/");
    518 
    519  url = Services.io.newURI("file:C||/m/");
    520  Assert.equal(url.spec, "file:///C||/m/");
    521 
    522  run_next_test();
    523 });
    524 
    525 add_test(function test_pathPercentEncodedDot() {
    526  var url = stringToURL("http://example.com/hello/%2e%2E/%2e");
    527  Assert.equal(url.spec, "http://example.com/");
    528  Assert.equal(url.directory, "/");
    529  Assert.equal(url.fileName, "");
    530  Assert.equal(url.fileBaseName, "");
    531  Assert.equal(url.fileExtension, "");
    532 
    533  url = stringToURL("http://example.com/hello/%2e%2E/%");
    534  Assert.equal(url.spec, "http://example.com/%");
    535  Assert.equal(url.directory, "/");
    536  Assert.equal(url.fileName, "%");
    537  Assert.equal(url.fileBaseName, "%");
    538  Assert.equal(url.fileExtension, "");
    539 
    540  url = stringToURL("http://example.com/hello/%2e%2E/%2");
    541  Assert.equal(url.spec, "http://example.com/%2");
    542  Assert.equal(url.directory, "/");
    543  Assert.equal(url.fileName, "%2");
    544  Assert.equal(url.fileBaseName, "%2");
    545  Assert.equal(url.fileExtension, "");
    546 
    547  url = stringToURL("http://example.com/hello/%2e%2E/%#");
    548  Assert.equal(url.spec, "http://example.com/%#");
    549  Assert.equal(url.directory, "/");
    550  Assert.equal(url.fileName, "%");
    551  Assert.equal(url.fileBaseName, "%");
    552  Assert.equal(url.fileExtension, "");
    553 
    554  url = stringToURL("http://example.com/hello/%2e%2E/%2?");
    555  Assert.equal(url.spec, "http://example.com/%2?");
    556  Assert.equal(url.directory, "/");
    557  Assert.equal(url.fileName, "%2");
    558  Assert.equal(url.fileBaseName, "%2");
    559  Assert.equal(url.fileExtension, "");
    560 
    561  url = stringToURL("http://example.com/hello/%2e/");
    562  Assert.equal(url.spec, "http://example.com/hello/");
    563  Assert.equal(url.directory, "/hello/");
    564  Assert.equal(url.fileName, "");
    565  Assert.equal(url.fileBaseName, "");
    566  Assert.equal(url.fileExtension, "");
    567 
    568  url = stringToURL("http://example.com/%2e");
    569  Assert.equal(url.spec, "http://example.com/");
    570  Assert.equal(url.directory, "/");
    571  Assert.equal(url.fileName, "");
    572  Assert.equal(url.fileBaseName, "");
    573  Assert.equal(url.fileExtension, "");
    574 
    575  url = stringToURL("http://example.com/.%2e");
    576  Assert.equal(url.spec, "http://example.com/");
    577  Assert.equal(url.directory, "/");
    578  Assert.equal(url.fileName, "");
    579  Assert.equal(url.fileBaseName, "");
    580  Assert.equal(url.fileExtension, "");
    581 
    582  url = stringToURL("http://example.com/%2e.");
    583  Assert.equal(url.spec, "http://example.com/");
    584  Assert.equal(url.directory, "/");
    585  Assert.equal(url.fileName, "");
    586  Assert.equal(url.fileBaseName, "");
    587  Assert.equal(url.fileExtension, "");
    588 
    589  url = stringToURL("http://example.com/%2e%2e");
    590  Assert.equal(url.spec, "http://example.com/");
    591  Assert.equal(url.directory, "/");
    592  Assert.equal(url.fileName, "");
    593  Assert.equal(url.fileBaseName, "");
    594  Assert.equal(url.fileExtension, "");
    595 
    596  url = stringToURL("http://example.com/%2e%2e%2e");
    597  Assert.equal(url.spec, "http://example.com/%2e%2e%2e");
    598  Assert.equal(url.directory, "/");
    599  Assert.equal(url.fileName, "%2e%2e%2e");
    600  Assert.equal(url.fileBaseName, "%2e%2e%2e");
    601  Assert.equal(url.fileExtension, "");
    602 
    603  url = stringToURL("http://example.com/%2e%2e%2e%2e");
    604  Assert.equal(url.spec, "http://example.com/%2e%2e%2e%2e");
    605  Assert.equal(url.directory, "/");
    606  Assert.equal(url.fileName, "%2e%2e%2e%2e");
    607  Assert.equal(url.fileBaseName, "%2e%2e%2e%2e");
    608  Assert.equal(url.fileExtension, "");
    609 
    610  url = stringToURL("http://example.com/hello/%2e%2");
    611  Assert.equal(url.spec, "http://example.com/hello/%2e%2");
    612  Assert.equal(url.directory, "/hello/");
    613  Assert.equal(url.fileName, "%2e%2");
    614  Assert.equal(url.fileBaseName, "%2e%2");
    615  Assert.equal(url.fileExtension, "");
    616 
    617  url = stringToURL("http://example.com/hello/%2e./%2e%2e/.%2e/%2e.bar");
    618  Assert.equal(url.spec, "http://example.com/%2e.bar");
    619  Assert.equal(url.directory, "/");
    620  Assert.equal(url.fileName, "%2e.bar");
    621  Assert.equal(url.fileBaseName, "%2e");
    622  Assert.equal(url.fileExtension, "bar");
    623 
    624  url = stringToURL("http://example.com/%2eX/X%2e/%2eX");
    625  Assert.equal(url.spec, "http://example.com/%2eX/X%2e/%2eX");
    626  Assert.equal(url.directory, "/%2eX/X%2e/");
    627  Assert.equal(url.fileName, "%2eX");
    628  Assert.equal(url.fileBaseName, "%2eX");
    629  Assert.equal(url.fileExtension, "");
    630 
    631  run_next_test();
    632 });
    633 
    634 add_test(function test_filterWhitespace() {
    635  let url = stringToURL(
    636    " \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 "
    637  );
    638  Assert.equal(
    639    url.spec,
    640    "http://example.com/path/to%20the/file.ext?query#hash"
    641  );
    642 
    643  // These setters should filter \r\n\t.
    644  url = stringToURL("http://test.com/path?query#hash");
    645  url = url.mutate().setFilePath("pa\r\n\tth").finalize();
    646  Assert.equal(url.spec, "http://test.com/path?query#hash");
    647  url = url.mutate().setQuery("que\r\n\try").finalize();
    648  Assert.equal(url.spec, "http://test.com/path?query#hash");
    649  url = url.mutate().setRef("ha\r\n\tsh").finalize();
    650  Assert.equal(url.spec, "http://test.com/path?query#hash");
    651  url = url
    652    .mutate()
    653    .QueryInterface(Ci.nsIURLMutator)
    654    .setFileName("fi\r\n\tle.name")
    655    .finalize();
    656  Assert.equal(url.spec, "http://test.com/fi%0D%0A%09le.name?query#hash");
    657 
    658  run_next_test();
    659 });
    660 
    661 add_test(function test_backslashReplacement() {
    662  var url = stringToURL(
    663    "http:\\\\test.com\\path/to\\file?query\\backslash#hash\\"
    664  );
    665  Assert.equal(
    666    url.spec,
    667    "http://test.com/path/to/file?query\\backslash#hash\\"
    668  );
    669 
    670  url = stringToURL("http:\\\\test.com\\example.org/path\\to/file");
    671  Assert.equal(url.spec, "http://test.com/example.org/path/to/file");
    672  Assert.equal(url.host, "test.com");
    673  Assert.equal(url.pathQueryRef, "/example.org/path/to/file");
    674 
    675  run_next_test();
    676 });
    677 
    678 add_test(function test_authority_host() {
    679  Assert.throws(
    680    () => {
    681      stringToURL("http:");
    682    },
    683    /NS_ERROR_MALFORMED_URI/,
    684    "TYPE_AUTHORITY should have host"
    685  );
    686  Assert.throws(
    687    () => {
    688      stringToURL("http:///");
    689    },
    690    /NS_ERROR_MALFORMED_URI/,
    691    "TYPE_AUTHORITY should have host"
    692  );
    693 
    694  run_next_test();
    695 });
    696 
    697 add_test(function test_trim_C0_and_space() {
    698  var url = stringToURL(
    699    "\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 "
    700  );
    701  Assert.equal(url.spec, "http://example.com/");
    702  url = url
    703    .mutate()
    704    .setSpec(
    705      "\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 "
    706    )
    707    .finalize();
    708  Assert.equal(url.spec, "http://test.com/");
    709  Assert.throws(
    710    () => {
    711      url = url
    712        .mutate()
    713        .setSpec(
    714          "\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 "
    715        )
    716        .finalize();
    717    },
    718    /NS_ERROR_MALFORMED_URI/,
    719    "set empty spec"
    720  );
    721  run_next_test();
    722 });
    723 
    724 // This tests that C0-and-space characters in the path, query and ref are
    725 // percent encoded.
    726 add_test(function test_encode_C0_and_space() {
    727  function toHex(d) {
    728    var hex = d.toString(16);
    729    if (hex.length == 1) {
    730      hex = "0" + hex;
    731    }
    732    return hex.toUpperCase();
    733  }
    734 
    735  for (var i = 0x0; i <= 0x20; i++) {
    736    // These characters get filtered - they are not encoded.
    737    if (
    738      String.fromCharCode(i) == "\r" ||
    739      String.fromCharCode(i) == "\n" ||
    740      String.fromCharCode(i) == "\t"
    741    ) {
    742      continue;
    743    }
    744    let url = stringToURL(
    745      "http://example.com/pa" +
    746        String.fromCharCode(i) +
    747        "th?qu" +
    748        String.fromCharCode(i) +
    749        "ery#ha" +
    750        String.fromCharCode(i) +
    751        "sh"
    752    );
    753    Assert.equal(
    754      url.spec,
    755      "http://example.com/pa%" +
    756        toHex(i) +
    757        "th?qu%" +
    758        toHex(i) +
    759        "ery#ha%" +
    760        toHex(i) +
    761        "sh"
    762    );
    763  }
    764 
    765  // Additionally, we need to check the setters.
    766  let url = stringToURL("http://example.com/path?query#hash");
    767  url = url.mutate().setFilePath("pa\0th").finalize();
    768  Assert.equal(url.spec, "http://example.com/pa%00th?query#hash");
    769  url = url.mutate().setQuery("qu\0ery").finalize();
    770  Assert.equal(url.spec, "http://example.com/pa%00th?qu%00ery#hash");
    771  url = url.mutate().setRef("ha\0sh").finalize();
    772  Assert.equal(url.spec, "http://example.com/pa%00th?qu%00ery#ha%00sh");
    773  url = url
    774    .mutate()
    775    .QueryInterface(Ci.nsIURLMutator)
    776    .setFileName("fi\0le.name")
    777    .finalize();
    778  Assert.equal(url.spec, "http://example.com/fi%00le.name?qu%00ery#ha%00sh");
    779 
    780  run_next_test();
    781 });
    782 
    783 add_test(function test_ipv4Normalize() {
    784  var localIPv4s = [
    785    "http://127.0.0.1",
    786    "http://127.0.1",
    787    "http://127.1",
    788    "http://2130706433",
    789    "http://0177.00.00.01",
    790    "http://0177.00.01",
    791    "http://0177.01",
    792    "http://00000000000000000000000000177.0000000.0000000.0001",
    793    "http://000000177.0000001",
    794    "http://017700000001",
    795    "http://0x7f.0x00.0x00.0x01",
    796    "http://0x7f.0x01",
    797    "http://0x7f000001",
    798    "http://0x007f.0x0000.0x0000.0x0001",
    799    "http://000177.0.00000.0x0001",
    800    "http://127.0.0.1.",
    801  ].map(stringToURL);
    802 
    803  let url;
    804  for (url of localIPv4s) {
    805    Assert.equal(url.spec, "http://127.0.0.1/");
    806  }
    807 
    808  // These should treated as a domain instead of an IPv4.
    809  var nonIPv4s = [
    810    "http://2+3/",
    811    "http://0.0.0.-1/",
    812    "http://1.2.3.4../",
    813    "resource://123/",
    814    "resource://4294967296/",
    815  ];
    816  var spec;
    817  for (spec of nonIPv4s) {
    818    url = stringToURL(spec);
    819    Assert.equal(url.spec, spec);
    820  }
    821 
    822  url = stringToURL("resource://path/to/resource/");
    823  url = url.mutate().setHost("123").finalize();
    824  Assert.equal(url.host, "123");
    825 
    826  run_next_test();
    827 });
    828 
    829 add_test(function test_invalidHostChars() {
    830  var url = stringToURL("http://example.org/");
    831  for (let i = 0; i <= 0x20; i++) {
    832    // These characters get filtered.
    833    if (
    834      String.fromCharCode(i) == "\r" ||
    835      String.fromCharCode(i) == "\n" ||
    836      String.fromCharCode(i) == "\t"
    837    ) {
    838      continue;
    839    }
    840    Assert.throws(
    841      () => {
    842        url = url
    843          .mutate()
    844          .setHost("a" + String.fromCharCode(i) + "b")
    845          .finalize();
    846      },
    847      /NS_ERROR_MALFORMED_URI/,
    848      "Trying to set hostname containing char code: " + i
    849    );
    850  }
    851  for (let c of '@[]*<>|:"') {
    852    Assert.throws(
    853      () => {
    854        url = url
    855          .mutate()
    856          .setHost("a" + c)
    857          .finalize();
    858      },
    859      /NS_ERROR_MALFORMED_URI/,
    860      "Trying to set hostname containing char: " + c
    861    );
    862  }
    863 
    864  // It also can't contain /, \, #, ?, but we treat these characters as
    865  // hostname separators, so there is no way to set them and fail.
    866  run_next_test();
    867 });
    868 
    869 add_test(function test_normalize_ipv6() {
    870  var url = stringToURL("http://example.com");
    871  url = url.mutate().setHost("[::192.9.5.5]").finalize();
    872  Assert.equal(url.spec, "http://[::c009:505]/");
    873 
    874  run_next_test();
    875 });
    876 
    877 add_test(function test_emptyPassword() {
    878  var url = stringToURL("http://a:@example.com");
    879  Assert.equal(url.spec, "http://a@example.com/");
    880  url = url.mutate().setPassword("pp").finalize();
    881  Assert.equal(url.spec, "http://a:pp@example.com/");
    882  url = url.mutate().setPassword("").finalize();
    883  Assert.equal(url.spec, "http://a@example.com/");
    884  url = url.mutate().setUserPass("xxx:").finalize();
    885  Assert.equal(url.spec, "http://xxx@example.com/");
    886  url = url.mutate().setPassword("zzzz").finalize();
    887  Assert.equal(url.spec, "http://xxx:zzzz@example.com/");
    888  url = url.mutate().setUserPass("xxxxx:yyyyyy").finalize();
    889  Assert.equal(url.spec, "http://xxxxx:yyyyyy@example.com/");
    890  url = url.mutate().setUserPass("z:").finalize();
    891  Assert.equal(url.spec, "http://z@example.com/");
    892  url = url.mutate().setPassword("ppppppppppp").finalize();
    893  Assert.equal(url.spec, "http://z:ppppppppppp@example.com/");
    894 
    895  url = stringToURL("http://example.com");
    896  url = url.mutate().setPassword("").finalize(); // Still empty. Should work.
    897  Assert.equal(url.spec, "http://example.com/");
    898 
    899  run_next_test();
    900 });
    901 
    902 add_test(function test_emptyUser() {
    903  let url = stringToURL("http://:a@example.com/path/to/something?query#hash");
    904  Assert.equal(url.spec, "http://:a@example.com/path/to/something?query#hash");
    905  url = stringToURL("http://:@example.com/path/to/something?query#hash");
    906  Assert.equal(url.spec, "http://example.com/path/to/something?query#hash");
    907 
    908  const kurl = stringToURL(
    909    "http://user:pass@example.com:8888/path/to/something?query#hash"
    910  );
    911  url = kurl.mutate().setUsername("").finalize();
    912  Assert.equal(
    913    url.spec,
    914    "http://:pass@example.com:8888/path/to/something?query#hash"
    915  );
    916  Assert.equal(url.host, "example.com");
    917  Assert.equal(url.hostPort, "example.com:8888");
    918  Assert.equal(url.filePath, "/path/to/something");
    919  Assert.equal(url.query, "query");
    920  Assert.equal(url.ref, "hash");
    921  url = kurl.mutate().setUserPass(":pass1").finalize();
    922  Assert.equal(
    923    url.spec,
    924    "http://:pass1@example.com:8888/path/to/something?query#hash"
    925  );
    926  Assert.equal(url.host, "example.com");
    927  Assert.equal(url.hostPort, "example.com:8888");
    928  Assert.equal(url.filePath, "/path/to/something");
    929  Assert.equal(url.query, "query");
    930  Assert.equal(url.ref, "hash");
    931  url = url.mutate().setUsername("user2").finalize();
    932  Assert.equal(
    933    url.spec,
    934    "http://user2:pass1@example.com:8888/path/to/something?query#hash"
    935  );
    936  Assert.equal(url.host, "example.com");
    937  url = url.mutate().setUserPass(":pass234").finalize();
    938  Assert.equal(
    939    url.spec,
    940    "http://:pass234@example.com:8888/path/to/something?query#hash"
    941  );
    942  Assert.equal(url.host, "example.com");
    943  url = url.mutate().setUserPass("").finalize();
    944  Assert.equal(
    945    url.spec,
    946    "http://example.com:8888/path/to/something?query#hash"
    947  );
    948  Assert.equal(url.host, "example.com");
    949  url = url.mutate().setPassword("pa").finalize();
    950  Assert.equal(
    951    url.spec,
    952    "http://:pa@example.com:8888/path/to/something?query#hash"
    953  );
    954  Assert.equal(url.host, "example.com");
    955  url = url.mutate().setUserPass("user:pass").finalize();
    956  symmetricEquality(true, url.QueryInterface(Ci.nsIURL), kurl);
    957 
    958  url = stringToURL("http://example.com:8888/path/to/something?query#hash");
    959  url = url.mutate().setPassword("pass").finalize();
    960  Assert.equal(
    961    url.spec,
    962    "http://:pass@example.com:8888/path/to/something?query#hash"
    963  );
    964  url = url.mutate().setUsername("").finalize();
    965  Assert.equal(
    966    url.spec,
    967    "http://:pass@example.com:8888/path/to/something?query#hash"
    968  );
    969 
    970  url = stringToURL("http://example.com:8888");
    971  url = url.mutate().setUsername("user").finalize();
    972  url = url.mutate().setUsername("").finalize();
    973  Assert.equal(url.spec, "http://example.com:8888/");
    974 
    975  url = stringToURL("http://:pass@example.com");
    976  Assert.equal(url.spec, "http://:pass@example.com/");
    977  url = url.mutate().setPassword("").finalize();
    978  Assert.equal(url.spec, "http://example.com/");
    979  url = url.mutate().setUserPass("user:pass").finalize();
    980  Assert.equal(url.spec, "http://user:pass@example.com/");
    981  Assert.equal(url.host, "example.com");
    982  url = url.mutate().setUserPass("u:p").finalize();
    983  Assert.equal(url.spec, "http://u:p@example.com/");
    984  Assert.equal(url.host, "example.com");
    985  url = url.mutate().setUserPass("u1:p23").finalize();
    986  Assert.equal(url.spec, "http://u1:p23@example.com/");
    987  Assert.equal(url.host, "example.com");
    988  url = url.mutate().setUsername("u").finalize();
    989  Assert.equal(url.spec, "http://u:p23@example.com/");
    990  Assert.equal(url.host, "example.com");
    991  url = url.mutate().setPassword("p").finalize();
    992  Assert.equal(url.spec, "http://u:p@example.com/");
    993  Assert.equal(url.host, "example.com");
    994 
    995  url = url.mutate().setUserPass("u2:p2").finalize();
    996  Assert.equal(url.spec, "http://u2:p2@example.com/");
    997  Assert.equal(url.host, "example.com");
    998  url = url.mutate().setUserPass("u23:p23").finalize();
    999  Assert.equal(url.spec, "http://u23:p23@example.com/");
   1000  Assert.equal(url.host, "example.com");
   1001 
   1002  run_next_test();
   1003 });
   1004 
   1005 registerCleanupFunction(function () {
   1006  gPrefs.clearUserPref("network.standard-url.punycode-host");
   1007 });
   1008 
   1009 add_test(function test_idna_host() {
   1010  // See bug 945240 - this test makes sure that URLs return a punycode hostname
   1011  let url = stringToURL(
   1012    "http://user:password@ält.example.org:8080/path?query#etc"
   1013  );
   1014  equal(url.host, "xn--lt-uia.example.org");
   1015  equal(url.hostPort, "xn--lt-uia.example.org:8080");
   1016  equal(url.prePath, "http://user:password@xn--lt-uia.example.org:8080");
   1017  equal(
   1018    url.spec,
   1019    "http://user:password@xn--lt-uia.example.org:8080/path?query#etc"
   1020  );
   1021  equal(
   1022    url.specIgnoringRef,
   1023    "http://user:password@xn--lt-uia.example.org:8080/path?query"
   1024  );
   1025  equal(
   1026    url
   1027      .QueryInterface(Ci.nsISensitiveInfoHiddenURI)
   1028      .getSensitiveInfoHiddenSpec(),
   1029    "http://user:****@xn--lt-uia.example.org:8080/path?query#etc"
   1030  );
   1031 
   1032  equal(url.displayHost, "ält.example.org");
   1033  equal(url.displayHostPort, "ält.example.org:8080");
   1034  equal(
   1035    url.displaySpec,
   1036    "http://user:password@ält.example.org:8080/path?query#etc"
   1037  );
   1038 
   1039  equal(url.asciiHost, "xn--lt-uia.example.org");
   1040  equal(url.asciiHostPort, "xn--lt-uia.example.org:8080");
   1041  equal(
   1042    url.asciiSpec,
   1043    "http://user:password@xn--lt-uia.example.org:8080/path?query#etc"
   1044  );
   1045 
   1046  url = url.mutate().setRef("").finalize(); // SetRef calls InvalidateCache()
   1047  equal(
   1048    url.spec,
   1049    "http://user:password@xn--lt-uia.example.org:8080/path?query"
   1050  );
   1051  equal(
   1052    url.displaySpec,
   1053    "http://user:password@ält.example.org:8080/path?query"
   1054  );
   1055  equal(
   1056    url.asciiSpec,
   1057    "http://user:password@xn--lt-uia.example.org:8080/path?query"
   1058  );
   1059 
   1060  url = stringToURL("http://user:password@www.ält.com:8080/path?query#etc");
   1061  url = url.mutate().setRef("").finalize();
   1062  equal(url.spec, "http://user:password@www.xn--lt-uia.com:8080/path?query");
   1063 
   1064  run_next_test();
   1065 });
   1066 
   1067 add_test(
   1068  { skip_if: () => AppConstants.MOZ_APP_NAME == "thunderbird" },
   1069  function test_bug1517025() {
   1070    Assert.throws(
   1071      () => {
   1072        stringToURL("https://b%9a/");
   1073      },
   1074      /NS_ERROR_MALFORMED_URI/,
   1075      "bad URI"
   1076    );
   1077 
   1078    Assert.throws(
   1079      () => {
   1080        stringToURL("https://b%9ª/");
   1081      },
   1082      /NS_ERROR_MALFORMED_URI/,
   1083      "bad URI"
   1084    );
   1085 
   1086    let base = stringToURL(
   1087      "https://bug1517025.bmoattachments.org/attachment.cgi?id=9033787"
   1088    );
   1089    Assert.throws(
   1090      () => {
   1091        Services.io.newURI("/\\b%9ª", "windows-1252", base);
   1092      },
   1093      /NS_ERROR_MALFORMED_URI/,
   1094      "bad URI"
   1095    );
   1096 
   1097    run_next_test();
   1098  }
   1099 );
   1100 
   1101 add_task(async function test_emptyHostWithURLType() {
   1102  let makeURL = (str, type) => {
   1103    return Cc["@mozilla.org/network/standard-url-mutator;1"]
   1104      .createInstance(Ci.nsIStandardURLMutator)
   1105      .init(type, 80, str, "UTF-8", null)
   1106      .finalize()
   1107      .QueryInterface(Ci.nsIURL);
   1108  };
   1109 
   1110  let url = makeURL("http://foo.com/bar/", Ci.nsIStandardURL.URLTYPE_AUTHORITY);
   1111  Assert.throws(
   1112    () => url.mutate().setHost("").finalize().spec,
   1113    /NS_ERROR_UNEXPECTED/,
   1114    "Empty host is not allowed for URLTYPE_AUTHORITY"
   1115  );
   1116 
   1117  url = makeURL("http://user@foo.com/bar/", Ci.nsIStandardURL.URLTYPE_STANDARD);
   1118  Assert.throws(
   1119    () => url.mutate().setHost("").finalize().spec,
   1120    /NS_ERROR_MALFORMED_URI/,
   1121    "Setting an empty host should throw if there is a username present"
   1122  );
   1123 
   1124  url = makeURL(
   1125    "http://:password@foo.com/bar/",
   1126    Ci.nsIStandardURL.URLTYPE_STANDARD
   1127  );
   1128  Assert.throws(
   1129    () => url.mutate().setHost("").finalize().spec,
   1130    /NS_ERROR_MALFORMED_URI/,
   1131    "Setting an empty host should throw if there is a password present"
   1132  );
   1133 
   1134  url = makeURL("http://foo.com:123/bar/", Ci.nsIStandardURL.URLTYPE_STANDARD);
   1135  Assert.throws(
   1136    () => url.mutate().setHost("").finalize().spec,
   1137    /NS_ERROR_MALFORMED_URI/,
   1138    "Setting an empty host should throw if there is a port present"
   1139  );
   1140 
   1141  url = makeURL("http://foo.com/bar/", Ci.nsIStandardURL.URLTYPE_STANDARD);
   1142  Assert.equal(url.mutate().setHost("").finalize().spec, "http:///bar/");
   1143 
   1144  url = makeURL("http://foo.com/bar/", Ci.nsIStandardURL.URLTYPE_NO_AUTHORITY);
   1145  equal(
   1146    url.spec,
   1147    "http:///bar/",
   1148    "Host is removed when parsing URLTYPE_NO_AUTHORITY"
   1149  );
   1150  equal(
   1151    url.mutate().setHost("").finalize().spec,
   1152    "http:///bar/",
   1153    "Setting an empty host does nothing for URLTYPE_NO_AUTHORITY"
   1154  );
   1155  Assert.throws(
   1156    () => url.mutate().setHost("something").finalize().spec,
   1157    /NS_ERROR_UNEXPECTED/,
   1158    "Setting a non-empty host is not allowed for URLTYPE_NO_AUTHORITY"
   1159  );
   1160  equal(
   1161    url.mutate().setHost("#j").finalize().spec,
   1162    "http:///bar/",
   1163    "Setting a pseudo-empty host does nothing for URLTYPE_NO_AUTHORITY"
   1164  );
   1165 
   1166  url = makeURL(
   1167    "http://example.org:123/foo?bar#baz",
   1168    Ci.nsIStandardURL.URLTYPE_AUTHORITY
   1169  );
   1170  Assert.throws(
   1171    () => url.mutate().setHost("#j").finalize().spec,
   1172    /NS_ERROR_UNEXPECTED/,
   1173    "A pseudo-empty host is not allowed for URLTYPE_AUTHORITY"
   1174  );
   1175 });
   1176 
   1177 add_task(async function test_fuzz() {
   1178  let makeURL = str => {
   1179    return (
   1180      Cc["@mozilla.org/network/standard-url-mutator;1"]
   1181        .createInstance(Ci.nsIStandardURLMutator)
   1182        .QueryInterface(Ci.nsIURIMutator)
   1183        // .init(type, 80, str, "UTF-8", null)
   1184        .setSpec(str)
   1185        .finalize()
   1186        .QueryInterface(Ci.nsIURL)
   1187    );
   1188  };
   1189 
   1190  Assert.throws(() => {
   1191    let url = makeURL("/");
   1192    url.mutate().setHost("(").finalize();
   1193  }, /NS_ERROR_MALFORMED_URI/);
   1194 });
   1195 
   1196 add_task(async function test_bug1648493() {
   1197  let url = stringToURL("https://example.com/");
   1198  url = url.mutate().setScheme("file").finalize();
   1199  url = url.mutate().setScheme("resource").finalize();
   1200  url = url.mutate().setPassword("ê").finalize();
   1201  url = url.mutate().setUsername("ç").finalize();
   1202  url = url.mutate().setScheme("t").finalize();
   1203  equal(url.spec, "t://%C3%83%C2%A7:%C3%83%C2%AA@example.com/");
   1204  equal(url.username, "%C3%83%C2%A7");
   1205 });
   1206 
   1207 add_task(async function test_bug1873976() {
   1208  let url = Services.io.newURI("file:.");
   1209  equal(url.spec, "file:///");
   1210 });
   1211 
   1212 add_task(async function test_bug1890346() {
   1213  let url = Services.io.newURI("file:..?/..");
   1214  equal(url.spec, "file:///?/..");
   1215 });
   1216 
   1217 add_task(async function test_bug1914141() {
   1218  equal(Services.io.isValidHostname("example.com"), true);
   1219  equal(Services.io.isValidHostname("example.0"), false);
   1220 
   1221  equal(Services.io.isValidHostname("192.168.0.1"), true);
   1222  equal(Services.io.isValidHostname("192.168.0"), true);
   1223  equal(Services.io.isValidHostname("1.192.168.0.1"), false);
   1224  equal(Services.io.isValidHostname("invalid.192.168.0.1"), false);
   1225 
   1226  equal(Services.io.isValidHostname("::1"), true);
   1227  equal(Services.io.isValidHostname("abcd::zz::00"), false);
   1228  equal(Services.io.isValidHostname("zzzz::1.2.3.4"), false);
   1229 
   1230  equal(Services.io.isValidHostname("::1.2.3.4"), true);
   1231 });