Bug 1433958 - Change code that sets nsIURI.scheme to use nsIURIMutator draft
authorValentin Gosu <valentin.gosu@gmail.com>
Mon, 26 Feb 2018 20:43:47 +0100
changeset 759899 170997f1e75e722b902649187982c3b97cead11e
parent 759898 dcf13407679bd5676dc7a24b38209e5d114715bd
child 760073 da145467cfa5eaabab65b65c6d3071f880e32acf
child 760183 78b27ffb25e2f8c1515e393caebd82cc0f22c0c2
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.scheme to use nsIURIMutator MozReview-Commit-ID: GgyIkZSG2y3
browser/base/content/browser-feeds.js
dom/base/Link.cpp
dom/base/Location.cpp
dom/url/URLMainThread.cpp
dom/url/URLWorker.cpp
netwerk/protocol/websocket/WebSocketChannel.cpp
netwerk/test/unit/test_URIs.js
netwerk/test/unit/test_URIs2.js
netwerk/test/unit/test_standardurl.js
security/manager/pki/resources/content/exceptionDialog.js
toolkit/modules/NewTabUtils.jsm
--- a/browser/base/content/browser-feeds.js
+++ b/browser/base/content/browser-feeds.js
@@ -378,17 +378,19 @@ var FeedHandler = {
     // URLs than just feeds, send feed: URLs in the following format:
     //
     // http urls: replace scheme with feed, e.g.
     // http://foo.com/index.rdf -> feed://foo.com/index.rdf
     // other urls: prepend feed: scheme, e.g.
     // https://foo.com/index.rdf -> feed:https://foo.com/index.rdf
     let feedURI = NetUtil.newURI(aSpec);
     if (feedURI.schemeIs("http")) {
-      feedURI.scheme = "feed";
+      feedURI = feedURI.mutate()
+                       .setScheme("feed")
+                       .finalize();
       aSpec = feedURI.spec;
     } else {
       aSpec = "feed:" + aSpec;
     }
 
     // Retrieving the shell service might fail on some systems, most
     // notably systems where GNOME is not installed.
     try {
--- a/dom/base/Link.cpp
+++ b/dom/base/Link.cpp
@@ -425,28 +425,33 @@ Link::GetURI() const
   mCachedURI = element->GetHrefURI();
 
   return mCachedURI;
 }
 
 void
 Link::SetProtocol(const nsAString &aProtocol)
 {
-  nsCOMPtr<nsIURI> uri(GetURIToMutate());
+  nsCOMPtr<nsIURI> uri(GetURI());
   if (!uri) {
     // Ignore failures to be compatible with NS4.
     return;
   }
 
   nsAString::const_iterator start, end;
   aProtocol.BeginReading(start);
   aProtocol.EndReading(end);
   nsAString::const_iterator iter(start);
   (void)FindCharInReadable(':', iter, end);
-  (void)uri->SetScheme(NS_ConvertUTF16toUTF8(Substring(start, iter)));
+  nsresult rv = NS_MutateURI(uri)
+                  .SetScheme(NS_ConvertUTF16toUTF8(Substring(start, iter)))
+                  .Finalize(uri);
+  if (NS_FAILED(rv)) {
+    return;
+  }
 
   SetHrefAttribute(uri);
 }
 
 void
 Link::SetPassword(const nsAString &aPassword)
 {
   nsCOMPtr<nsIURI> uri(GetURI());
--- a/dom/base/Location.cpp
+++ b/dom/base/Location.cpp
@@ -721,28 +721,30 @@ Location::SetProtocol(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;
   }
 
   nsAString::const_iterator start, end;
   aProtocol.BeginReading(start);
   aProtocol.EndReading(end);
   nsAString::const_iterator iter(start);
   Unused << FindCharInReadable(':', iter, end);
 
-  nsresult rv = uri->SetScheme(NS_ConvertUTF16toUTF8(Substring(start, iter)));
+  nsresult rv = NS_MutateURI(uri)
+                  .SetScheme(NS_ConvertUTF16toUTF8(Substring(start, iter)))
+                  .Finalize(uri);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     // Oh, I wish nsStandardURL returned NS_ERROR_MALFORMED_URI for _all_ the
     // malformed cases, not just some of them!
     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
     return;
   }
 
   nsAutoCString newSpec;
--- a/dom/url/URLMainThread.cpp
+++ b/dom/url/URLMainThread.cpp
@@ -245,22 +245,19 @@ URLMainThread::SetProtocol(const nsAStri
   nsAString::const_iterator iter(start);
 
   FindCharInReadable(':', iter, end);
 
   // Changing the protocol of a URL, changes the "nature" of the URI
   // implementation. In order to do this properly, we have to serialize the
   // existing URL and reparse it in a new object.
   nsCOMPtr<nsIURI> clone;
-  nsresult rv = mURI->Clone(getter_AddRefs(clone));
-  if (NS_WARN_IF(NS_FAILED(rv)) || !clone) {
-    return;
-  }
-
-  rv = clone->SetScheme(NS_ConvertUTF16toUTF8(Substring(start, iter)));
+  nsresult rv = NS_MutateURI(mURI)
+                  .SetScheme(NS_ConvertUTF16toUTF8(Substring(start, iter)))
+                  .Finalize(clone);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
   nsAutoCString href;
   rv = clone->GetSpec(href);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
--- a/dom/url/URLWorker.cpp
+++ b/dom/url/URLWorker.cpp
@@ -816,17 +816,19 @@ URLWorker::SetProtocol(const nsAString& 
 
   FindCharInReadable(':', iter, end);
   NS_ConvertUTF16toUTF8 scheme(Substring(start, iter));
 
   // If we are using nsStandardURL on the owning thread, we can continue only if
   // the scheme is http or https.
   if (mStdURL &&
       (scheme.EqualsLiteral("http") || scheme.EqualsLiteral("https"))) {
-    mStdURL->SetScheme(scheme);
+    Unused << NS_MutateURI(mStdURL)
+                .SetScheme(scheme)
+                .Finalize(mStdURL);
     return;
   }
 
   // If we are using mStandardURL but the new scheme is not http nor https, we
   // have to migrate to the URL proxy.
   if (mStdURL) {
     nsAutoCString href;
     nsresult rv = mStdURL->GetSpec(href);
--- a/netwerk/protocol/websocket/WebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannel.cpp
@@ -10,16 +10,17 @@
 
 #include "mozilla/Atomics.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/EndianUtils.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/net/WebSocketEventService.h"
 
 #include "nsIURI.h"
+#include "nsIURIMutator.h"
 #include "nsIChannel.h"
 #include "nsICryptoHash.h"
 #include "nsIRunnable.h"
 #include "nsIPrefBranch.h"
 #include "nsIPrefService.h"
 #include "nsICancelable.h"
 #include "nsIClassOfService.h"
 #include "nsIDNSRecord.h"
@@ -3198,21 +3199,25 @@ WebSocketChannel::AsyncOnChannelRedirect
     return rv;
   }
 
   // The redirect is likely OK
 
   newChannel->SetNotificationCallbacks(this);
 
   mEncrypted = newuriIsHttps;
-  newuri->Clone(getter_AddRefs(mURI));
-  if (mEncrypted)
-    rv = mURI->SetScheme(NS_LITERAL_CSTRING("wss"));
-  else
-    rv = mURI->SetScheme(NS_LITERAL_CSTRING("ws"));
+  rv = NS_MutateURI(newuri)
+         .SetScheme(mEncrypted ? NS_LITERAL_CSTRING("wss")
+                               : NS_LITERAL_CSTRING("ws"))
+         .Finalize(mURI);
+
+  if (NS_FAILED(rv)) {
+    LOG(("WebSocketChannel: Could not set the proper scheme\n"));
+    return rv;
+  }
 
   mHttpChannel = newHttpChannel;
   mChannel = newUpgradeChannel;
   rv = SetupRequest();
   if (NS_FAILED(rv)) {
     LOG(("WebSocketChannel: Redirect could not SetupRequest()\n"));
     return rv;
   }
@@ -3456,21 +3461,20 @@ WebSocketChannel::AsyncOpen(nsIURI *aURI
   if (NS_FAILED(rv)) {
     NS_WARNING("unable to continue without random number generator");
     return rv;
   }
 
   nsCOMPtr<nsIURI> localURI;
   nsCOMPtr<nsIChannel> localChannel;
 
-  mURI->Clone(getter_AddRefs(localURI));
-  if (mEncrypted)
-    rv = localURI->SetScheme(NS_LITERAL_CSTRING("https"));
-  else
-    rv = localURI->SetScheme(NS_LITERAL_CSTRING("http"));
+  rv = NS_MutateURI(mURI)
+         .SetScheme(mEncrypted ? NS_LITERAL_CSTRING("https")
+                               : NS_LITERAL_CSTRING("http"))
+         .Finalize(localURI);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIIOService> ioService;
   ioService = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
   if (NS_FAILED(rv)) {
     NS_WARNING("unable to continue without io service");
     return rv;
   }
--- a/netwerk/test/unit/test_URIs.js
+++ b/netwerk/test/unit/test_URIs.js
@@ -514,40 +514,16 @@ function do_test_mutate_ref(aTest, aSuff
       do_info("testing that clearing path from " + 
               pathWithSuffix + " also clears .ref");
       testURI = testURI.mutate().setPathQueryRef("").finalize();
       Assert.equal(testURI.ref, "");
     }
   }
 }
 
-// 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"];
-
-  propertiesToCheck.forEach(function(aProperty) {
-    var threw = false;
-    try {
-      URI[aProperty] = "anothervalue";
-    } catch(e) {
-      threw = true;
-    }
-
-    do_info("testing that setting '" + aProperty +
-            "' on immutable URI '" + aTest.spec + "' will throw");
-    Assert.ok(threw);
-  });
-}
-
-
 // TEST MAIN FUNCTION
 // ------------------
 function run_test()
 {
   // UTF-8 check - From bug 622981
   // ASCII
   let base = gIoService.newURI("http://example.org/xenia?");
   let resolved = gIoService.newURI("?x", null, base);
@@ -574,13 +550,13 @@ function run_test()
           if (!aTest.immutable) {
             do_test_mutate_ref(aTest, aSuffix);
           }
         });
 
       // For URIs that we couldn't mutate above due to them being immutable:
       // Now we check that they're actually immutable.
       if (aTest.immutable) {
-        do_test_immutable(aTest);
+        Assert.ok(aTest.immutable);
       }
     }
   });
 }
--- a/netwerk/test/unit/test_URIs2.js
+++ b/netwerk/test/unit/test_URIs2.js
@@ -615,40 +615,16 @@ function do_test_mutate_ref(aTest, aSuff
       do_info("testing that clearing path from " + 
               pathWithSuffix + " also clears .ref");
       testURI = testURI.mutate().setPathQueryRef("").finalize();
       Assert.equal(testURI.ref, "");
     }
   }
 }
 
-// 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"];
-
-  propertiesToCheck.forEach(function(aProperty) {
-    var threw = false;
-    try {
-      URI[aProperty] = "anothervalue";
-    } catch(e) {
-      threw = true;
-    }
-
-    do_info("testing that setting '" + aProperty +
-            "' on immutable URI '" + aTest.spec + "' will throw");
-    Assert.ok(threw);
-  });
-}
-
-
 // TEST MAIN FUNCTION
 // ------------------
 function run_test()
 {
   // UTF-8 check - From bug 622981
   // ASCII
   let base = gIoService.newURI("http://example.org/xenia?");
   let resolved = gIoService.newURI("?x", null, base);
@@ -675,13 +651,13 @@ function run_test()
           if (!aTest.immutable) {
             do_test_mutate_ref(aTest, aSuffix);
           }
         });
 
       // For URIs that we couldn't mutate above due to them being immutable:
       // Now we check that they're actually immutable.
       if (aTest.immutable) {
-        do_test_immutable(aTest);
+        Assert.ok(aTest.immutable);
       }
     }
   });
 }
--- a/netwerk/test/unit/test_standardurl.js
+++ b/netwerk/test/unit/test_standardurl.js
@@ -301,34 +301,28 @@ 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"];
-  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: "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/,
--- a/security/manager/pki/resources/content/exceptionDialog.js
+++ b/security/manager/pki/resources/content/exceptionDialog.js
@@ -122,25 +122,26 @@ function getURI() {
   // in malformed uri exceptions being thrown.
   let locationTextBox = document.getElementById("locationTextBox");
   let uri = Services.uriFixup.createFixupURI(locationTextBox.value, 0);
 
   if (!uri) {
     return null;
   }
 
+  let mutator = uri.mutate();
   if (uri.scheme == "http") {
-    uri.scheme = "https";
+    mutator.setScheme("https");
   }
 
   if (uri.port == -1) {
-    uri = uri.mutate().setPort(443).finalize();
+    mutator.setPort(443);
   }
 
-  return uri;
+  return mutator.finalize();
 }
 
 function resetDialog() {
   document.getElementById("viewCertButton").disabled = true;
   document.getElementById("permanent").disabled = true;
   gDialog.getButton("extra1").disabled = true;
   setText("headerDescription", "");
   setText("statusDescription", "");
--- a/toolkit/modules/NewTabUtils.jsm
+++ b/toolkit/modules/NewTabUtils.jsm
@@ -960,22 +960,24 @@ var ActivityStreamProvider = {
     return Promise.all(aLinks.map(link => new Promise(async resolve => {
       // Never add favicon data for pocket items
       if (link.type === "pocket") {
         resolve(link);
         return;
       }
       let iconData;
       try {
-        const linkUri = Services.io.newURI(link.url);
+        let linkUri = Services.io.newURI(link.url);
         iconData = await this._getIconData(linkUri);
 
         // Switch the scheme to try again with the other
         if (!iconData) {
-          linkUri.scheme = linkUri.scheme === "https" ? "http" : "https";
+          linkUri = linkUri.mutate()
+                           .setScheme(linkUri.scheme === "https" ? "http" : "https")
+                           .finalize();
           iconData = await this._getIconData(linkUri);
         }
       } catch (e) {
         // We just won't put icon data on the link
       }
 
       // Add the icon data to the link if we have any
       resolve(Object.assign(link, iconData || {}));