Bug 1433958 - Change code that sets nsIURI.host to use nsIURIMutator draft
authorValentin Gosu <valentin.gosu@gmail.com>
Mon, 26 Feb 2018 20:43:47 +0100
changeset 759897 f03ec78a8e79a6212fd73828d75d69aae8163beb
parent 759896 5fa03cdaac29c772964ee1a8aa2ae4550a7d7bed
child 759898 dcf13407679bd5676dc7a24b38209e5d114715bd
push id100504
push uservalentin.gosu@gmail.com
push dateMon, 26 Feb 2018 19:44:44 +0000
bugs1433958
milestone60.0a1
Bug 1433958 - Change code that sets nsIURI.host to use nsIURIMutator MozReview-Commit-ID: 7T5gCu8WOfa
caps/DomainPolicy.cpp
caps/nsScriptSecurityManager.cpp
docshell/base/nsDefaultURIFixup.cpp
docshell/base/nsDefaultURIFixup.h
dom/base/Link.cpp
dom/base/Location.cpp
dom/url/URLMainThread.cpp
extensions/cookie/nsPermissionManager.cpp
netwerk/test/unit/test_URIs.js
netwerk/test/unit/test_URIs2.js
netwerk/test/unit/test_bug261425.js
netwerk/test/unit/test_standardurl.js
--- a/caps/DomainPolicy.cpp
+++ b/caps/DomainPolicy.cpp
@@ -223,17 +223,19 @@ DomainSet::ContainsSuperDomain(nsIURI* a
         }
 
         // Chop off everything before the first dot, or break if there are no
         // dots left.
         int32_t index = domain.Find(".");
         if (index == kNotFound)
             break;
         domain.Assign(Substring(domain, index + 1));
-        rv = clone->SetHost(domain);
+        rv = NS_MutateURI(clone)
+               .SetHost(domain)
+               .Finalize(clone);
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
     // No match.
     return NS_OK;
 
 }
 
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -11,16 +11,17 @@
 #include "xpcpublic.h"
 #include "XPCWrapper.h"
 #include "nsIInputStreamChannel.h"
 #include "nsILoadContext.h"
 #include "nsIServiceManager.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIScriptContext.h"
 #include "nsIURL.h"
+#include "nsIURIMutator.h"
 #include "nsINestedURI.h"
 #include "nspr.h"
 #include "nsJSPrincipals.h"
 #include "mozilla/BasePrincipal.h"
 #include "ExpandedPrincipal.h"
 #include "SystemPrincipal.h"
 #include "NullPrincipal.h"
 #include "DomainPolicy.h"
@@ -528,20 +529,18 @@ DenyAccessIfURIHasFlags(nsIURI* aURI, ui
     }
 
     return NS_OK;
 }
 
 static bool
 EqualOrSubdomain(nsIURI* aProbeArg, nsIURI* aBase)
 {
-    // Make a clone of the incoming URI, because we're going to mutate it.
-    nsCOMPtr<nsIURI> probe;
-    nsresult rv = aProbeArg->Clone(getter_AddRefs(probe));
-    NS_ENSURE_SUCCESS(rv, false);
+    nsresult rv;
+    nsCOMPtr<nsIURI> probe = aProbeArg;
 
     nsCOMPtr<nsIEffectiveTLDService> tldService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
     NS_ENSURE_TRUE(tldService, false);
     while (true) {
         if (nsScriptSecurityManager::SecurityCompareURIs(probe, aBase)) {
             return true;
         }
 
@@ -549,17 +548,19 @@ EqualOrSubdomain(nsIURI* aProbeArg, nsIU
         rv = probe->GetHost(host);
         NS_ENSURE_SUCCESS(rv, false);
 
         rv = tldService->GetNextSubDomain(host, newHost);
         if (rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
             return false;
         }
         NS_ENSURE_SUCCESS(rv, false);
-        rv = probe->SetHost(newHost);
+        rv = NS_MutateURI(probe)
+               .SetHost(newHost)
+               .Finalize(probe);
         NS_ENSURE_SUCCESS(rv, false);
     }
 }
 
 NS_IMETHODIMP
 nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
                                                    nsIURI *aTargetURI,
                                                    uint32_t aFlags)
--- a/docshell/base/nsDefaultURIFixup.cpp
+++ b/docshell/base/nsDefaultURIFixup.cpp
@@ -507,17 +507,17 @@ nsDefaultURIFixup::TryKeywordFixupForURI
     keywordInfo->GetKeywordProviderName(aFixupInfo->mKeywordProviderName);
     keywordInfo->GetKeywordAsSent(aFixupInfo->mKeywordAsSent);
     keywordInfo->GetPreferredURI(getter_AddRefs(aFixupInfo->mPreferredURI));
   }
   return rv;
 }
 
 bool
-nsDefaultURIFixup::MakeAlternateURI(nsIURI* aURI)
+nsDefaultURIFixup::MakeAlternateURI(nsCOMPtr<nsIURI>& aURI)
 {
   if (!Preferences::GetRootBranch()) {
     return false;
   }
   if (!Preferences::GetBool("browser.fixup.alternate.enabled", true)) {
     return false;
   }
 
@@ -602,17 +602,20 @@ nsDefaultURIFixup::MakeAlternateURI(nsIU
     return false;
   }
 
   if (newHost.IsEmpty()) {
     return false;
   }
 
   // Assign the new host string over the old one
-  aURI->SetHost(newHost);
+  Unused << NS_MutateURI(aURI)
+              .SetHost(newHost)
+              .Finalize(aURI);
+
   return true;
 }
 
 nsresult
 nsDefaultURIFixup::FileURIFixup(const nsACString& aStringURI, nsIURI** aURI)
 {
   nsAutoCString uriSpecOut;
 
--- a/docshell/base/nsDefaultURIFixup.h
+++ b/docshell/base/nsDefaultURIFixup.h
@@ -32,17 +32,17 @@ private:
                             nsIURI** aURI);
   nsresult KeywordURIFixup(const nsACString& aStringURI,
                            nsDefaultURIFixupInfo* aFixupInfo,
                            nsIInputStream** aPostData);
   nsresult TryKeywordFixupForURIInfo(const nsACString& aStringURI,
                                      nsDefaultURIFixupInfo* aFixupInfo,
                                      nsIInputStream** aPostData);
   bool PossiblyHostPortUrl(const nsACString& aUrl);
-  bool MakeAlternateURI(nsIURI* aURI);
+  bool MakeAlternateURI(nsCOMPtr<nsIURI>& aURI);
   bool IsDomainWhitelisted(const nsACString& aAsciiHost,
                            const uint32_t aDotLoc);
 };
 
 class nsDefaultURIFixupInfo : public nsIURIFixupInfo
 {
 public:
   NS_DECL_ISUPPORTS
--- a/dom/base/Link.cpp
+++ b/dom/base/Link.cpp
@@ -496,23 +496,28 @@ Link::SetHost(const nsAString &aHost)
     return;
   }
   SetHrefAttribute(uri);
 }
 
 void
 Link::SetHostname(const nsAString &aHostname)
 {
-  nsCOMPtr<nsIURI> uri(GetURIToMutate());
+  nsCOMPtr<nsIURI> uri(GetURI());
   if (!uri) {
     // Ignore failures to be compatible with NS4.
     return;
   }
 
-  (void)uri->SetHost(NS_ConvertUTF16toUTF8(aHostname));
+  nsresult rv = NS_MutateURI(uri)
+                  .SetHost(NS_ConvertUTF16toUTF8(aHostname))
+                  .Finalize(uri);
+  if (NS_FAILED(rv)) {
+    return;
+  }
   SetHrefAttribute(uri);
 }
 
 void
 Link::SetPathname(const nsAString &aPathname)
 {
   nsCOMPtr<nsIURI> uri(GetURI());
   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
--- a/dom/base/Location.cpp
+++ b/dom/base/Location.cpp
@@ -402,22 +402,24 @@ Location::SetHostname(const nsAString& a
                       ErrorResult& aRv)
 {
   if (!CallerSubsumes(&aSubjectPrincipal)) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return;
   }
 
   nsCOMPtr<nsIURI> uri;
-  aRv = GetWritableURI(getter_AddRefs(uri));
+  aRv = GetURI(getter_AddRefs(uri));
   if (NS_WARN_IF(aRv.Failed()) || !uri) {
     return;
   }
 
-  aRv = uri->SetHost(NS_ConvertUTF16toUTF8(aHostname));
+  aRv = NS_MutateURI(uri)
+          .SetHost(NS_ConvertUTF16toUTF8(aHostname))
+          .Finalize(uri);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   aRv = SetURI(uri);
 }
 
 nsresult
--- a/dom/url/URLMainThread.cpp
+++ b/dom/url/URLMainThread.cpp
@@ -348,17 +348,19 @@ URLMainThread::GetHostname(nsAString& aH
   nsContentUtils::GetHostOrIPv6WithBrackets(mURI, aHostname);
 }
 
 void
 URLMainThread::SetHostname(const nsAString& aHostname, ErrorResult& aRv)
 {
   // nsStandardURL returns NS_ERROR_UNEXPECTED for an empty hostname
   // The return code is silently ignored
-  mURI->SetHost(NS_ConvertUTF16toUTF8(aHostname));
+  mozilla::Unused << NS_MutateURI(mURI)
+                       .SetHost(NS_ConvertUTF16toUTF8(aHostname))
+                       .Finalize(mURI);
 }
 
 void
 URLMainThread::GetPort(nsAString& aPort, ErrorResult& aRv) const
 {
   aPort.Truncate();
 
   int32_t port;
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -23,16 +23,17 @@
 #include "nsReadableUtils.h"
 #include "nsILineInputStream.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsDirectoryServiceDefs.h"
 #include "mozilla/storage.h"
 #include "mozilla/Attributes.h"
 #include "nsXULAppAPI.h"
 #include "nsIPrincipal.h"
+#include "nsIURIMutator.h"
 #include "nsContentUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIEffectiveTLDService.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDocument.h"
 #include "mozilla/net/NeckoMessageUtils.h"
 #include "mozilla/Preferences.h"
 #include "nsReadLine.h"
@@ -291,26 +292,23 @@ GetNextSubDomainURI(nsIURI* aURI)
   }
 
   nsCString domain = GetNextSubDomainForHost(host);
   if (domain.IsEmpty()) {
     return nullptr;
   }
 
   nsCOMPtr<nsIURI> uri;
-  rv = aURI->Clone(getter_AddRefs(uri));
+  rv = NS_MutateURI(aURI)
+         .SetHost(domain)
+         .Finalize(uri);
   if (NS_FAILED(rv) || !uri) {
     return nullptr;
   }
 
-  rv = uri->SetHost(domain);
-  if (NS_FAILED(rv)) {
-    return nullptr;
-  }
-
   return uri.forget();
 }
 
 // This function produces a nsIPrincipal which is identical to the current
 // nsIPrincipal, except that it has one less subdomain segment. It returns
 // `nullptr` if there are no more segments to remove.
 already_AddRefed<nsIPrincipal>
 GetNextSubDomainPrincipal(nsIPrincipal* aPrincipal)
@@ -659,17 +657,19 @@ UpgradeHostToOriginAndInsert(const nsACS
       rv = child->GetUri(uriSpec);
       if (NS_WARN_IF(NS_FAILED(rv))) continue;
 
       nsCOMPtr<nsIURI> uri;
       rv = NS_NewURI(getter_AddRefs(uri), uriSpec);
       if (NS_WARN_IF(NS_FAILED(rv))) continue;
 
       // Use the provided host - this URI may be for a subdomain, rather than the host we care about.
-      rv = uri->SetHost(aHost);
+      rv = NS_MutateURI(uri)
+             .SetHost(aHost)
+             .Finalize(uri);
       if (NS_WARN_IF(NS_FAILED(rv))) continue;
 
       // We now have a URI which we can make a nsIPrincipal out of
       nsCOMPtr<nsIPrincipal> principal;
       rv = GetPrincipal(uri, aAppId, aIsInIsolatedMozBrowserElement, getter_AddRefs(principal));
       if (NS_WARN_IF(NS_FAILED(rv))) continue;
 
       nsAutoCString origin;
--- a/netwerk/test/unit/test_URIs.js
+++ b/netwerk/test/unit/test_URIs.js
@@ -521,18 +521,17 @@ function do_test_mutate_ref(aTest, aSuff
 
 // Tests that normally-mutable properties can't be modified on
 // special URIs that are known to be immutable.
 function do_test_immutable(aTest) {
   Assert.ok(aTest.immutable);
 
   var URI = NetUtil.newURI(aTest.spec);
   // All the non-readonly attributes on nsIURI.idl:
-  var propertiesToCheck = ["spec", "scheme",
-                           "host"];
+  var propertiesToCheck = ["spec", "scheme"];
 
   propertiesToCheck.forEach(function(aProperty) {
     var threw = false;
     try {
       URI[aProperty] = "anothervalue";
     } catch(e) {
       threw = true;
     }
--- a/netwerk/test/unit/test_URIs2.js
+++ b/netwerk/test/unit/test_URIs2.js
@@ -622,18 +622,17 @@ function do_test_mutate_ref(aTest, aSuff
 
 // Tests that normally-mutable properties can't be modified on
 // special URIs that are known to be immutable.
 function do_test_immutable(aTest) {
   Assert.ok(aTest.immutable);
 
   var URI = NetUtil.newURI(aTest.spec);
   // All the non-readonly attributes on nsIURI.idl:
-  var propertiesToCheck = ["scheme",
-                           "host"];
+  var propertiesToCheck = ["scheme"];
 
   propertiesToCheck.forEach(function(aProperty) {
     var threw = false;
     try {
       URI[aProperty] = "anothervalue";
     } catch(e) {
       threw = true;
     }
--- a/netwerk/test/unit/test_bug261425.js
+++ b/netwerk/test/unit/test_bug261425.js
@@ -11,16 +11,16 @@ function run_test() {
   catch (e) {
     success = e.result == Cr.NS_ERROR_MALFORMED_URI;
   }
   if (!success)
     do_throw("We didn't throw NS_ERROR_MALFORMED_URI when a space was passed in the hostname!");
 
   success = false;
   try {
-    newURI.host = " foo.com";
+    newURI = newURI.mutate().setHost(" foo.com").finalize();
   }
   catch (e) {
     success = e.result == Cr.NS_ERROR_MALFORMED_URI;
   }
   if (!success)
     do_throw("We didn't throw NS_ERROR_MALFORMED_URI when a space was passed in the hostname!");
 }
--- a/netwerk/test/unit/test_standardurl.js
+++ b/netwerk/test/unit/test_standardurl.js
@@ -164,17 +164,17 @@ add_test(function test_setRef()
   }
   run_next_test();
 });
 
 // Bug 960014 - Make nsStandardURL::SetHost less magical around IPv6
 add_test(function test_ipv6()
 {
   var url = stringToURL("http://example.com");
-  url.host = "[2001::1]";
+  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");
 
@@ -185,24 +185,24 @@ add_test(function test_ipv6()
   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.host = "2001::1"; }, "missing brackets");
-  Assert.throws(() => { url.host = "[2001::1]:20"; }, "url.host with port");
-  Assert.throws(() => { url.host = "[2001::1"; }, "missing last bracket");
-  Assert.throws(() => { url.host = "2001::1]"; }, "missing first bracket");
-  Assert.throws(() => { url.host = "2001[::1]"; }, "bad bracket position");
-  Assert.throws(() => { url.host = "[]"; }, "empty IPv6 address");
-  Assert.throws(() => { url.host = "[hello]"; }, "bad IPv6 address");
-  Assert.throws(() => { url.host = "[192.168.1.1]"; }, "bad IPv6 address");
+  Assert.throws(() => { url = url.mutate().setHost("2001::1").finalize(); }, "missing brackets");
+  Assert.throws(() => { url = url.mutate().setHost("[2001::1]:20").finalize(); }, "url.host with port");
+  Assert.throws(() => { url = url.mutate().setHost("[2001::1").finalize(); }, "missing last bracket");
+  Assert.throws(() => { url = url.mutate().setHost("2001::1]").finalize(); }, "missing first bracket");
+  Assert.throws(() => { url = url.mutate().setHost("2001[::1]").finalize(); }, "bad bracket position");
+  Assert.throws(() => { url = url.mutate().setHost("[]").finalize(); }, "empty IPv6 address");
+  Assert.throws(() => { url = url.mutate().setHost("[hello]").finalize(); }, "bad IPv6 address");
+  Assert.throws(() => { url = url.mutate().setHost("[192.168.1.1]").finalize(); }, "bad IPv6 address");
   Assert.throws(() => { url = url.mutate().setHostPort("2001::1").finalize(); }, "missing brackets");
   Assert.throws(() => { url = url.mutate().setHostPort("[2001::1]30").finalize(); }, "missing : after IP");
   Assert.throws(() => { url = url.mutate().setHostPort("[2001:1]").finalize(); }, "bad IPv6 address");
   Assert.throws(() => { url = url.mutate().setHostPort("[2001:1]10").finalize(); }, "bad IPv6 address");
   Assert.throws(() => { url = url.mutate().setHostPort("[2001:1]10:20").finalize(); }, "bad IPv6 address");
   Assert.throws(() => { url = url.mutate().setHostPort("[2001:1]:10:20").finalize(); }, "bad IPv6 address");
   Assert.throws(() => { url = url.mutate().setHostPort("[2001:1").finalize(); }, "bad IPv6 address");
   Assert.throws(() => { url = url.mutate().setHostPort("2001]:1").finalize(); }, "bad IPv6 address");
@@ -214,17 +214,17 @@ add_test(function test_ipv6_fail()
 });
 
 add_test(function test_clearedSpec()
 {
   var url = stringToURL("http://example.com/path");
   Assert.throws(() => { url = url.mutate().setSpec("http: example").finalize(); }, "set bad spec");
   Assert.throws(() => { url = url.mutate().setSpec("").finalize(); }, "set empty spec");
   Assert.equal(url.spec, "http://example.com/path");
-  url.host = "allizom.org";
+  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()
 {
@@ -296,30 +296,30 @@ add_test(function test_percentDecoding()
 add_test(function test_hugeStringThrows()
 {
   let prefs = Cc["@mozilla.org/preferences-service;1"]
                 .getService(Ci.nsIPrefService);
   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 properties = ["scheme",
-                    "host"];
+  let properties = ["scheme"];
   for (let prop of properties) {
     Assert.throws(() => url[prop] = hugeString,
                   /NS_ERROR_MALFORMED_URI/,
                   `Passing a huge string to "${prop}" should throw`);
   }
 
   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: "setFileName", qi: Ci.nsIURLMutator },
     { method: "setFileExtension", qi: Ci.nsIURLMutator },
     { method: "setFileBaseName", qi: Ci.nsIURLMutator },
   ];
@@ -469,39 +469,39 @@ add_test(function test_ipv4Normalize()
     ];
   var spec;
   for (spec of nonIPv4s) {
     url = stringToURL(spec);
     Assert.equal(url.spec, spec);
   }
 
   var url = stringToURL("resource://path/to/resource/");
-  url.host = "123";
+  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++) {
-    Assert.throws(() => { url.host = "a" + String.fromCharCode(i) + "b"; }, "Trying to set hostname containing char code: " + i);
+    Assert.throws(() => { url = url.mutate().setHost("a" + String.fromCharCode(i) + "b").finalize(); }, "Trying to set hostname containing char code: " + i);
   }
   for (let c of "@[]*<>|:\"") {
-    Assert.throws(() => { url.host = "a" + c; }, "Trying to set hostname containing char: " + c);
+    Assert.throws(() => { url = url.mutate().setHost("a" + c).finalize(); }, "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.host = "[::192.9.5.5]";
+  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/");