Bug 1385883 - nsStandardURL - make sure we always check if the host is ascii r=jduell
authorValentin Gosu <valentin.gosu@gmail.com>
Tue, 01 Aug 2017 01:51:48 +0300
changeset 423261 70d8a128477916173272ffddfaa34538dfc54010
parent 423260 2142989aace8f27a874a74b836b510012de35006
child 423262 a9f00bf0aeff80ca03f30a20b0f235adb1cbd4c4
push id1517
push userjlorenzo@mozilla.com
push dateThu, 14 Sep 2017 16:50:54 +0000
treeherdermozilla-release@3b41fd564418 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjduell
bugs1385883
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1385883 - nsStandardURL - make sure we always check if the host is ascii r=jduell SetRef and several other methods call InvalidateCache, which in turn sets mCheckedIfHostA to false. That means that each time before trying to access mDisplayHost we need to make sure it is properly initalized. MozReview-Commit-ID: Agtsy6Lx7Nb
netwerk/base/nsStandardURL.cpp
netwerk/base/nsStandardURL.h
netwerk/test/unit/test_standardurl.js
--- a/netwerk/base/nsStandardURL.cpp
+++ b/netwerk/base/nsStandardURL.cpp
@@ -1406,29 +1406,63 @@ nsStandardURL::GetSpecIgnoringRef(nsACSt
     // URI without ref is 0 to one char before ref
     if (mRef.mLen < 0) {
         return GetSpec(result);
     }
 
     URLSegment noRef(0, mRef.mPos - 1);
     result = Segment(noRef);
 
-    if (!gPunycodeHost && mCheckedIfHostA && !mDisplayHost.IsEmpty()) {
+    CheckIfHostIsAscii();
+    MOZ_ASSERT(mCheckedIfHostA);
+    if (!gPunycodeHost && !mDisplayHost.IsEmpty()) {
         result.Replace(mHost.mPos, mHost.mLen, mDisplayHost);
     }
 
     CALL_RUST_GETTER_STR(result, GetSpecIgnoringRef, result);
     return NS_OK;
 }
 
+nsresult
+nsStandardURL::CheckIfHostIsAscii()
+{
+    nsresult rv;
+    if (mCheckedIfHostA) {
+        return NS_OK;
+    }
+
+    mCheckedIfHostA = true;
+
+    // If the hostname doesn't begin with `xn--` we are sure it is ASCII.
+    if (!StringBeginsWith(Host(), NS_LITERAL_CSTRING("xn--"))) {
+        return NS_OK;
+    }
+
+    if (!gIDN) {
+        return NS_ERROR_NOT_INITIALIZED;
+    }
+
+    bool isAscii;
+    rv = gIDN->ConvertToDisplayIDN(Host(), &isAscii, mDisplayHost);
+    if (NS_FAILED(rv)) {
+        mDisplayHost.Truncate();
+        mCheckedIfHostA = false;
+        return rv;
+    }
+
+    return NS_OK;
+}
+
 NS_IMETHODIMP
 nsStandardURL::GetDisplaySpec(nsACString &aUnicodeSpec)
 {
+    CheckIfHostIsAscii();
     aUnicodeSpec.Assign(mSpec);
-    if (mCheckedIfHostA && !mDisplayHost.IsEmpty()) {
+    MOZ_ASSERT(mCheckedIfHostA);
+    if (!mDisplayHost.IsEmpty()) {
         aUnicodeSpec.Replace(mHost.mPos, mHost.mLen, mDisplayHost);
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::GetDisplayHostPort(nsACString &aUnicodeHostPort)
@@ -1453,49 +1487,35 @@ nsStandardURL::GetDisplayHostPort(nsACSt
         aUnicodeHostPort += Substring(mSpec, pos, mPath.mPos - pos);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::GetDisplayHost(nsACString &aUnicodeHost)
 {
-    if (mCheckedIfHostA) {
-        if (mDisplayHost.IsEmpty()) {
-            return GetAsciiHost(aUnicodeHost);
-        } else {
-            aUnicodeHost = mDisplayHost;
-            return NS_OK;
-        }
-    }
-
-    if (!gIDN) {
-        return NS_ERROR_NOT_INITIALIZED;
+    CheckIfHostIsAscii();
+    MOZ_ASSERT(mCheckedIfHostA);
+    if (mDisplayHost.IsEmpty()) {
+        return GetAsciiHost(aUnicodeHost);
     }
 
-    nsresult rv = gIDN->ConvertACEtoUTF8(Host(), aUnicodeHost);
-    if (NS_FAILED(rv)) {
-        return rv;
-    }
-
-    mCheckedIfHostA = true;
-    if (aUnicodeHost != Host()) {
-        mDisplayHost = aUnicodeHost;
-    }
-
+    aUnicodeHost = mDisplayHost;
     return NS_OK;
 }
 
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
 nsStandardURL::GetPrePath(nsACString &result)
 {
     result = Prepath();
-    if (!gPunycodeHost && mCheckedIfHostA && !mDisplayHost.IsEmpty()) {
+    CheckIfHostIsAscii();
+    MOZ_ASSERT(mCheckedIfHostA);
+    if (!gPunycodeHost && !mDisplayHost.IsEmpty()) {
         result.Replace(mHost.mPos, mHost.mLen, mDisplayHost);
     }
     CALL_RUST_GETTER_STR(result, GetPrePath, result);
     return NS_OK;
 }
 
 // result is strictly US-ASCII
 NS_IMETHODIMP
--- a/netwerk/base/nsStandardURL.h
+++ b/netwerk/base/nsStandardURL.h
@@ -184,16 +184,17 @@ private:
 
     void     ReplacePortInSpec(int32_t aNewPort);
     void     Clear();
     void     InvalidateCache(bool invalidateCachedFile = true);
 
     bool     ValidIPv6orHostname(const char *host, uint32_t aLen);
     static bool     IsValidOfBase(unsigned char c, const uint32_t base);
     nsresult NormalizeIDN(const nsACString& host, nsCString& result);
+    nsresult CheckIfHostIsAscii();
     void     CoalescePath(netCoalesceFlags coalesceFlag, char *path);
 
     uint32_t AppendSegmentToBuf(char *, uint32_t, const char *,
                                 const URLSegment &input, URLSegment &output,
                                 const nsCString *esc=nullptr,
                                 bool useEsc = false, int32_t* diff = nullptr);
     uint32_t AppendToBuf(char *, uint32_t, const char *, uint32_t);
 
--- a/netwerk/test/unit/test_standardurl.js
+++ b/netwerk/test/unit/test_standardurl.js
@@ -515,16 +515,21 @@ add_test(function test_idna_host() {
   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.ref = ""; // SetRef calls InvalidateCache()
+  equal(url.spec, "http://user:password@ält.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");
+
   // We also check that the default behaviour changes once we filp the pref
   gPrefs.setBoolPref("network.standard-url.punycode-host", true);
 
   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");
@@ -534,10 +539,15 @@ add_test(function test_idna_host() {
   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.ref = ""; // 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");
+
   run_next_test();
 });