Bug 1724233 - Make sure to run ConvertUTF8toACE before ConvertToDisplayIDN r=necko-reviewers,dragana
Differential Revision: https://phabricator.services.mozilla.com/D122097
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=448166
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Test for Bug 448166</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
@@ -23,8 +24,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=448166
|
||||
/** Test for Bug 448166 **/
|
||||
isnot($("test").href, "http://www.mozilla.org/",
|
||||
"Should notice unpaired surrogate");
|
||||
is($("test").href, "http://www.xn--mozilla-2e14b.org/",
|
||||
"Should replace unpaired surrogate with replacement char");
|
||||
is($("test").href, "http://www.moz<EFBFBD>illa.org",
|
||||
"URL parser fails. Href returns original input string");
|
||||
|
||||
SimpleTest.doesThrow(() => { new URL($("test").href);}, "URL parser rejects input");
|
||||
|
||||
is($("control").href, "http://www.mozilla.org/",
|
||||
"Just making sure .href works");
|
||||
|
||||
|
||||
@@ -599,43 +599,51 @@ nsresult nsStandardURL::NormalizeIPv4(const nsACString& host,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsStandardURL::NormalizeIDN(const nsACString& host,
|
||||
nsCString& result) {
|
||||
// If host is ACE, then convert to UTF-8. Else, if host is already UTF-8,
|
||||
// then make sure it is normalized per IDN.
|
||||
|
||||
// this function returns true if normalization succeeds.
|
||||
|
||||
nsresult nsStandardURL::NormalizeIDN(const nsCString& host, nsCString& result) {
|
||||
result.Truncate();
|
||||
mDisplayHost.Truncate();
|
||||
nsresult rv;
|
||||
|
||||
if (!gIDN) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
bool isAscii;
|
||||
nsAutoCString normalized;
|
||||
rv = gIDN->ConvertToDisplayIDN(host, &isAscii, normalized);
|
||||
// If the input is ASCII, and not ACE encoded, then there's no processing
|
||||
// needed. This is needed because we want to allow ascii labels longer than
|
||||
// 64 characters for some schemes.
|
||||
bool isACE = false;
|
||||
if (IsAscii(host) && NS_SUCCEEDED(gIDN->IsACE(host, &isACE)) && !isACE) {
|
||||
mCheckedIfHostA = true;
|
||||
result = host;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Even if it's already ACE, we must still call ConvertUTF8toACE in order
|
||||
// for the input normalization to take place.
|
||||
rv = gIDN->ConvertUTF8toACE(host, result);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// The result is ASCII. No need to convert to ACE.
|
||||
if (isAscii) {
|
||||
result = normalized;
|
||||
// If the ASCII representation doesn't contain the xn-- token then we don't
|
||||
// need to call ConvertToDisplayIDN as that would not change anything.
|
||||
if (!StringBeginsWith(result, "xn--"_ns) &&
|
||||
result.Find(".xn--"_ns) == kNotFound) {
|
||||
mCheckedIfHostA = true;
|
||||
mDisplayHost.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
rv = gIDN->ConvertUTF8toACE(normalized, result);
|
||||
bool isAscii = true;
|
||||
nsAutoCString displayHost;
|
||||
rv = gIDN->ConvertToDisplayIDN(result, &isAscii, displayHost);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mCheckedIfHostA = true;
|
||||
mDisplayHost = normalized;
|
||||
|
||||
if (!isAscii) {
|
||||
mDisplayHost = displayHost;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -184,7 +184,7 @@ class nsStandardURL : public nsIFileURL,
|
||||
|
||||
bool ValidIPv6orHostname(const char* host, uint32_t length);
|
||||
static bool IsValidOfBase(unsigned char c, const uint32_t base);
|
||||
nsresult NormalizeIDN(const nsACString& host, nsCString& result);
|
||||
nsresult NormalizeIDN(const nsCString& host, nsCString& result);
|
||||
nsresult CheckIfHostIsAscii();
|
||||
void CoalescePath(netCoalesceFlags coalesceFlag, char* path);
|
||||
|
||||
|
||||
@@ -212,7 +212,13 @@ nsresult nsIDNService::IDNA2008StringPrep(const nsAString& input,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (info.errors != 0) {
|
||||
uint32_t ignoredErrors = 0;
|
||||
if (flag == eStringPrepForDNS) {
|
||||
ignoredErrors = UIDNA_ERROR_LEADING_HYPHEN | UIDNA_ERROR_TRAILING_HYPHEN |
|
||||
UIDNA_ERROR_HYPHEN_3_4;
|
||||
}
|
||||
|
||||
if ((info.errors & ~ignoredErrors) != 0) {
|
||||
if (flag == eStringPrepForDNS) {
|
||||
output.Truncate();
|
||||
}
|
||||
@@ -325,16 +331,25 @@ nsresult nsIDNService::ACEtoUTF8(const nsACString& input, nsACString& _retval,
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIDNService::IsACE(const nsACString& input, bool* _retval) {
|
||||
const char* data = input.BeginReading();
|
||||
uint32_t dataLen = input.Length();
|
||||
|
||||
// look for the ACE prefix in the input string. it may occur
|
||||
// at the beginning of any segment in the domain name. for
|
||||
// example: "www.xn--ENCODED.com"
|
||||
|
||||
const char* p = PL_strncasestr(data, kACEPrefix, dataLen);
|
||||
if (!IsAscii(input)) {
|
||||
*_retval = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*_retval = p && (p == data || *(p - 1) == '.');
|
||||
auto stringContains = [](const nsACString& haystack,
|
||||
const nsACString& needle) {
|
||||
return std::search(haystack.BeginReading(), haystack.EndReading(),
|
||||
needle.BeginReading(),
|
||||
needle.EndReading()) != haystack.EndReading();
|
||||
};
|
||||
|
||||
*_retval = StringBeginsWith(input, "xn--"_ns) ||
|
||||
(!input.IsEmpty() && input[0] != '.' &&
|
||||
stringContains(input, ".xn--"_ns));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ function run_test() {
|
||||
.setSpec("http://%80.com")
|
||||
.finalize();
|
||||
},
|
||||
/NS_ERROR_UNEXPECTED/,
|
||||
/NS_ERROR_MALFORMED_URI/,
|
||||
"illegal UTF character"
|
||||
);
|
||||
|
||||
|
||||
@@ -1164,7 +1164,7 @@ add_test(
|
||||
() => {
|
||||
stringToURL("https://b%9a/");
|
||||
},
|
||||
/NS_ERROR_UNEXPECTED/,
|
||||
/NS_ERROR_MALFORMED_URI/,
|
||||
"bad URI"
|
||||
);
|
||||
|
||||
|
||||
@@ -146,12 +146,6 @@
|
||||
[Parsing: <file:..> against <http://www.example.com/test>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <http://zyx.com> against <http://other.com/>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <http://%ef%b7%90zyx.com> against <http://other.com/>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <http://192.168.0.257> against <http://other.com/>]
|
||||
expected: FAIL
|
||||
|
||||
@@ -281,12 +275,6 @@
|
||||
[Parsing: <file://[example\]/> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <https://<2F>> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <https://%EF%BF%BD> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <sc://\x00/> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
||||
@@ -498,12 +486,6 @@
|
||||
[Parsing: <x> against <sc://ñ>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <http://zyx.com> against <http://other.com/>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <https://<2F>> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <data:test# »> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
@@ -143,12 +143,6 @@
|
||||
[Parsing: <http://www.@pple.com> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <http://zyx.com> against <http://other.com/>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <http://%ef%b7%90zyx.com> against <http://other.com/>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <http://192.168.0.257> against <http://other.com/>]
|
||||
expected: FAIL
|
||||
|
||||
@@ -281,12 +275,6 @@
|
||||
[Parsing: <file://[example\]/> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <https://<2F>> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <https://%EF%BF%BD> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <sc://\x00/> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
||||
@@ -498,12 +486,6 @@
|
||||
[Parsing: <x> against <sc://ñ>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <http://zyx.com> against <http://other.com/>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <https://<2F>> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <data:test# »> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
||||
@@ -531,12 +513,6 @@
|
||||
[Parsing: <x> against <sc://ñ>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <http://zyx.com> against <http://other.com/>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <https://<2F>> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <data:test# »> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
@@ -48,27 +48,9 @@
|
||||
[Location's href: http://@:www.example.com should throw]
|
||||
expected: FAIL
|
||||
|
||||
[URL's href: https://<2F> should throw]
|
||||
expected: FAIL
|
||||
|
||||
[XHR: https://<2F> should throw]
|
||||
expected: FAIL
|
||||
|
||||
[sendBeacon(): https://<2F> should throw]
|
||||
expected: FAIL
|
||||
|
||||
[Location's href: https://<2F> should throw]
|
||||
expected: FAIL
|
||||
|
||||
[URL's href: https://%EF%BF%BD should throw]
|
||||
expected: FAIL
|
||||
|
||||
[XHR: https://%EF%BF%BD should throw]
|
||||
expected: FAIL
|
||||
|
||||
[sendBeacon(): https://%EF%BF%BD should throw]
|
||||
expected: FAIL
|
||||
|
||||
[Location's href: https://%EF%BF%BD should throw]
|
||||
expected: FAIL
|
||||
|
||||
@@ -159,27 +141,15 @@
|
||||
[Location's href: sc://\]/ should throw]
|
||||
expected: FAIL
|
||||
|
||||
[XHR: ftp://example.com%80/ should throw]
|
||||
expected: FAIL
|
||||
|
||||
[Location's href: ftp://example.com%80/ should throw]
|
||||
expected: FAIL
|
||||
|
||||
[XHR: ftp://example.com%A0/ should throw]
|
||||
expected: FAIL
|
||||
|
||||
[Location's href: ftp://example.com%A0/ should throw]
|
||||
expected: FAIL
|
||||
|
||||
[XHR: https://example.com%80/ should throw]
|
||||
expected: FAIL
|
||||
|
||||
[Location's href: https://example.com%80/ should throw]
|
||||
expected: FAIL
|
||||
|
||||
[XHR: https://example.com%A0/ should throw]
|
||||
expected: FAIL
|
||||
|
||||
[Location's href: https://example.com%A0/ should throw]
|
||||
expected: FAIL
|
||||
|
||||
@@ -231,12 +201,6 @@
|
||||
[window.open(): file://[example\]/ should throw]
|
||||
expected: FAIL
|
||||
|
||||
[window.open(): https://<2F> should throw]
|
||||
expected: FAIL
|
||||
|
||||
[window.open(): https://%EF%BF%BD should throw]
|
||||
expected: FAIL
|
||||
|
||||
[window.open(): sc://\x00/ should throw]
|
||||
expected: FAIL
|
||||
|
||||
@@ -312,12 +276,6 @@
|
||||
[URL's constructor's base argument: file://[example\]/ should throw]
|
||||
expected: FAIL
|
||||
|
||||
[URL's constructor's base argument: https://<2F> should throw]
|
||||
expected: FAIL
|
||||
|
||||
[URL's constructor's base argument: https://%EF%BF%BD should throw]
|
||||
expected: FAIL
|
||||
|
||||
[URL's constructor's base argument: sc://\x00/ should throw]
|
||||
expected: FAIL
|
||||
|
||||
@@ -354,42 +312,12 @@
|
||||
[URL's constructor's base argument: non-special://[:80/ should throw]
|
||||
expected: FAIL
|
||||
|
||||
[sendBeacon(): https://<2F> should throw]
|
||||
expected: FAIL
|
||||
|
||||
[window.open(): https://<2F> should throw]
|
||||
expected: FAIL
|
||||
|
||||
[Location's href: https://<2F> should throw]
|
||||
expected: FAIL
|
||||
|
||||
[XHR: https://<2F> should throw]
|
||||
expected: FAIL
|
||||
|
||||
[URL's constructor's base argument: https://<2F> should throw]
|
||||
expected: FAIL
|
||||
|
||||
[URL's href: https://<2F> should throw]
|
||||
expected: FAIL
|
||||
|
||||
[sendBeacon(): https://<2F> should throw]
|
||||
expected: FAIL
|
||||
|
||||
[window.open(): https://<2F> should throw]
|
||||
expected: FAIL
|
||||
|
||||
[Location's href: https://<2F> should throw]
|
||||
expected: FAIL
|
||||
|
||||
[XHR: https://<2F> should throw]
|
||||
expected: FAIL
|
||||
|
||||
[URL's constructor's base argument: https://<2F> should throw]
|
||||
expected: FAIL
|
||||
|
||||
[URL's href: https://<2F> should throw]
|
||||
expected: FAIL
|
||||
|
||||
[URL's constructor's base argument: file://xn--/p should throw]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
@@ -80,33 +80,6 @@
|
||||
[xn--a.β (using <area>.hostname)]
|
||||
expected: FAIL
|
||||
|
||||
[.example (using URL)]
|
||||
expected: FAIL
|
||||
|
||||
[.example (using URL.host)]
|
||||
expected: FAIL
|
||||
|
||||
[.example (using URL.hostname)]
|
||||
expected: FAIL
|
||||
|
||||
[.example (using <a>)]
|
||||
expected: FAIL
|
||||
|
||||
[.example (using <a>.host)]
|
||||
expected: FAIL
|
||||
|
||||
[.example (using <a>.hostname)]
|
||||
expected: FAIL
|
||||
|
||||
[.example (using <area>)]
|
||||
expected: FAIL
|
||||
|
||||
[.example (using <area>.host)]
|
||||
expected: FAIL
|
||||
|
||||
[.example (using <area>.hostname)]
|
||||
expected: FAIL
|
||||
|
||||
[xn--1ug.example (using URL)]
|
||||
expected: FAIL
|
||||
|
||||
@@ -134,33 +107,6 @@
|
||||
[xn--1ug.example (using <area>.hostname)]
|
||||
expected: FAIL
|
||||
|
||||
[يa (using URL)]
|
||||
expected: FAIL
|
||||
|
||||
[يa (using URL.host)]
|
||||
expected: FAIL
|
||||
|
||||
[يa (using URL.hostname)]
|
||||
expected: FAIL
|
||||
|
||||
[يa (using <a>)]
|
||||
expected: FAIL
|
||||
|
||||
[يa (using <a>.host)]
|
||||
expected: FAIL
|
||||
|
||||
[يa (using <a>.hostname)]
|
||||
expected: FAIL
|
||||
|
||||
[يa (using <area>)]
|
||||
expected: FAIL
|
||||
|
||||
[يa (using <area>.host)]
|
||||
expected: FAIL
|
||||
|
||||
[يa (using <area>.hostname)]
|
||||
expected: FAIL
|
||||
|
||||
[xn--a-yoc (using URL)]
|
||||
expected: FAIL
|
||||
|
||||
@@ -188,33 +134,6 @@
|
||||
[xn--a-yoc (using <area>.hostname)]
|
||||
expected: FAIL
|
||||
|
||||
[<5B>.com (using URL)]
|
||||
expected: FAIL
|
||||
|
||||
[<5B>.com (using URL.host)]
|
||||
expected: FAIL
|
||||
|
||||
[<5B>.com (using URL.hostname)]
|
||||
expected: FAIL
|
||||
|
||||
[<5B>.com (using <a>)]
|
||||
expected: FAIL
|
||||
|
||||
[<5B>.com (using <a>.host)]
|
||||
expected: FAIL
|
||||
|
||||
[<5B>.com (using <a>.hostname)]
|
||||
expected: FAIL
|
||||
|
||||
[<5B>.com (using <area>)]
|
||||
expected: FAIL
|
||||
|
||||
[<5B>.com (using <area>.host)]
|
||||
expected: FAIL
|
||||
|
||||
[<5B>.com (using <area>.hostname)]
|
||||
expected: FAIL
|
||||
|
||||
[xn--zn7c.com (using URL)]
|
||||
expected: FAIL
|
||||
|
||||
@@ -349,4 +268,3 @@
|
||||
|
||||
[xn-- (using URL.host)]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
@@ -80,18 +80,6 @@
|
||||
[Parsing: <file:..> against <http://www.example.com/test>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <http://zyx.com> against <http://other.com/>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <http://%ef%b7%90zyx.com> against <http://other.com/>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <https://<2F>> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <https://%EF%BF%BD> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <sc://faß.ExAmPlE/> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
||||
@@ -688,18 +676,6 @@
|
||||
[Parsing: <file:..> against <http://www.example.com/test>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <http://zyx.com> against <http://other.com/>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <http://%ef%b7%90zyx.com> against <http://other.com/>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <https://<2F>> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <https://%EF%BF%BD> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <sc://faß.ExAmPlE/> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
Reference in New Issue
Block a user