"use strict";
const gPrefs = Services.prefs;
function symmetricEquality(expect, a, b) {
/* Use if/else instead of |do_check_eq(expect, a.spec == b.spec)| so
that we get the specs output on the console if the check fails.
*/
if (expect) {
/* Check all the sub-pieces too, since that can help with
debugging cases when equals() returns something unexpected */
/* We don't check port in the loop, because it can be defaulted in
some cases. */
[
"spec",
"prePath",
"scheme",
"userPass",
"username",
"password",
"hostPort",
"host",
"pathQueryRef",
"filePath",
"query",
"ref",
"directory",
"fileName",
"fileBaseName",
"fileExtension",
].map(
function (prop) {
dump(
"Testing '" + prop +
"'\n");
Assert.equal(a[prop], b[prop]);
});
}
else {
Assert.notEqual(a.spec, b.spec);
}
Assert.equal(expect, a.equals(b));
Assert.equal(expect, b.equals(a));
}
function stringToURL(str) {
return Cc[
"@mozilla.org/network/standard-url-mutator;1"]
.createInstance(Ci.nsIStandardURLMutator)
.init(Ci.nsIStandardURL.URLTYPE_AUTHORITY, 80, str,
"UTF-8",
null)
.finalize()
.QueryInterface(Ci.nsIURL);
}
function pairToURLs(pair) {
Assert.equal(pair.length, 2);
return pair.map(stringToURL);
}
add_test(
function test_setEmptyPath() {
var pairs = [
[
"http://example.com", "http://example.com/tests/dom/tests"],
[
"http://example.com:80", "http://example.com/tests/dom/tests"],
[
"http://example.com:80/", "http://example.com/tests/dom/test"],
[
"http://example.com/", "http://example.com/tests/dom/tests"],
[
"http://example.com/a", "http://example.com/tests/dom/tests"],
[
"http://example.com:80/a", "http://example.com/tests/dom/tests"],
].map(pairToURLs);
for (
var [provided, target] of pairs) {
symmetricEquality(
false, target, provided);
provided = provided.mutate().setPathQueryRef(
"").finalize();
target = target.mutate().setPathQueryRef(
"").finalize();
Assert.equal(provided.spec, target.spec);
symmetricEquality(
true, target, provided);
}
run_next_test();
});
add_test(
function test_setQuery() {
var pairs = [
[
"http://example.com", "http://example.com/?foo"],
[
"http://example.com/bar", "http://example.com/bar?foo"],
[
"http://example.com#bar", "http://example.com/?foo#bar"],
[
"http://example.com/#bar", "http://example.com/?foo#bar"],
[
"http://example.com/?longerthanfoo#bar", "http://example.com/?foo#bar"],
[
"http://example.com/?longerthanfoo", "http://example.com/?foo"],
/* And one that's nonempty but shorter than "foo" */
[
"http://example.com/?f#bar", "http://example.com/?foo#bar"],
[
"http://example.com/?f", "http://example.com/?foo"],
].map(pairToURLs);
for (
var [provided, target] of pairs) {
symmetricEquality(
false, provided, target);
provided = provided
.mutate()
.setQuery(
"foo")
.finalize()
.QueryInterface(Ci.nsIURL);
Assert.equal(provided.spec, target.spec);
symmetricEquality(
true, provided, target);
}
[provided, target] = [
"http://example.com/#",
"http://example.com/?foo#bar",
].map(stringToURL);
symmetricEquality(
false, provided, target);
provided = provided
.mutate()
.setQuery(
"foo")
.finalize()
.QueryInterface(Ci.nsIURL);
symmetricEquality(
false, provided, target);
var newProvided = Services.io
.newURI(
"#bar",
null, provided)
.QueryInterface(Ci.nsIURL);
Assert.equal(newProvided.spec, target.spec);
symmetricEquality(
true, newProvided, target);
run_next_test();
});
add_test(
function test_setRef() {
var tests = [
[
"http://example.com", "", "http://example.com/"],
[
"http://example.com:80", "", "http://example.com:80/"],
[
"http://example.com:80/", "", "http://example.com:80/"],
[
"http://example.com/", "", "http://example.com/"],
[
"http://example.com/a", "", "http://example.com/a"],
[
"http://example.com:80/a", "", "http://example.com:80/a"],
[
"http://example.com", "x", "http://example.com/#x"],
[
"http://example.com:80", "x", "http://example.com:80/#x"],
[
"http://example.com:80/", "x", "http://example.com:80/#x"],
[
"http://example.com/", "x", "http://example.com/#x"],
[
"http://example.com/a", "x", "http://example.com/a#x"],
[
"http://example.com:80/a", "x", "http://example.com:80/a#x"],
[
"http://example.com", "xx", "http://example.com/#xx"],
[
"http://example.com:80", "xx", "http://example.com:80/#xx"],
[
"http://example.com:80/", "xx", "http://example.com:80/#xx"],
[
"http://example.com/", "xx", "http://example.com/#xx"],
[
"http://example.com/a", "xx", "http://example.com/a#xx"],
[
"http://example.com:80/a", "xx", "http://example.com:80/a#xx"],
[
"http://example.com",
"xxxxxxxxxxxxxx",
"http://example.com/#xxxxxxxxxxxxxx",
],
[
"http://example.com:80",
"xxxxxxxxxxxxxx",
"http://example.com:80/#xxxxxxxxxxxxxx",
],
[
"http://example.com:80/",
"xxxxxxxxxxxxxx",
"http://example.com:80/#xxxxxxxxxxxxxx",
],
[
"http://example.com/",
"xxxxxxxxxxxxxx",
"http://example.com/#xxxxxxxxxxxxxx",
],
[
"http://example.com/a",
"xxxxxxxxxxxxxx",
"http://example.com/a#xxxxxxxxxxxxxx",
],
[
"http://example.com:80/a",
"xxxxxxxxxxxxxx",
"http://example.com:80/a#xxxxxxxxxxxxxx",
],
];
for (
var [before, ref, result] of tests) {
/* Test1: starting with empty ref */
var a = stringToURL(before);
a = a.mutate().setRef(ref).finalize().QueryInterface(Ci.nsIURL);
var b = stringToURL(result);
Assert.equal(a.spec, b.spec);
Assert.equal(ref, b.ref);
symmetricEquality(
true, a, b);
/* Test2: starting with non-empty */
a = a.mutate().setRef(
"yyyy").finalize().QueryInterface(Ci.nsIURL);
var c = stringToURL(before);
c = c.mutate().setRef(
"yyyy").finalize().QueryInterface(Ci.nsIURL);
symmetricEquality(
true, a, c);
/* Test3: reset the ref */
a = a.mutate().setRef(
"").finalize().QueryInterface(Ci.nsIURL);
symmetricEquality(
true, a, stringToURL(before));
/* Test4: verify again after reset */
a = a.mutate().setRef(ref).finalize().QueryInterface(Ci.nsIURL);
symmetricEquality(
true, a, b);
}
run_next_test();
});
// Bug 960014 - Make nsStandardURL::SetHost less magical around IPv6
add_test(
function test_ipv6() {
var url = stringToURL(
"http://example.com");
url = url.mutate().setHost(
"[2001::1]").finalize();
Assert.equal(url.host,
"2001::1");
url = stringToURL(
"http://example.com");
url = url.mutate().setHostPort(
"[2001::1]:30").finalize();
Assert.equal(url.host,
"2001::1");
Assert.equal(url.port, 30);
Assert.equal(url.hostPort,
"[2001::1]:30");
url = stringToURL(
"http://example.com");
url = url.mutate().setHostPort(
"2001:1").finalize();
Assert.equal(url.host,
"0.0.7.209");
Assert.equal(url.port, 1);
Assert.equal(url.hostPort,
"0.0.7.209:1");
run_next_test();
});
add_test(
function test_ipv6_fail() {
var url = stringToURL(
"http://example.com");
Assert.
throws(
() => {
url = url.mutate().setHost(
"2001::1").finalize();
},
/NS_ERROR_MALFORMED_URI/,
"missing brackets"
);
Assert.
throws(
() => {
url = url.mutate().setHost(
"[2001::1]:20").finalize();
},
/NS_ERROR_MALFORMED_URI/,
"url.host with port"
);
Assert.
throws(
() => {
url = url.mutate().setHost(
"[2001::1").finalize();
},
/NS_ERROR_MALFORMED_URI/,
"missing last bracket"
);
Assert.
throws(
() => {
url = url.mutate().setHost(
"2001::1]").finalize();
},
/NS_ERROR_MALFORMED_URI/,
"missing first bracket"
);
Assert.
throws(
() => {
url = url.mutate().setHost(
"2001[::1]").finalize();
},
/NS_ERROR_MALFORMED_URI/,
"bad bracket position"
);
Assert.
throws(
() => {
url = url.mutate().setHost(
"[]").finalize();
},
/NS_ERROR_MALFORMED_URI/,
"empty IPv6 address"
);
Assert.
throws(
() => {
url = url.mutate().setHost(
"[hello]").finalize();
},
/NS_ERROR_MALFORMED_URI/,
"bad IPv6 address"
);
Assert.
throws(
() => {
url = url.mutate().setHost(
"[192.168.1.1]").finalize();
},
/NS_ERROR_MALFORMED_URI/,
"bad IPv6 address"
);
Assert.
throws(
() => {
url = url.mutate().setHostPort(
"2001::1").finalize();
},
/NS_ERROR_MALFORMED_URI/,
"missing brackets"
);
Assert.
throws(
() => {
url = url.mutate().setHostPort(
"[2001::1]30").finalize();
},
/NS_ERROR_MALFORMED_URI/,
"missing : after IP"
);
Assert.
throws(
() => {
url = url.mutate().setHostPort(
"[2001:1]").finalize();
},
/NS_ERROR_MALFORMED_URI/,
"bad IPv6 address"
);
Assert.
throws(
() => {
url = url.mutate().setHostPort(
"[2001:1]10").finalize();
},
/NS_ERROR_MALFORMED_URI/,
"bad IPv6 address"
);
Assert.
throws(
() => {
url = url.mutate().setHostPort(
"[2001:1]10:20").finalize();
},
/NS_ERROR_MALFORMED_URI/,
"bad IPv6 address"
);
Assert.
throws(
() => {
url = url.mutate().setHostPort(
"[2001:1]:10:20").finalize();
},
/NS_ERROR_MALFORMED_URI/,
"bad IPv6 address"
);
Assert.
throws(
() => {
url = url.mutate().setHostPort(
"[2001:1").finalize();
},
/NS_ERROR_MALFORMED_URI/,
"bad IPv6 address"
);
Assert.
throws(
() => {
url = url.mutate().setHostPort(
"2001]:1").finalize();
},
/NS_ERROR_MALFORMED_URI/,
"bad IPv6 address"
);
Assert.
throws(
() => {
url = url.mutate().setHostPort(
"2001:1]").finalize();
},
/NS_ERROR_MALFORMED_URI/,
"bad IPv6 address"
);
Assert.
throws(
() => {
url = url.mutate().setHostPort(
"").finalize();
},
/NS_ERROR_UNEXPECTED/,
"Empty hostPort should fail"
);
// These checks used to fail, but now don't (see bug 1433958 comment 57)
url = url.mutate().setHostPort(
"[2001::1]:").finalize();
Assert.equal(url.spec,
"http://[2001::1]/");
url = url.mutate().setHostPort(
"[2002::1]:bad").finalize();
Assert.equal(url.spec,
"http://[2002::1]/");
run_next_test();
});
add_test(
function test_clearedSpec() {
var url = stringToURL(
"http://example.com/path");
Assert.
throws(
() => {
url = url.mutate().setSpec(
"http: example").finalize();
},
/NS_ERROR_MALFORMED_URI/,
"set bad spec"
);
Assert.
throws(
() => {
url = url.mutate().setSpec(
"").finalize();
},
/NS_ERROR_MALFORMED_URI/,
"set empty spec"
);
Assert.equal(url.spec,
"http://example.com/path");
url = url
.mutate()
.setHost(
"allizom.org")
.finalize()
.QueryInterface(Ci.nsIURL);
var ref = stringToURL(
"http://allizom.org/path");
symmetricEquality(
true, url, ref);
run_next_test();
});
add_test(
function test_escapeBrackets() {
// Query
var url = stringToURL(
"http://example.com/?a[x]=1");
Assert.equal(url.spec,
"http://example.com/?a[x]=1");
url = stringToURL(
"http://example.com/?a%5Bx%5D=1");
Assert.equal(url.spec,
"http://example.com/?a%5Bx%5D=1");
url = stringToURL(
"http://[2001::1]/?a[x]=1");
Assert.equal(url.spec,
"http://[2001::1]/?a[x]=1");
url = stringToURL(
"http://[2001::1]/?a%5Bx%5D=1");
Assert.equal(url.spec,
"http://[2001::1]/?a%5Bx%5D=1");
// Path
url = stringToURL(
"http://example.com/brackets[x]/test");
Assert.equal(url.spec,
"http://example.com/brackets[x]/test");
url = stringToURL(
"http://example.com/a%5Bx%5D/test");
Assert.equal(url.spec,
"http://example.com/a%5Bx%5D/test");
run_next_test();
});
add_test(
function test_escapeQuote() {
var url = stringToURL(
"http://example.com/#'");
Assert.equal(url.spec,
"http://example.com/#'");
Assert.equal(url.ref,
"'");
url = url.mutate().setRef(
"test'test").finalize();
Assert.equal(url.spec,
"http://example.com/#test'test");
Assert.equal(url.ref,
"test'test");
run_next_test();
});
add_test(
function test_apostropheEncoding() {
// For now, single quote is escaped everywhere _except_ the path.
// This policy is controlled by the bitmask in nsEscape.cpp::EscapeChars[]
var url = stringToURL(
"http://example.com/dir'/file'.ext'");
Assert.equal(url.spec,
"http://example.com/dir'/file'.ext'");
run_next_test();
});
add_test(
function test_accentEncoding() {
var url = stringToURL(
"http://example.com/?hello=`");
Assert.equal(url.spec,
"http://example.com/?hello=`");
Assert.equal(url.query,
"hello=`");
url = stringToURL(
"http://example.com/?hello=%2C");
Assert.equal(url.spec,
"http://example.com/?hello=%2C");
Assert.equal(url.query,
"hello=%2C");
run_next_test();
});
add_test(
{ skip_if: () => AppConstants.MOZ_APP_NAME ==
"thunderbird" },
function test_percentDecoding() {
var url = stringToURL(
"http://%70%61%73%74%65%62%69%6E.com");
Assert.equal(url.spec,
"http://pastebin.com/");
// Disallowed hostname characters are rejected even when percent encoded
Assert.
throws(
() => {
url = stringToURL(
"http://example.com%0a%23.google.com/");
},
/NS_ERROR_MALFORMED_URI/,
"invalid characters are not allowed"
);
run_next_test();
}
);
add_test(
function test_hugeStringThrows() {
let prefs = Services.prefs;
let maxLen = prefs.getIntPref(
"network.standard-url.max-length");
let url = stringToURL(
"http://test:test@example.com");
let hugeString =
new Array(maxLen + 1).fill(
"a").join(
"");
let setters = [
{ method:
"setSpec", qi: Ci.nsIURIMutator },
{ method:
"setUsername", qi: Ci.nsIURIMutator },
{ method:
"setPassword", qi: Ci.nsIURIMutator },
{ method:
"setFilePath", qi: Ci.nsIURIMutator },
{ method:
"setHostPort", qi: Ci.nsIURIMutator },
{ method:
"setHost", qi: Ci.nsIURIMutator },
{ method:
"setUserPass", qi: Ci.nsIURIMutator },
{ method:
"setPathQueryRef", qi: Ci.nsIURIMutator },
{ method:
"setQuery", qi: Ci.nsIURIMutator },
{ method:
"setRef", qi: Ci.nsIURIMutator },
{ method:
"setScheme", qi: Ci.nsIURIMutator },
{ method:
"setFileName", qi: Ci.nsIURLMutator },
{ method:
"setFileExtension", qi: Ci.nsIURLMutator },
{ method:
"setFileBaseName", qi: Ci.nsIURLMutator },
];
for (let prop of setters) {
Assert.
throws(
() =>
(url = url
.mutate()
.QueryInterface(prop.qi)
[prop.method](hugeString)
.finalize()),
/NS_ERROR_MALFORMED_URI/,
`Passing a huge string to
"${prop.method}" should
throw`
);
}
run_next_test();
});
add_test(
function test_verticalBar() {
var url = Services.io.newURI(
"file:///w|m");
Assert.equal(url.spec,
"file:///w|m");
url = Services.io.newURI(
"file:///w||m");
Assert.equal(url.spec,
"file:///w||m");
url = Services.io.newURI(
"file:///w|/m");
Assert.equal(url.spec,
"file:///w:/m");
url = Services.io.newURI(
"file:C|/m/");
Assert.equal(url.spec,
"file:///C:/m/");
url = Services.io.newURI(
"file:C||/m/");
Assert.equal(url.spec,
"file:///C||/m/");
run_next_test();
});
add_test(
function test_pathPercentEncodedDot() {
var url = stringToURL(
"http://example.com/hello/%2e%2E/%2e");
Assert.equal(url.spec,
"http://example.com/");
Assert.equal(url.directory,
"/");
Assert.equal(url.fileName,
"");
Assert.equal(url.fileBaseName,
"");
Assert.equal(url.fileExtension,
"");
url = stringToURL(
"http://example.com/hello/%2e%2E/%");
Assert.equal(url.spec,
"http://example.com/%");
Assert.equal(url.directory,
"/");
Assert.equal(url.fileName,
"%");
Assert.equal(url.fileBaseName,
"%");
Assert.equal(url.fileExtension,
"");
url = stringToURL(
"http://example.com/hello/%2e%2E/%2");
Assert.equal(url.spec,
"http://example.com/%2");
Assert.equal(url.directory,
"/");
Assert.equal(url.fileName,
"%2");
Assert.equal(url.fileBaseName,
"%2");
Assert.equal(url.fileExtension,
"");
url = stringToURL(
"http://example.com/hello/%2e%2E/%#");
Assert.equal(url.spec,
"http://example.com/%#");
Assert.equal(url.directory,
"/");
Assert.equal(url.fileName,
"%");
Assert.equal(url.fileBaseName,
"%");
Assert.equal(url.fileExtension,
"");
url = stringToURL(
"http://example.com/hello/%2e%2E/%2?");
Assert.equal(url.spec,
"http://example.com/%2?");
Assert.equal(url.directory,
"/");
Assert.equal(url.fileName,
"%2");
Assert.equal(url.fileBaseName,
"%2");
Assert.equal(url.fileExtension,
"");
url = stringToURL(
"http://example.com/hello/%2e/");
Assert.equal(url.spec,
"http://example.com/hello/");
Assert.equal(url.directory,
"/hello/");
Assert.equal(url.fileName,
"");
Assert.equal(url.fileBaseName,
"");
Assert.equal(url.fileExtension,
"");
url = stringToURL(
"http://example.com/%2e");
Assert.equal(url.spec,
"http://example.com/");
Assert.equal(url.directory,
"/");
Assert.equal(url.fileName,
"");
Assert.equal(url.fileBaseName,
"");
Assert.equal(url.fileExtension,
"");
url = stringToURL(
"http://example.com/.%2e");
Assert.equal(url.spec,
"http://example.com/");
Assert.equal(url.directory,
"/");
Assert.equal(url.fileName,
"");
Assert.equal(url.fileBaseName,
"");
Assert.equal(url.fileExtension,
"");
url = stringToURL(
"http://example.com/%2e.");
Assert.equal(url.spec,
"http://example.com/");
Assert.equal(url.directory,
"/");
Assert.equal(url.fileName,
"");
Assert.equal(url.fileBaseName,
"");
Assert.equal(url.fileExtension,
"");
url = stringToURL(
"http://example.com/%2e%2e");
Assert.equal(url.spec,
"http://example.com/");
Assert.equal(url.directory,
"/");
Assert.equal(url.fileName,
"");
Assert.equal(url.fileBaseName,
"");
Assert.equal(url.fileExtension,
"");
url = stringToURL(
"http://example.com/%2e%2e%2e");
Assert.equal(url.spec,
"http://example.com/%2e%2e%2e");
Assert.equal(url.directory,
"/");
Assert.equal(url.fileName,
"%2e%2e%2e");
Assert.equal(url.fileBaseName,
"%2e%2e%2e");
Assert.equal(url.fileExtension,
"");
url = stringToURL(
"http://example.com/%2e%2e%2e%2e");
Assert.equal(url.spec,
"http://example.com/%2e%2e%2e%2e");
Assert.equal(url.directory,
"/");
Assert.equal(url.fileName,
"%2e%2e%2e%2e");
Assert.equal(url.fileBaseName,
"%2e%2e%2e%2e");
Assert.equal(url.fileExtension,
"");
url = stringToURL(
"http://example.com/hello/%2e%2");
Assert.equal(url.spec,
"http://example.com/hello/%2e%2");
Assert.equal(url.directory,
"/hello/");
Assert.equal(url.fileName,
"%2e%2");
Assert.equal(url.fileBaseName,
"%2e%2");
Assert.equal(url.fileExtension,
"");
url = stringToURL(
"http://example.com/hello/%2e./%2e%2e/.%2e/%2e.bar");
Assert.equal(url.spec,
"http://example.com/%2e.bar");
Assert.equal(url.directory,
"/");
Assert.equal(url.fileName,
"%2e.bar");
Assert.equal(url.fileBaseName,
"%2e");
Assert.equal(url.fileExtension,
"bar");
url = stringToURL(
"http://example.com/%2eX/X%2e/%2eX");
Assert.equal(url.spec,
"http://example.com/%2eX/X%2e/%2eX");
Assert.equal(url.directory,
"/%2eX/X%2e/");
Assert.equal(url.fileName,
"%2eX");
Assert.equal(url.fileBaseName,
"%2eX");
Assert.equal(url.fileExtension,
"");
run_next_test();
});
add_test(
function test_filterWhitespace() {
let url = stringToURL(
" \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 "
);
Assert.equal(
url.spec,
"http://example.com/path/to%20the/file.ext?query#hash"
);
// These setters should filter \r\n\t.
url = stringToURL(
"http://test.com/path?query#hash");
url = url.mutate().setFilePath(
"pa\r\n\tth").finalize();
Assert.equal(url.spec,
"http://test.com/path?query#hash");
url = url.mutate().setQuery(
"que\r\n\try").finalize();
Assert.equal(url.spec,
"http://test.com/path?query#hash");
url = url.mutate().setRef(
"ha\r\n\tsh").finalize();
Assert.equal(url.spec,
"http://test.com/path?query#hash");
url = url
.mutate()
.QueryInterface(Ci.nsIURLMutator)
.setFileName(
"fi\r\n\tle.name")
.finalize();
Assert.equal(url.spec,
"http://test.com/fi%0D%0A%09le.name?query#hash");
run_next_test();
});
add_test(
function test_backslashReplacement() {
var url = stringToURL(
"http:\\\\test.com\\path/to\\file?query\\backslash#hash\\"
);
Assert.equal(
url.spec,
"http://test.com/path/to/file?query\\backslash#hash\\"
);
url = stringToURL(
"http:\\\\test.com\\example.org/path\\to/file");
Assert.equal(url.spec,
"http://test.com/example.org/path/to/file");
Assert.equal(url.host,
"test.com");
Assert.equal(url.pathQueryRef,
"/example.org/path/to/file");
run_next_test();
});
add_test(
function test_authority_host() {
Assert.
throws(
() => {
stringToURL(
"http:");
},
/NS_ERROR_MALFORMED_URI/,
"TYPE_AUTHORITY should have host"
);
Assert.
throws(
() => {
stringToURL(
"http:///");
},
/NS_ERROR_MALFORMED_URI/,
"TYPE_AUTHORITY should have host"
);
run_next_test();
});
add_test(
function test_trim_C0_and_space() {
var url = stringToURL(
"\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 "
);
Assert.equal(url.spec,
"http://example.com/");
url = url
.mutate()
.setSpec(
"\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 "
)
.finalize();
Assert.equal(url.spec,
"http://test.com/");
Assert.
throws(
() => {
url = url
.mutate()
.setSpec(
"\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 "
)
.finalize();
},
/NS_ERROR_MALFORMED_URI/,
"set empty spec"
);
run_next_test();
});
// This tests that C0-and-space characters in the path, query and ref are
// percent encoded.
add_test(
function test_encode_C0_and_space() {
function toHex(d) {
var hex = d.toString(16);
if (hex.length == 1) {
hex =
"0" + hex;
}
return hex.toUpperCase();
}
for (
var i = 0x0; i <= 0x20; i++) {
// These characters get filtered - they are not encoded.
if (
String.fromCharCode(i) ==
"\r" ||
String.fromCharCode(i) ==
"\n" ||
String.fromCharCode(i) ==
"\t"
) {
continue;
}
let url = stringToURL(
"http://example.com/pa" +
String.fromCharCode(i) +
"th?qu" +
String.fromCharCode(i) +
"ery#ha" +
String.fromCharCode(i) +
"sh"
);
Assert.equal(
url.spec,
"http://example.com/pa%" +
toHex(i) +
"th?qu%" +
toHex(i) +
"ery#ha%" +
toHex(i) +
"sh"
);
}
// Additionally, we need to check the setters.
let url = stringToURL(
"http://example.com/path?query#hash");
url = url.mutate().setFilePath(
"pa\0th").finalize();
Assert.equal(url.spec,
"http://example.com/pa%00th?query#hash");
url = url.mutate().setQuery(
"qu\0ery").finalize();
Assert.equal(url.spec,
"http://example.com/pa%00th?qu%00ery#hash");
url = url.mutate().setRef(
"ha\0sh").finalize();
Assert.equal(url.spec,
"http://example.com/pa%00th?qu%00ery#ha%00sh");
url = url
.mutate()
.QueryInterface(Ci.nsIURLMutator)
.setFileName(
"fi\0le.name")
.finalize();
Assert.equal(url.spec,
"http://example.com/fi%00le.name?qu%00ery#ha%00sh");
run_next_test();
});
add_test(
function test_ipv4Normalize() {
var localIPv4s = [
"http://127.0.0.1",
"http://127.0.1",
"http://127.1",
"http://2130706433",
"http://0177.00.00.01",
"http://0177.00.01",
"http://0177.01",
"http://00000000000000000000000000177.0000000.0000000.0001",
"http://000000177.0000001",
"http://017700000001",
"http://0x7f.0x00.0x00.0x01",
"http://0x7f.0x01",
"http://0x7f000001",
"http://0x007f.0x0000.0x0000.0x0001",
"http://000177.0.00000.0x0001",
"http://127.0.0.1.",
].map(stringToURL);
let url;
for (url of localIPv4s) {
Assert.equal(url.spec,
"http://127.0.0.1/");
}
// These should treated as a domain instead of an IPv4.
var nonIPv4s = [
"http://2+3/",
"http://0.0.0.-1/",
"http://1.2.3.4../",
"resource://123/",
"resource://4294967296/",
];
var spec;
for (spec of nonIPv4s) {
url = stringToURL(spec);
Assert.equal(url.spec, spec);
}
url = stringToURL(
"resource://path/to/resource/");
url = url.mutate().setHost(
"123").finalize();
Assert.equal(url.host,
"123");
run_next_test();
});
add_test(
function test_invalidHostChars() {
var url = stringToURL(
"http://example.org/");
for (let i = 0; i <= 0x20; i++) {
// These characters get filtered.
if (
String.fromCharCode(i) ==
"\r" ||
String.fromCharCode(i) ==
"\n" ||
String.fromCharCode(i) ==
"\t"
) {
continue;
}
Assert.
throws(
() => {
url = url
.mutate()
.setHost(
"a" + String.fromCharCode(i) +
"b")
.finalize();
},
/NS_ERROR_MALFORMED_URI/,
"Trying to set hostname containing char code: " + i
);
}
for (let c of
'@[]*<>|:"') {
Assert.
throws(
() => {
url = url
.mutate()
.setHost(
"a" + c)
.finalize();
},
/NS_ERROR_MALFORMED_URI/,
"Trying to set hostname containing char: " + c
);
}
// It also can't contain /, \, #, ?, but we treat these characters as
// hostname separators, so there is no way to set them and fail.
run_next_test();
});
add_test(
function test_normalize_ipv6() {
var url = stringToURL(
"http://example.com");
url = url.mutate().setHost(
"[::192.9.5.5]").finalize();
Assert.equal(url.spec,
"http://[::c009:505]/");
run_next_test();
});
add_test(
function test_emptyPassword() {
var url = stringToURL(
"http://a:@example.com");
Assert.equal(url.spec,
"http://a@example.com/");
url = url.mutate().setPassword(
"pp").finalize();
Assert.equal(url.spec,
"http://a:pp@example.com/");
url = url.mutate().setPassword(
"").finalize();
Assert.equal(url.spec,
"http://a@example.com/");
url = url.mutate().setUserPass(
"xxx:").finalize();
Assert.equal(url.spec,
"http://xxx@example.com/");
url = url.mutate().setPassword(
"zzzz").finalize();
Assert.equal(url.spec,
"http://xxx:zzzz@example.com/");
url = url.mutate().setUserPass(
"xxxxx:yyyyyy").finalize();
Assert.equal(url.spec,
"http://xxxxx:yyyyyy@example.com/");
url = url.mutate().setUserPass(
"z:").finalize();
Assert.equal(url.spec,
"http://z@example.com/");
url = url.mutate().setPassword(
"ppppppppppp").finalize();
Assert.equal(url.spec,
"http://z:ppppppppppp@example.com/");
url = stringToURL(
"http://example.com");
url = url.mutate().setPassword(
"").finalize();
// Still empty. Should work.
Assert.equal(url.spec,
"http://example.com/");
run_next_test();
});
add_test(
function test_emptyUser() {
let url = stringToURL(
"http://:a@example.com/path/to/something?query#hash");
Assert.equal(url.spec,
"http://:a@example.com/path/to/something?query#hash");
url = stringToURL(
"http://:@example.com/path/to/something?query#hash");
Assert.equal(url.spec,
"http://example.com/path/to/something?query#hash");
const kurl = stringToURL(
"http://user:pass@example.com:8888/path/to/something?query#hash"
);
url = kurl.mutate().setUsername(
"").finalize();
Assert.equal(
url.spec,
"http://:pass@example.com:8888/path/to/something?query#hash"
);
Assert.equal(url.host,
"example.com");
Assert.equal(url.hostPort,
"example.com:8888");
Assert.equal(url.filePath,
"/path/to/something");
Assert.equal(url.query,
"query");
Assert.equal(url.ref,
"hash");
url = kurl.mutate().setUserPass(
":pass1").finalize();
Assert.equal(
url.spec,
"http://:pass1@example.com:8888/path/to/something?query#hash"
);
Assert.equal(url.host,
"example.com");
Assert.equal(url.hostPort,
"example.com:8888");
Assert.equal(url.filePath,
"/path/to/something");
Assert.equal(url.query,
"query");
Assert.equal(url.ref,
"hash");
url = url.mutate().setUsername(
"user2").finalize();
Assert.equal(
url.spec,
"http://user2:pass1@example.com:8888/path/to/something?query#hash"
);
Assert.equal(url.host,
"example.com");
url = url.mutate().setUserPass(
":pass234").finalize();
Assert.equal(
url.spec,
"http://:pass234@example.com:8888/path/to/something?query#hash"
);
Assert.equal(url.host,
"example.com");
url = url.mutate().setUserPass(
"").finalize();
Assert.equal(
url.spec,
"http://example.com:8888/path/to/something?query#hash"
);
Assert.equal(url.host,
"example.com");
url = url.mutate().setPassword(
"pa").finalize();
Assert.equal(
url.spec,
"http://:pa@example.com:8888/path/to/something?query#hash"
);
Assert.equal(url.host,
"example.com");
url = url.mutate().setUserPass(
"user:pass").finalize();
symmetricEquality(
true, url.QueryInterface(Ci.nsIURL), kurl);
url = stringToURL(
"http://example.com:8888/path/to/something?query#hash");
url = url.mutate().setPassword(
"pass").finalize();
Assert.equal(
url.spec,
"http://:pass@example.com:8888/path/to/something?query#hash"
);
url = url.mutate().setUsername(
"").finalize();
Assert.equal(
url.spec,
"http://:pass@example.com:8888/path/to/something?query#hash"
);
url = stringToURL(
"http://example.com:8888");
url = url.mutate().setUsername(
"user").finalize();
url = url.mutate().setUsername(
"").finalize();
Assert.equal(url.spec,
"http://example.com:8888/");
url = stringToURL(
"http://:pass@example.com");
Assert.equal(url.spec,
"http://:pass@example.com/");
url = url.mutate().setPassword(
"").finalize();
Assert.equal(url.spec,
"http://example.com/");
url = url.mutate().setUserPass(
"user:pass").finalize();
Assert.equal(url.spec,
"http://user:pass@example.com/");
Assert.equal(url.host,
"example.com");
url = url.mutate().setUserPass(
"u:p").finalize();
Assert.equal(url.spec,
"http://u:p@example.com/");
Assert.equal(url.host,
"example.com");
url = url.mutate().setUserPass(
"u1:p23").finalize();
Assert.equal(url.spec,
"http://u1:p23@example.com/");
Assert.equal(url.host,
"example.com");
url = url.mutate().setUsername(
"u").finalize();
Assert.equal(url.spec,
"http://u:p23@example.com/");
Assert.equal(url.host,
"example.com");
url = url.mutate().setPassword(
"p").finalize();
Assert.equal(url.spec,
"http://u:p@example.com/");
Assert.equal(url.host,
"example.com");
url = url.mutate().setUserPass(
"u2:p2").finalize();
Assert.equal(url.spec,
"http://u2:p2@example.com/");
Assert.equal(url.host,
"example.com");
url = url.mutate().setUserPass(
"u23:p23").finalize();
Assert.equal(url.spec,
"http://u23:p23@example.com/");
Assert.equal(url.host,
"example.com");
run_next_test();
});
registerCleanupFunction(
function () {
gPrefs.clearUserPref(
"network.standard-url.punycode-host");
});
add_test(
function test_idna_host() {
// See bug 945240 - this test makes sure that URLs return a punycode hostname
let url = stringToURL(
"http://user:password@ält.example.org:8080/path?query#etc"
);
equal(url.host,
"xn--lt-uia.example.org");
equal(url.hostPort,
"xn--lt-uia.example.org:8080");
equal(url.prePath,
"http://user:password@xn--lt-uia.example.org:8080");
equal(
url.spec,
"http://user:password@xn--lt-uia.example.org:8080/path?query#etc"
);
equal(
url.specIgnoringRef,
"http://user:password@xn--lt-uia.example.org:8080/path?query"
);
equal(
url
.QueryInterface(Ci.nsISensitiveInfoHiddenURI)
.getSensitiveInfoHiddenSpec(),
"http://user:****@xn--lt-uia.example.org:8080/path?query#etc"
);
equal(url.displayHost,
"ält.example.org");
equal(url.displayHostPort,
"ält.example.org:8080");
equal(
url.displaySpec,
"http://user:password@ält.example.org:8080/path?query#etc"
);
equal(url.asciiHost,
"xn--lt-uia.example.org");
equal(url.asciiHostPort,
"xn--lt-uia.example.org:8080");
equal(
url.asciiSpec,
"http://user:password@xn--lt-uia.example.org:8080/path?query#etc"
);
url = url.mutate().setRef(
"").finalize();
// SetRef calls InvalidateCache()
equal(
url.spec,
"http://user:password@xn--lt-uia.example.org:8080/path?query"
);
equal(
url.displaySpec,
"http://user:password@ält.example.org:8080/path?query"
);
equal(
url.asciiSpec,
"http://user:password@xn--lt-uia.example.org:8080/path?query"
);
url = stringToURL(
"http://user:password@www.ält.com:8080/path?query#etc");
url = url.mutate().setRef(
"").finalize();
equal(url.spec,
"http://user:password@www.xn--lt-uia.com:8080/path?query");
run_next_test();
});
add_test(
{ skip_if: () => AppConstants.MOZ_APP_NAME ==
"thunderbird" },
function test_bug1517025() {
Assert.
throws(
() => {
stringToURL(
"https://b%9a/");
},
/NS_ERROR_MALFORMED_URI/,
"bad URI"
);
Assert.
throws(
() => {
stringToURL(
"https://b%9ª/");
},
/NS_ERROR_MALFORMED_URI/,
"bad URI"
);
let base = stringToURL(
"https://bug1517025.bmoattachments.org/attachment.cgi?id=9033787"
);
Assert.
throws(
() => {
Services.io.newURI(
"/\\b%9ª",
"windows-1252", base);
},
/NS_ERROR_MALFORMED_URI/,
"bad URI"
);
run_next_test();
}
);
add_task(async
function test_emptyHostWithURLType() {
let makeURL = (str, type) => {
return Cc[
"@mozilla.org/network/standard-url-mutator;1"]
.createInstance(Ci.nsIStandardURLMutator)
.init(type, 80, str,
"UTF-8",
null)
.finalize()
.QueryInterface(Ci.nsIURL);
};
let url = makeURL(
"http://foo.com/bar/", Ci.nsIStandardURL.URLTYPE_AUTHORITY);
Assert.
throws(
() => url.mutate().setHost(
"").finalize().spec,
/NS_ERROR_UNEXPECTED/,
"Empty host is not allowed for URLTYPE_AUTHORITY"
);
url = makeURL(
"http://user@foo.com/bar/", Ci.nsIStandardURL.URLTYPE_STANDARD);
Assert.
throws(
() => url.mutate().setHost(
"").finalize().spec,
/NS_ERROR_MALFORMED_URI/,
"Setting an empty host should throw if there is a username present"
);
url = makeURL(
"http://:password@foo.com/bar/",
Ci.nsIStandardURL.URLTYPE_STANDARD
);
Assert.
throws(
() => url.mutate().setHost(
"").finalize().spec,
/NS_ERROR_MALFORMED_URI/,
"Setting an empty host should throw if there is a password present"
);
url = makeURL(
"http://foo.com:123/bar/", Ci.nsIStandardURL.URLTYPE_STANDARD);
Assert.
throws(
() => url.mutate().setHost(
"").finalize().spec,
/NS_ERROR_MALFORMED_URI/,
"Setting an empty host should throw if there is a port present"
);
url = makeURL(
"http://foo.com/bar/", Ci.nsIStandardURL.URLTYPE_STANDARD);
Assert.equal(url.mutate().setHost(
"").finalize().spec,
"http:///bar/");
url = makeURL(
"http://foo.com/bar/", Ci.nsIStandardURL.URLTYPE_NO_AUTHORITY);
equal(
url.spec,
"http:///bar/",
"Host is removed when parsing URLTYPE_NO_AUTHORITY"
);
equal(
url.mutate().setHost(
"").finalize().spec,
"http:///bar/",
"Setting an empty host does nothing for URLTYPE_NO_AUTHORITY"
);
Assert.
throws(
() => url.mutate().setHost(
"something").finalize().spec,
/NS_ERROR_UNEXPECTED/,
"Setting a non-empty host is not allowed for URLTYPE_NO_AUTHORITY"
);
equal(
url.mutate().setHost(
"#j").finalize().spec,
"http:///bar/",
"Setting a pseudo-empty host does nothing for URLTYPE_NO_AUTHORITY"
);
url = makeURL(
"http://example.org:123/foo?bar#baz",
Ci.nsIStandardURL.URLTYPE_AUTHORITY
);
Assert.
throws(
() => url.mutate().setHost(
"#j").finalize().spec,
/NS_ERROR_UNEXPECTED/,
"A pseudo-empty host is not allowed for URLTYPE_AUTHORITY"
);
});
add_task(async
function test_fuzz() {
let makeURL = str => {
return (
Cc[
"@mozilla.org/network/standard-url-mutator;1"]
.createInstance(Ci.nsIStandardURLMutator)
.QueryInterface(Ci.nsIURIMutator)
// .init(type, 80, str, "UTF-8", null)
.setSpec(str)
.finalize()
.QueryInterface(Ci.nsIURL)
);
};
Assert.
throws(() => {
let url = makeURL(
"/");
url.mutate().setHost(
"(").finalize();
}, /NS_ERROR_MALFORMED_URI/);
});
add_task(async
function test_bug1648493() {
let url = stringToURL(
"https://example.com/");
url = url.mutate().setScheme(
"file").finalize();
url = url.mutate().setScheme(
"resource").finalize();
url = url.mutate().setPassword(
"ê").finalize();
url = url.mutate().setUsername(
"ç").finalize();
url = url.mutate().setScheme(
"t").finalize();
equal(url.spec,
"t://%C3%83%C2%A7:%C3%83%C2%AA@example.com/");
equal(url.username,
"%C3%83%C2%A7");
});
add_task(async
function test_bug1873976() {
let url = Services.io.newURI(
"file:.");
equal(url.spec,
"file:///");
});
add_task(async
function test_bug1890346() {
let url = Services.io.newURI(
"file:..?/..");
equal(url.spec,
"file:///?/..");
});
add_task(async
function test_bug1914141() {
equal(Services.io.isValidHostname(
"example.com"),
true);
equal(Services.io.isValidHostname(
"example.0"),
false);
equal(Services.io.isValidHostname(
"192.168.0.1"),
true);
equal(Services.io.isValidHostname(
"192.168.0"),
true);
equal(Services.io.isValidHostname(
"1.192.168.0.1"),
false);
equal(Services.io.isValidHostname(
"invalid.192.168.0.1"),
false);
equal(Services.io.isValidHostname(
"::1"),
true);
equal(Services.io.isValidHostname(
"abcd::zz::00"),
false);
equal(Services.io.isValidHostname(
"zzzz::1.2.3.4"),
false);
equal(Services.io.isValidHostname(
"::1.2.3.4"),
true);
});