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 });