Bug 1432187 - Change code to use nsIStandardURLMutator.{init,setDefaultPort} draft
authorValentin Gosu <valentin.gosu@gmail.com>
Wed, 24 Jan 2018 20:33:02 +0100
changeset 724252 e3b8bb3126269b433976ddde4ad3628c94600a2b
parent 724242 aef57a220292ba19f1b474bb982a8b07d64e17f9
child 724253 ec6afd972819d32c34d3c86a9f73597d73594eec
push id96710
push uservalentin.gosu@gmail.com
push dateWed, 24 Jan 2018 19:33:43 +0000
bugs1432187
milestone60.0a1
Bug 1432187 - Change code to use nsIStandardURLMutator.{init,setDefaultPort} MozReview-Commit-ID: K2Uy9ET3Ay6
chrome/nsChromeProtocolHandler.cpp
dom/url/URLWorker.cpp
modules/libjar/nsJARURI.cpp
netwerk/base/nsNetUtil.cpp
netwerk/protocol/file/nsFileProtocolHandler.cpp
netwerk/protocol/ftp/nsFtpProtocolHandler.cpp
netwerk/protocol/gio/nsGIOProtocolHandler.cpp
netwerk/protocol/http/Http2Session.cpp
netwerk/protocol/http/Http2Stream.cpp
netwerk/protocol/http/Http2Stream.h
netwerk/protocol/http/nsHttpHandler.cpp
netwerk/protocol/res/SubstitutingProtocolHandler.cpp
netwerk/protocol/websocket/BaseWebSocketChannel.cpp
netwerk/test/unit/test_bug464591.js
netwerk/test/unit/test_large_port.js
netwerk/test/unit/test_standardurl.js
netwerk/test/unit/test_standardurl_default_port.js
widget/android/nsAndroidProtocolHandler.cpp
--- a/chrome/nsChromeProtocolHandler.cpp
+++ b/chrome/nsChromeProtocolHandler.cpp
@@ -71,33 +71,36 @@ NS_IMETHODIMP
 nsChromeProtocolHandler::NewURI(const nsACString &aSpec,
                                 const char *aCharset,
                                 nsIURI *aBaseURI,
                                 nsIURI **result)
 {
 
     // Chrome: URLs (currently) have no additional structure beyond that provided
     // by standard URLs, so there is no "outer" given to CreateInstance
-
-    RefPtr<mozilla::net::nsStandardURL> surl = new mozilla::net::nsStandardURL();
-
-    nsresult rv = surl->Init(nsIStandardURL::URLTYPE_STANDARD, -1, aSpec,
-                             aCharset, aBaseURI);
-    if (NS_FAILED(rv))
+    nsresult rv;
+    nsCOMPtr<nsIURL> surl;
+    rv = NS_MutateURI(new mozilla::net::nsStandardURL::Mutator())
+           .Apply<nsIStandardURLMutator>(&nsIStandardURLMutator::Init,
+                                         nsIStandardURL::URLTYPE_STANDARD, -1,
+                                         nsCString(aSpec), aCharset, aBaseURI, nullptr)
+           .Finalize(surl);
+    if (NS_FAILED(rv)) {
         return rv;
+    }
 
     // Canonify the "chrome:" URL; e.g., so that we collapse
     // "chrome://navigator/content/" and "chrome://navigator/content"
     // and "chrome://navigator/content/navigator.xul".
 
     rv = nsChromeRegistry::Canonify(surl);
     if (NS_FAILED(rv))
         return rv;
 
-    surl->SetMutable(false);
+    NS_TryToSetImmutable(surl);
 
     surl.forget(result);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsChromeProtocolHandler::NewChannel2(nsIURI* aURI,
                                      nsILoadInfo* aLoadInfo,
--- a/dom/url/URLWorker.cpp
+++ b/dom/url/URLWorker.cpp
@@ -627,36 +627,42 @@ URLWorker::Init(const nsAString& aURL, c
       aRv.ThrowTypeError<MSG_INVALID_URL>(aURL);
       return;
     }
   }
 
   if (scheme.EqualsLiteral("http") || scheme.EqualsLiteral("https")) {
     nsCOMPtr<nsIURI> baseURL;
     if (aBase.WasPassed()) {
-      baseURL = new nsStandardURL();
-
       // XXXcatalinb: SetSpec only writes a warning to the console on urls
       // without a valid scheme. I can't fix that because we've come to rely
       // on that behaviour in a bunch of different places.
       nsresult rv = NS_MutateURI(new nsStandardURL::Mutator())
         .SetSpec(NS_ConvertUTF16toUTF8(aBase.Value()))
         .Finalize(baseURL);
       nsAutoCString baseScheme;
       if (baseURL) {
         baseURL->GetScheme(baseScheme);
       }
       if (NS_WARN_IF(NS_FAILED(rv)) || baseScheme.IsEmpty()) {
         aRv.ThrowTypeError<MSG_INVALID_URL>(aBase.Value());
         return;
       }
     }
-    mStdURL = new nsStandardURL();
-    aRv = mStdURL->Init(nsIStandardURL::URLTYPE_STANDARD, -1,
-                        NS_ConvertUTF16toUTF8(aURL), nullptr, baseURL);
+    nsCOMPtr<nsIURI> uri;
+    rv = NS_MutateURI(new nsStandardURL::Mutator())
+            .Apply<nsIStandardURLMutator>(&nsIStandardURLMutator::Init,
+                                          nsIStandardURL::URLTYPE_STANDARD, -1,
+                                          NS_ConvertUTF16toUTF8(aURL),
+                                          nullptr, baseURL, nullptr)
+            .Finalize(uri);
+    aRv = rv;
+    if (NS_SUCCEEDED(rv)) {
+      mStdURL = static_cast<nsStandardURL*>(uri.get());
+    }
     return;
   }
 
   // create url proxy
   RefPtr<ConstructorRunnable> runnable =
     new ConstructorRunnable(mWorkerPrivate, aURL, aBase);
   runnable->Dispatch(Terminating, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
--- a/modules/libjar/nsJARURI.cpp
+++ b/modules/libjar/nsJARURI.cpp
@@ -89,31 +89,24 @@ nsJARURI::FormatSpec(const nsACString &e
 }
 
 nsresult
 nsJARURI::CreateEntryURL(const nsACString& entryFilename,
                          const char* charset,
                          nsIURL** url)
 {
     *url = nullptr;
-
-    nsCOMPtr<nsIStandardURL> stdURL(do_CreateInstance(NS_STANDARDURL_CONTRACTID));
-    if (!stdURL) {
-        return NS_ERROR_OUT_OF_MEMORY;
-    }
-
     // Flatten the concatenation, just in case.  See bug 128288
     nsAutoCString spec(NS_BOGUS_ENTRY_SCHEME + entryFilename);
-    nsresult rv = stdURL->Init(nsIStandardURL::URLTYPE_NO_AUTHORITY, -1,
-                               spec, charset, nullptr);
-    if (NS_FAILED(rv)) {
-        return rv;
-    }
-
-    return CallQueryInterface(stdURL, url);
+    return NS_MutateURI(NS_STANDARDURLMUTATOR_CONTRACTID)
+             .Apply<nsIStandardURLMutator>(&nsIStandardURLMutator::Init,
+                                           nsIStandardURL::URLTYPE_NO_AUTHORITY, -1,
+                                           spec, charset, nullptr,
+                                           nullptr)
+             .Finalize(url);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsISerializable methods:
 
 NS_IMETHODIMP
 nsJARURI::Read(nsIObjectInputStream* aInputStream)
 {
--- a/netwerk/base/nsNetUtil.cpp
+++ b/netwerk/base/nsNetUtil.cpp
@@ -2856,50 +2856,45 @@ NS_ShouldSecureUpgrade(nsIURI* aURI,
   }
   aShouldUpgrade = false;
   return NS_OK;
 }
 
 nsresult
 NS_GetSecureUpgradedURI(nsIURI* aURI, nsIURI** aUpgradedURI)
 {
-  nsCOMPtr<nsIURI> upgradedURI;
-
-  nsresult rv = aURI->Clone(getter_AddRefs(upgradedURI));
-  NS_ENSURE_SUCCESS(rv,rv);
-
-  // Change the scheme to HTTPS:
-  upgradedURI->SetScheme(NS_LITERAL_CSTRING("https"));
+  NS_MutateURI mutator(aURI);
+  mutator.SetScheme(NS_LITERAL_CSTRING("https")); // Change the scheme to HTTPS:
 
   // Change the default port to 443:
-  nsCOMPtr<nsIStandardURL> upgradedStandardURL = do_QueryInterface(upgradedURI);
-  if (upgradedStandardURL) {
-    upgradedStandardURL->SetDefaultPort(443);
+  nsCOMPtr<nsIStandardURL> stdURL = do_QueryInterface(aURI);
+  if (stdURL) {
+    mutator.Apply<nsIStandardURLMutator>(&nsIStandardURLMutator::SetDefaultPort, 443, nullptr);
   } else {
     // If we don't have a nsStandardURL, fall back to using GetPort/SetPort.
     // XXXdholbert Is this function even called with a non-nsStandardURL arg,
     // in practice?
+    NS_WARNING("Calling NS_GetSecureUpgradedURI for non nsStandardURL");
     int32_t oldPort = -1;
-    rv = aURI->GetPort(&oldPort);
+    nsresult rv = aURI->GetPort(&oldPort);
     if (NS_FAILED(rv)) return rv;
 
     // Keep any nonstandard ports so only the scheme is changed.
     // For example:
     //  http://foo.com:80 -> https://foo.com:443
     //  http://foo.com:81 -> https://foo.com:81
 
     if (oldPort == 80 || oldPort == -1) {
-        upgradedURI->SetPort(-1);
+        mutator.SetPort(-1);
     } else {
-        upgradedURI->SetPort(oldPort);
+        mutator.SetPort(oldPort);
     }
   }
 
-  upgradedURI.forget(aUpgradedURI);
-  return NS_OK;
+  return mutator.Finalize(aUpgradedURI);
 }
 
 nsresult
 NS_CompareLoadInfoAndLoadContext(nsIChannel *aChannel)
 {
   nsCOMPtr<nsILoadInfo> loadInfo;
   aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
 
--- a/netwerk/protocol/file/nsFileProtocolHandler.cpp
+++ b/netwerk/protocol/file/nsFileProtocolHandler.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIFile.h"
 #include "nsFileProtocolHandler.h"
 #include "nsFileChannel.h"
 #include "nsStandardURL.h"
 #include "nsURLHelper.h"
+#include "nsIURIMutator.h"
 
 #include "nsNetUtil.h"
 
 #include "FileChannelChild.h"
 
 // URL file handling, copied and modified from xpfe/components/bookmarks/src/nsBookmarksService.cpp
 #ifdef XP_WIN
 #include <shlobj.h>
@@ -161,33 +162,32 @@ nsFileProtocolHandler::GetProtocolFlags(
 }
 
 NS_IMETHODIMP
 nsFileProtocolHandler::NewURI(const nsACString &spec,
                               const char *charset,
                               nsIURI *baseURI,
                               nsIURI **result)
 {
-    nsCOMPtr<nsIStandardURL> url = new nsStandardURL(true);
-    if (!url)
-        return NS_ERROR_OUT_OF_MEMORY;
+    nsCOMPtr<nsIURI> url = new nsStandardURL(true);
 
-    const nsACString *specPtr = &spec;
-
+    nsAutoCString buf(spec);
 #if defined(XP_WIN)
-    nsAutoCString buf;
-    if (net_NormalizeFileURL(spec, buf))
-        specPtr = &buf;
+    buf.Truncate();
+    if (!net_NormalizeFileURL(spec, buf)) {
+        buf = spec;
+    }
 #endif
 
-    nsresult rv = url->Init(nsIStandardURL::URLTYPE_NO_AUTHORITY, -1,
-                            *specPtr, charset, baseURI);
-    if (NS_FAILED(rv)) return rv;
-
-    return CallQueryInterface(url, result);
+    return NS_MutateURI(url)
+             .Apply<nsIStandardURLMutator>(&nsIStandardURLMutator::Init,
+                                           nsIStandardURL::URLTYPE_NO_AUTHORITY, -1,
+                                           buf, charset, baseURI,
+                                           nullptr)
+             .Finalize(result);
 }
 
 NS_IMETHODIMP
 nsFileProtocolHandler::NewChannel2(nsIURI* uri,
                                    nsILoadInfo* aLoadInfo,
                                    nsIChannel** result)
 {
     nsresult rv;
--- a/netwerk/protocol/ftp/nsFtpProtocolHandler.cpp
+++ b/netwerk/protocol/ftp/nsFtpProtocolHandler.cpp
@@ -166,24 +166,23 @@ nsFtpProtocolHandler::NewURI(const nsACS
     // NS_UnescapeURL() modified spec's buffer, truncate to ensure
     // spec knows its new length.
     spec.Truncate(len);
 
     // return an error if we find a NUL, CR, or LF in the path
     if (spec.FindCharInSet(CRLF) >= 0 || spec.FindChar('\0') >= 0)
         return NS_ERROR_MALFORMED_URI;
 
-    nsresult rv;
-    nsCOMPtr<nsIStandardURL> url = do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv);
-    if (NS_FAILED(rv)) return rv;
-
-    rv = url->Init(nsIStandardURL::URLTYPE_AUTHORITY, 21, aSpec, aCharset, aBaseURI);
-    if (NS_FAILED(rv)) return rv;
-
-    return CallQueryInterface(url, result);
+    nsCOMPtr<nsIURI> url;
+    return NS_MutateURI(NS_STANDARDURLMUTATOR_CONTRACTID)
+             .Apply<nsIStandardURLMutator>(&nsIStandardURLMutator::Init,
+                                           nsIStandardURL::URLTYPE_AUTHORITY, 21,
+                                           nsCString(aSpec), aCharset, aBaseURI,
+                                           nullptr)
+             .Finalize(result);
 }
 
 NS_IMETHODIMP
 nsFtpProtocolHandler::NewChannel2(nsIURI* url,
                                   nsILoadInfo* aLoadInfo,
                                   nsIChannel** result)
 {
     return NewProxiedChannel2(url, nullptr, 0, nullptr, aLoadInfo, result);
--- a/netwerk/protocol/gio/nsGIOProtocolHandler.cpp
+++ b/netwerk/protocol/gio/nsGIOProtocolHandler.cpp
@@ -15,16 +15,17 @@
 #include "nsProxyRelease.h"
 #include "nsIStringBundle.h"
 #include "nsIStandardURL.h"
 #include "nsMimeTypes.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIURI.h"
+#include "nsIURIMutator.h"
 #include "nsIAuthPrompt.h"
 #include "nsIChannel.h"
 #include "nsIInputStream.h"
 #include "nsIProtocolHandler.h"
 #include "NullPrincipal.h"
 #include "mozilla/Monitor.h"
 #include "plstr.h"
 #include "prtime.h"
@@ -1021,28 +1022,22 @@ nsGIOProtocolHandler::NewURI(const nsACS
       uri_schemes++;
     }
 
     if (!uri_scheme_supported) {
       return NS_ERROR_UNKNOWN_PROTOCOL;
     }
   }
 
-  nsresult rv;
-  nsCOMPtr<nsIStandardURL> url =
-      do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv);
-  if (NS_FAILED(rv))
-    return rv;
-
-  rv = url->Init(nsIStandardURL::URLTYPE_STANDARD, -1, flatSpec,
-                 aOriginCharset, aBaseURI);
-  if (NS_SUCCEEDED(rv))
-    rv = CallQueryInterface(url, aResult);
-  return rv;
-
+  return NS_MutateURI(NS_STANDARDURLMUTATOR_CONTRACTID)
+           .Apply<nsIStandardURLMutator>(&nsIStandardURLMutator::Init,
+                                         nsIStandardURL::URLTYPE_STANDARD, -1,
+                                         flatSpec, aOriginCharset, aBaseURI,
+                                         nullptr)
+           .Finalize(aResult);
 }
 
 NS_IMETHODIMP
 nsGIOProtocolHandler::NewChannel2(nsIURI* aURI,
                                   nsILoadInfo* aLoadInfo,
                                   nsIChannel** aResult)
 {
   NS_ENSURE_ARG_POINTER(aURI);
--- a/netwerk/protocol/http/Http2Session.cpp
+++ b/netwerk/protocol/http/Http2Session.cpp
@@ -1883,17 +1883,17 @@ Http2Session::RecvPushPromise(Http2Sessi
     self->CleanupStream(pushedStream, NS_ERROR_FAILURE, PROTOCOL_ERROR);
     self->ResetDownstreamState();
     return NS_OK;
   }
 
   // does the pushed origin belong on this connection?
   LOG3(("Http2Session::RecvPushPromise %p origin check %s", self,
         pushedStream->Origin().get()));
-  RefPtr<nsStandardURL> pushedOrigin;
+  nsCOMPtr<nsIURI> pushedOrigin;
   rv = Http2Stream::MakeOriginURL(pushedStream->Origin(), pushedOrigin);
   nsAutoCString pushedHostName;
   int32_t pushedPort = -1;
   if (NS_SUCCEEDED(rv)) {
     rv = pushedOrigin->GetHost(pushedHostName);
   }
   if (NS_SUCCEEDED(rv)) {
     rv = pushedOrigin->GetPort(&pushedPort);
@@ -1938,17 +1938,17 @@ Http2Session::RecvPushPromise(Http2Sessi
     pushedStream->GetOriginAttributes(&oa);
     RefPtr<LoadContextInfo> lci = GetLoadContextInfo(false, oa);
     nsCOMPtr<nsICacheStorage> ds;
     css->DiskCacheStorage(lci, false, getter_AddRefs(ds));
     // Build up our full URL for the cache lookup
     nsAutoCString spec;
     spec.Assign(pushedStream->Origin());
     spec.Append(pushedStream->Path());
-    RefPtr<nsStandardURL> pushedURL;
+    nsCOMPtr<nsIURI> pushedURL;
     // Nifty trick: this doesn't actually do anything origin-specific, it's just
     // named that way. So by passing it the full spec here, we get a URL with
     // the full path.
     // Another nifty trick! Even though this is using nsIURIs (which are not
     // generally ok off the main thread), since we're not using the protocol
     // handler to create any URIs, this will work just fine here. Don't try this
     // at home, though, kids. I'm a trained professional.
     if (NS_SUCCEEDED(Http2Stream::MakeOriginURL(spec, pushedURL))) {
@@ -2646,17 +2646,17 @@ Http2Session::RecvOrigin(Http2Session *s
       self->mInputFrameBuffer.get() + kFrameHeaderBytes + offset);
     LOG3(("Http2Session::RecvOrigin %p origin extension defined as %d bytes\n", self, originLen));
     if (originLen + 2U + offset > self->mInputFrameDataSize) {
       LOG3(("Http2Session::RecvOrigin %p origin len too big for frame", self));
       break;
     }
 
     nsAutoCString originString;
-    RefPtr<nsStandardURL> originURL;
+    nsCOMPtr<nsIURI> originURL;
     originString.Assign(self->mInputFrameBuffer.get() + kFrameHeaderBytes + offset + 2, originLen);
     offset += originLen + 2;
     if (NS_FAILED(Http2Stream::MakeOriginURL(originString, originURL))){
       LOG3(("Http2Session::RecvOrigin %p origin frame string %s failed to parse\n", self, originString.get()));
       continue;
     }
 
     LOG3(("Http2Session::RecvOrigin %p origin frame string %s parsed OK\n", self, originString.get()));
--- a/netwerk/protocol/http/Http2Stream.cpp
+++ b/netwerk/protocol/http/Http2Stream.cpp
@@ -328,51 +328,53 @@ Http2Stream::WriteSegments(nsAHttpSegmen
             static_cast<uint32_t>(rv), *countWritten));
     }
   }
   mSegmentWriter = nullptr;
   return rv;
 }
 
 nsresult
-Http2Stream::MakeOriginURL(const nsACString &origin, RefPtr<nsStandardURL> &url)
+Http2Stream::MakeOriginURL(const nsACString &origin, nsCOMPtr<nsIURI> &url)
 {
   nsAutoCString scheme;
   nsresult rv = net_ExtractURLScheme(origin, scheme);
   NS_ENSURE_SUCCESS(rv, rv);
   return MakeOriginURL(scheme, origin, url);
 }
 
 nsresult
 Http2Stream::MakeOriginURL(const nsACString &scheme, const nsACString &origin,
-                           RefPtr<nsStandardURL> &url)
+                           nsCOMPtr<nsIURI> &url)
 {
-  url = new nsStandardURL();
-  nsresult rv = url->Init(nsIStandardURL::URLTYPE_AUTHORITY,
-                          scheme.EqualsLiteral("http") ?
-                              NS_HTTP_DEFAULT_PORT :
-                              NS_HTTPS_DEFAULT_PORT,
-                          origin, nullptr, nullptr);
-  return rv;
+  return NS_MutateURI(new nsStandardURL::Mutator())
+           .Apply<nsIStandardURLMutator>(&nsIStandardURLMutator::Init,
+                                         nsIStandardURL::URLTYPE_AUTHORITY,
+                                         scheme.EqualsLiteral("http") ?
+                                             NS_HTTP_DEFAULT_PORT :
+                                             NS_HTTPS_DEFAULT_PORT,
+                                         nsCString(origin), nullptr, nullptr,
+                                         nullptr)
+           .Finalize(url);
 }
 
 void
 Http2Stream::CreatePushHashKey(const nsCString &scheme,
                                const nsCString &hostHeader,
                                const mozilla::OriginAttributes &originAttributes,
                                uint64_t serial,
                                const nsACString& pathInfo,
                                nsCString &outOrigin,
                                nsCString &outKey)
 {
   nsCString fullOrigin = scheme;
   fullOrigin.AppendLiteral("://");
   fullOrigin.Append(hostHeader);
 
-  RefPtr<nsStandardURL> origin;
+  nsCOMPtr<nsIURI> origin;
   nsresult rv = Http2Stream::MakeOriginURL(scheme, fullOrigin, origin);
 
   if (NS_SUCCEEDED(rv)) {
     rv = origin->GetAsciiSpec(outOrigin);
     outOrigin.Trim("/", false, true, false);
   }
 
   if (NS_FAILED(rv)) {
--- a/netwerk/protocol/http/Http2Stream.h
+++ b/netwerk/protocol/http/Http2Stream.h
@@ -156,21 +156,21 @@ public:
   // This is a no-op on pull streams. Pushed streams override this.
   virtual void SetPushComplete() { };
 
   virtual ~Http2Stream();
 
   Http2Session *Session() { return mSession; }
 
   static MOZ_MUST_USE nsresult MakeOriginURL(const nsACString &origin,
-                                             RefPtr<nsStandardURL> &url);
+                                             nsCOMPtr<nsIURI> &url);
 
   static MOZ_MUST_USE nsresult MakeOriginURL(const nsACString &scheme,
                                              const nsACString &origin,
-                                             RefPtr<nsStandardURL> &url);
+                                             nsCOMPtr<nsIURI> &url);
 
   // Mirrors nsAHttpTransaction
   bool Do0RTT();
   nsresult Finish0RTT(bool aRestart, bool aAlpnIgnored);
 
   nsresult GetOriginAttributes(mozilla::OriginAttributes *oa);
 
   void TopLevelOuterContentWindowIdChanged(uint64_t windowId);
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -131,26 +131,22 @@ LazyLogModule gHttpLog("nsHttp");
 
 static nsresult
 NewURI(const nsACString &aSpec,
        const char *aCharset,
        nsIURI *aBaseURI,
        int32_t aDefaultPort,
        nsIURI **aURI)
 {
-    RefPtr<nsStandardURL> url = new nsStandardURL();
-
-    nsresult rv = url->Init(nsIStandardURL::URLTYPE_AUTHORITY,
-                            aDefaultPort, aSpec, aCharset, aBaseURI);
-    if (NS_FAILED(rv)) {
-        return rv;
-    }
-
-    url.forget(aURI);
-    return NS_OK;
+    return NS_MutateURI(new nsStandardURL::Mutator())
+             .Apply<nsIStandardURLMutator>(&nsIStandardURLMutator::Init,
+                                           nsIStandardURL::URLTYPE_AUTHORITY,
+                                           aDefaultPort, nsCString(aSpec), aCharset, aBaseURI,
+                                           nullptr)
+             .Finalize(aURI);
 }
 
 #ifdef ANDROID
 static nsCString
 GetDeviceModelId() {
     // Assumed to be running on the main thread
     // We need the device property in either case
     nsAutoCString deviceModelId;
--- a/netwerk/protocol/res/SubstitutingProtocolHandler.cpp
+++ b/netwerk/protocol/res/SubstitutingProtocolHandler.cpp
@@ -27,16 +27,18 @@ namespace net {
 static LazyLogModule gResLog("nsResProtocol");
 
 static NS_DEFINE_CID(kSubstitutingURLCID, NS_SUBSTITUTINGURL_CID);
 
 //---------------------------------------------------------------------------------
 // SubstitutingURL : overrides nsStandardURL::GetFile to provide nsIFile resolution
 //---------------------------------------------------------------------------------
 
+NS_IMPL_ISUPPORTS(SubstitutingURL::Mutator, nsIURISetters, nsIURIMutator, nsIStandardURLMutator)
+
 nsresult
 SubstitutingURL::EnsureFile()
 {
   nsAutoCString ourScheme;
   nsresult rv = GetScheme(ourScheme);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Get the handler associated with this scheme. It would be nice to just
@@ -191,22 +193,16 @@ SubstitutingProtocolHandler::GetProtocol
 }
 
 nsresult
 SubstitutingProtocolHandler::NewURI(const nsACString &aSpec,
                                     const char *aCharset,
                                     nsIURI *aBaseURI,
                                     nsIURI **result)
 {
-  nsresult rv;
-
-  RefPtr<SubstitutingURL> url = new SubstitutingURL();
-  if (!url)
-    return NS_ERROR_OUT_OF_MEMORY;
-
   // unescape any %2f and %2e to make sure nsStandardURL coalesces them.
   // Later net_GetFileFromURLSpec() will do a full unescape and we want to
   // treat them the same way the file system will. (bugs 380994, 394075)
   nsAutoCString spec;
   const char *src = aSpec.BeginReading();
   const char *end = aSpec.EndReading();
   const char *last = src;
 
@@ -228,21 +224,22 @@ SubstitutingProtocolHandler::NewURI(cons
         src += 2;
         last = src+1; // src will be incremented by the loop
       }
     }
   }
   if (last < src)
     spec.Append(last, src-last);
 
-  rv = url->Init(nsIStandardURL::URLTYPE_STANDARD, -1, spec, aCharset, aBaseURI);
-  if (NS_SUCCEEDED(rv)) {
-    url.forget(result);
-  }
-  return rv;
+  return NS_MutateURI(new SubstitutingURL::Mutator())
+           .Apply<nsIStandardURLMutator>(&nsIStandardURLMutator::Init,
+                                         nsIStandardURL::URLTYPE_STANDARD, -1,
+                                         spec, aCharset, aBaseURI,
+                                         nullptr)
+           .Finalize(result);
 }
 
 nsresult
 SubstitutingProtocolHandler::NewChannel2(nsIURI* uri,
                                          nsILoadInfo* aLoadInfo,
                                          nsIChannel** result)
 {
   NS_ENSURE_ARG_POINTER(uri);
--- a/netwerk/protocol/websocket/BaseWebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/BaseWebSocketChannel.cpp
@@ -301,23 +301,22 @@ BaseWebSocketChannel::NewURI(const nsACS
 {
   LOG(("BaseWebSocketChannel::NewURI() %p\n", this));
 
   int32_t port;
   nsresult rv = GetDefaultPort(&port);
   if (NS_FAILED(rv))
     return rv;
 
-  RefPtr<nsStandardURL> url = new nsStandardURL();
-  rv = url->Init(nsIStandardURL::URLTYPE_AUTHORITY, port, aSpec,
-                aOriginCharset, aBaseURI);
-  if (NS_FAILED(rv))
-    return rv;
-  url.forget(_retval);
-  return NS_OK;
+  return NS_MutateURI(new nsStandardURL::Mutator())
+           .Apply<nsIStandardURLMutator>(&nsIStandardURLMutator::Init,
+                                         nsIStandardURL::URLTYPE_AUTHORITY, port,
+                                         nsCString(aSpec), aOriginCharset, aBaseURI,
+                                         nullptr)
+           .Finalize(_retval);
 }
 
 NS_IMETHODIMP
 BaseWebSocketChannel::NewChannel2(nsIURI* aURI,
                                   nsILoadInfo* aLoadInfo,
                                   nsIChannel** outChannel)
 {
   LOG(("BaseWebSocketChannel::NewChannel2() %p\n", this));
--- a/netwerk/test/unit/test_bug464591.js
+++ b/netwerk/test/unit/test_bug464591.js
@@ -1,13 +1,8 @@
-
-const StandardURL = Components.Constructor("@mozilla.org/network/standard-url;1",
-                                           "nsIStandardURL",
-                                           "init");
-
  // 1.percent-encoded IDN that contains blacklisted character should be converted
  //   to punycode, not UTF-8 string
  // 2.only hostname-valid percent encoded ASCII characters should be decoded
  // 3.IDN convertion must not bypassed by %00
 let reference = [
    ["www.example.com%e2%88%95www.mozill%d0%b0.com%e2%81%84www.mozilla.org",
     "www.example.xn--comwww-re3c.xn--mozill-8nf.xn--comwww-rq0c.mozilla.org"],
    ["www.mozill%61%2f.org", "www.mozilla%2f.org"], // a slash is not valid in the hostname
@@ -32,18 +27,20 @@ let prefData =
   ];
 
  let prefIdnBlackList = {
       name: "network.IDN.blacklist_chars",
       minimumList: "\u2215\u0430\u2044",
   };
 
 function stringToURL(str) {
-  return (new StandardURL(Ci.nsIStandardURL.URLTYPE_AUTHORITY, 80,
-			 str, "UTF-8", null))
+  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 run_test() {
   // Make sure our prefs are set such that this test actually means something
   let prefs = Cc["@mozilla.org/preferences-service;1"].
               getService(Ci.nsIPrefBranch);
   for (let pref of prefData) {
--- a/netwerk/test/unit/test_large_port.js
+++ b/netwerk/test/unit/test_large_port.js
@@ -4,33 +4,45 @@
 
 // Ensure that non-16-bit URIs are rejected
 
 "use strict";
 
 var Cc = Components.classes;
 var Ci = Components.interfaces;
 
-const StandardURL = Components.Constructor("@mozilla.org/network/standard-url;1",
-                                           "nsIStandardURL",
-                                           "init");
 function run_test()
 {
+    let mutator = Cc["@mozilla.org/network/standard-url-mutator;1"]
+                    .createInstance(Ci.nsIURIMutator);
+    Assert.ok(mutator, "Mutator constructor works");
+
+    let url = Cc["@mozilla.org/network/standard-url-mutator;1"]
+                .createInstance(Ci.nsIStandardURLMutator)
+                .init(Ci.nsIStandardURL.URLTYPE_AUTHORITY, 65535,
+                      "http://localhost", "UTF-8", null)
+                .finalize();
+
     // Bug 1301621 makes invalid ports throw
     Assert.throws(() => {
-        new StandardURL(Ci.nsIStandardURL.URLTYPE_AUTHORITY, 65536,
-                "http://localhost", "UTF-8", null)
+        url = Cc["@mozilla.org/network/standard-url-mutator;1"]
+                .createInstance(Ci.nsIStandardURLMutator)
+                .init(Ci.nsIStandardURL.URLTYPE_AUTHORITY, 65536,
+                      "http://localhost", "UTF-8", null)
+                .finalize();
     }, "invalid port during creation");
-    let url = new StandardURL(Ci.nsIStandardURL.URLTYPE_AUTHORITY, 65535,
-                              "http://localhost", "UTF-8", null)
-                .QueryInterface(Ci.nsIStandardURL)
 
     Assert.throws(() => {
-        url.setDefaultPort(65536);
+        url = url.mutate()
+                 .QueryInterface(Ci.nsIStandardURLMutator)
+                 .setDefaultPort(65536)
+                 .finalize();
     }, "invalid port in setDefaultPort");
     Assert.throws(() => {
-        url.port = 65536;
+        url = url.mutate()
+                 .setPort(65536)
+                 .finalize();
     }, "invalid port in port setter");
 
-    Assert.equal(url.QueryInterface(Ci.nsIURI).port, -1);
+    Assert.equal(url.port, -1);
     do_test_finished();
 }
 
--- a/netwerk/test/unit/test_standardurl.js
+++ b/netwerk/test/unit/test_standardurl.js
@@ -1,14 +1,10 @@
 "use strict";
 
-const StandardURL = Components.Constructor("@mozilla.org/network/standard-url;1",
-                                           "nsIStandardURL",
-                                           "init");
-const nsIStandardURL = Components.interfaces.nsIStandardURL;
 const gPrefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
 
 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) {
@@ -26,19 +22,21 @@ function symmetricEquality(expect, a, b)
   } else {
     Assert.notEqual(a.spec, b.spec);
   }
   Assert.equal(expect, a.equals(b));
   Assert.equal(expect, b.equals(a));
 }
 
 function stringToURL(str) {
-  return (new StandardURL(nsIStandardURL.URLTYPE_AUTHORITY, 80,
-			 str, "UTF-8", null))
-         .QueryInterface(Components.interfaces.nsIURL);
+  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()
--- a/netwerk/test/unit/test_standardurl_default_port.js
+++ b/netwerk/test/unit/test_standardurl_default_port.js
@@ -6,46 +6,55 @@
 
 /* This test exercises the nsIStandardURL "setDefaultPort" API. */
 
 "use strict";
 
 var Cc = Components.classes;
 var Ci = Components.interfaces;
 
-const StandardURL = Components.Constructor("@mozilla.org/network/standard-url;1",
-                                           "nsIStandardURL",
-                                           "init");
 function run_test() {
   function stringToURL(str) {
-    return (new StandardURL(Ci.nsIStandardURL.URLTYPE_AUTHORITY, 80,
-			    str, "UTF-8", null))
-      .QueryInterface(Ci.nsIStandardURL);
+    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.nsIStandardURL);
   }
 
   // Create a nsStandardURL:
   var origUrlStr = "http://foo.com/";
   var stdUrl = stringToURL(origUrlStr);
-  var stdUrlAsUri = stdUrl.QueryInterface(Ci.nsIURI);
-  Assert.equal(-1, stdUrlAsUri.port);
+  Assert.equal(-1, stdUrl.port);
 
   // Changing default port shouldn't adjust the value returned by "port",
   // or the string representation.
-  stdUrl.setDefaultPort(100);
-  Assert.equal(-1, stdUrlAsUri.port);
-  Assert.equal(stdUrlAsUri.spec, origUrlStr);
+  let def100Url = stdUrl.mutate()
+                        .QueryInterface(Ci.nsIStandardURLMutator)
+                        .setDefaultPort(100)
+                        .finalize();
+  Assert.equal(-1, def100Url.port);
+  Assert.equal(def100Url.spec, origUrlStr);
 
   // Changing port directly should update .port and .spec, though:
-  stdUrlAsUri.port = "200";
-  Assert.equal(200, stdUrlAsUri.port);
-  Assert.equal(stdUrlAsUri.spec, "http://foo.com:200/");
+  let port200Url = stdUrl.mutate()
+                         .setPort("200")
+                         .finalize();
+  Assert.equal(200, port200Url.port);
+  Assert.equal(port200Url.spec, "http://foo.com:200/");
 
   // ...but then if we change default port to match the custom port,
   // the custom port should reset to -1 and disappear from .spec:
-  stdUrl.setDefaultPort(200);
-  Assert.equal(-1, stdUrlAsUri.port);
-  Assert.equal(stdUrlAsUri.spec, origUrlStr);
+  let def200Url = port200Url.mutate()
+                            .QueryInterface(Ci.nsIStandardURLMutator)
+                            .setDefaultPort(200)
+                            .finalize();
+  Assert.equal(-1, def200Url.port);
+  Assert.equal(def200Url.spec, origUrlStr);
 
   // And further changes to default port should not make custom port reappear.
-  stdUrl.setDefaultPort(300);
-  Assert.equal(-1, stdUrlAsUri.port);
-  Assert.equal(stdUrlAsUri.spec, origUrlStr);
+  let def300Url = def200Url.mutate()
+                           .QueryInterface(Ci.nsIStandardURLMutator)
+                           .setDefaultPort(300)
+                           .finalize();
+  Assert.equal(-1, def300Url.port);
+  Assert.equal(def300Url.spec, origUrlStr);
 }
--- a/widget/android/nsAndroidProtocolHandler.cpp
+++ b/widget/android/nsAndroidProtocolHandler.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsAndroidProtocolHandler.h"
 #include "nsCOMPtr.h"
 #include "nsIChannel.h"
 #include "nsIIOService.h"
 #include "nsIStandardURL.h"
 #include "nsIURL.h"
+#include "nsIURIMutator.h"
 #include "android/log.h"
 #include "nsBaseChannel.h"
 #include "AndroidBridge.h"
 #include "GeneratedJNIWrappers.h"
 
 using namespace mozilla;
 
 class AndroidInputStream : public nsIInputStream
@@ -135,32 +136,22 @@ nsAndroidProtocolHandler::GetProtocolFla
 }
 
 NS_IMETHODIMP
 nsAndroidProtocolHandler::NewURI(const nsACString &aSpec,
                                  const char *aCharset,
                                  nsIURI *aBaseURI,
                                  nsIURI **result)
 {
-    nsresult rv;
-
-    nsCOMPtr<nsIStandardURL> surl(do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = surl->Init(nsIStandardURL::URLTYPE_STANDARD, -1, aSpec, aCharset, aBaseURI);
-    if (NS_FAILED(rv))
-        return rv;
-
-    nsCOMPtr<nsIURL> url(do_QueryInterface(surl, &rv));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    surl->SetMutable(false);
-
-    NS_ADDREF(*result = url);
-    return NS_OK;
+    return NS_MutateURI(NS_STANDARDURLMUTATOR_CONTRACTID)
+             .Apply<nsIStandardURLMutator>(&nsIStandardURLMutator::Init,
+                                           nsIStandardURL::URLTYPE_STANDARD, -1,
+                                           nsCString(aSpec), aCharset, aBaseURI,
+                                           nullptr)
+             .Finalize(result);
 }
 
 NS_IMETHODIMP
 nsAndroidProtocolHandler::NewChannel2(nsIURI* aURI,
                                       nsILoadInfo* aLoadInfo,
                                       nsIChannel** aResult)
 {
     nsCOMPtr<nsIChannel> channel = AndroidChannel::CreateChannel(aURI);