Bug 1415205 - Add nsIURIMutator impls for all objects implementing nsIURI r=bagder
authorValentin Gosu <valentin.gosu@gmail.com>
Mon, 20 Nov 2017 17:11:30 +0100
changeset 392878 306f999b79a588565b9e73dfda75c13248263dde
parent 392877 a6339ec0511bd3bdff7b3fa91226930657cbdb48
child 392879 61c0df291447d3eb409114988b0a52e5a7dbc551
push id32945
push userccoroiu@mozilla.com
push dateTue, 21 Nov 2017 23:30:10 +0000
treeherdermozilla-central@0ee6ca490391 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbagder
bugs1415205
milestone59.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 1415205 - Add nsIURIMutator impls for all objects implementing nsIURI r=bagder This also changes URIUtils.cpp:DeserializeURI() to use the mutator to instantiate new URIs, instead of using their default constructor. MozReview-Commit-ID: JQOvIquuQAP
caps/NullPrincipalURI.cpp
caps/NullPrincipalURI.h
dom/file/nsHostObjectURI.cpp
dom/file/nsHostObjectURI.h
dom/jsurl/nsJSProtocolHandler.cpp
dom/jsurl/nsJSProtocolHandler.h
image/decoders/icon/nsIconModule.cpp
image/decoders/icon/nsIconURI.cpp
image/decoders/icon/nsIconURI.h
image/nsIIconURI.idl
ipc/glue/URIUtils.cpp
modules/libjar/nsJARFactory.cpp
modules/libjar/nsJARURI.cpp
modules/libjar/nsJARURI.h
netwerk/base/nsIURIMutator.idl
netwerk/base/nsSimpleNestedURI.cpp
netwerk/base/nsSimpleNestedURI.h
netwerk/base/nsSimpleURI.cpp
netwerk/base/nsSimpleURI.h
netwerk/base/nsStandardURL.cpp
netwerk/base/nsStandardURL.h
netwerk/build/nsNetCID.h
netwerk/build/nsNetModule.cpp
netwerk/protocol/about/nsAboutProtocolHandler.cpp
netwerk/protocol/about/nsAboutProtocolHandler.h
--- a/caps/NullPrincipalURI.cpp
+++ b/caps/NullPrincipalURI.cpp
@@ -306,16 +306,30 @@ NullPrincipalURI::CloneIgnoringRef(nsIUR
 NS_IMETHODIMP
 NullPrincipalURI::CloneWithNewRef(const nsACString& newRef, nsIURI** _newURI)
 {
   // GetRef/SetRef not supported by NullPrincipalURI, so
   // CloneWithNewRef() is the same as Clone().
   return Clone(_newURI);
 }
 
+NS_IMPL_ISUPPORTS(NullPrincipalURI::Mutator, nsIURISetters, nsIURIMutator)
+
+NS_IMETHODIMP
+NullPrincipalURI::Mutate(nsIURIMutator** aMutator)
+{
+    RefPtr<NullPrincipalURI::Mutator> mutator = new NullPrincipalURI::Mutator();
+    nsresult rv = mutator->InitFromURI(this);
+    if (NS_FAILED(rv)) {
+        return rv;
+    }
+    mutator.forget(aMutator);
+    return NS_OK;
+}
+
 NS_IMETHODIMP
 NullPrincipalURI::Equals(nsIURI* aOther, bool* _equals)
 {
   *_equals = false;
   RefPtr<NullPrincipalURI> otherURI;
   nsresult rv = aOther->QueryInterface(kNullPrincipalURIImplementationCID,
                                        getter_AddRefs(otherURI));
   if (NS_SUCCEEDED(rv)) {
--- a/caps/NullPrincipalURI.h
+++ b/caps/NullPrincipalURI.h
@@ -14,16 +14,17 @@
 #include "nsIURI.h"
 #include "nsISizeOf.h"
 #include "nsString.h"
 #include "mozilla/Attributes.h"
 #include "nsIIPCSerializableURI.h"
 #include "mozilla/MemoryReporting.h"
 #include "NullPrincipal.h"
 #include "nsID.h"
+#include "nsIURIMutator.h"
 
 // {51fcd543-3b52-41f7-b91b-6b54102236e6}
 #define NS_NULLPRINCIPALURI_IMPLEMENTATION_CID \
   {0x51fcd543, 0x3b52, 0x41f7, \
     {0xb9, 0x1b, 0x6b, 0x54, 0x10, 0x22, 0x36, 0xe6} }
 
 class NullPrincipalURI final : public nsIURI
                              , public nsISizeOf
@@ -33,26 +34,61 @@ public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIURI
   NS_DECL_NSIIPCSERIALIZABLEURI
 
   // nsISizeOf
   virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
   virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
 
-  // NB: This constructor exists only for deserialization.  Everyone
-  // else should call Create.
-  NullPrincipalURI();
-
   // Returns null on failure.
   static already_AddRefed<NullPrincipalURI> Create();
 
 private:
+  NullPrincipalURI();
   NullPrincipalURI(const NullPrincipalURI& aOther);
 
   ~NullPrincipalURI() {}
 
   nsresult Init();
 
   nsAutoCStringN<NSID_LENGTH> mPath;
+
+public:
+  class Mutator
+      : public nsIURIMutator
+      , public BaseURIMutator<NullPrincipalURI>
+  {
+    NS_DECL_ISUPPORTS
+    NS_FORWARD_SAFE_NSIURISETTERS(mURI)
+
+    NS_IMETHOD Deserialize(const mozilla::ipc::URIParams& aParams) override
+    {
+      return InitFromIPCParams(aParams);
+    }
+
+    NS_IMETHOD Read(nsIObjectInputStream* aStream) override
+    {
+      return NS_ERROR_NOT_IMPLEMENTED;
+    }
+
+    NS_IMETHOD Finalize(nsIURI** aURI) override
+    {
+      mURI.forget(aURI);
+      return NS_OK;
+    }
+
+    NS_IMETHOD SetSpec(const nsACString & aSpec) override
+    {
+      return NS_ERROR_NOT_IMPLEMENTED;
+    }
+
+    explicit Mutator() { }
+  private:
+    virtual ~Mutator() { }
+
+    friend class NullPrincipalURI;
+  };
+
+  friend class BaseURIMutator<NullPrincipalURI>;
 };
 
 #endif // __NullPrincipalURI_h__
--- a/dom/file/nsHostObjectURI.cpp
+++ b/dom/file/nsHostObjectURI.cpp
@@ -225,16 +225,30 @@ nsHostObjectURI::EqualsInternal(nsIURI* 
     // Both of us have mPrincipals. Compare them.
     return mPrincipal->Equals(otherUri->mPrincipal, aResult);
   }
   // else, at least one of us lacks a principal; only equal if *both* lack it.
   *aResult = (!mPrincipal && !otherUri->mPrincipal);
   return NS_OK;
 }
 
+NS_IMPL_ISUPPORTS(nsHostObjectURI::Mutator, nsIURISetters, nsIURIMutator)
+
+NS_IMETHODIMP
+nsHostObjectURI::Mutate(nsIURIMutator** aMutator)
+{
+    RefPtr<nsHostObjectURI::Mutator> mutator = new nsHostObjectURI::Mutator();
+    nsresult rv = mutator->InitFromURI(this);
+    if (NS_FAILED(rv)) {
+        return rv;
+    }
+    mutator.forget(aMutator);
+    return NS_OK;
+}
+
 // nsIClassInfo methods:
 NS_IMETHODIMP
 nsHostObjectURI::GetInterfaces(uint32_t *count, nsIID * **array)
 {
   *count = 0;
   *array = nullptr;
   return NS_OK;
 }
--- a/dom/file/nsHostObjectURI.h
+++ b/dom/file/nsHostObjectURI.h
@@ -62,22 +62,40 @@ public:
   virtual mozilla::net::nsSimpleURI* StartClone(RefHandlingEnum refHandlingMode,
                                                 const nsACString& newRef) override
   {
     nsHostObjectURI* url = new nsHostObjectURI();
     SetRefOnClone(url, refHandlingMode, newRef);
     return url;
   }
 
+  NS_IMETHOD Mutate(nsIURIMutator * *_retval) override;
+
   void ForgetBlobImpl();
 
   nsCOMPtr<nsIPrincipal> mPrincipal;
   RefPtr<mozilla::dom::BlobImpl> mBlobImpl;
 
 protected:
   virtual ~nsHostObjectURI() {}
+
+public:
+  class Mutator
+    : public nsIURIMutator
+    , public BaseURIMutator<nsHostObjectURI>
+  {
+    NS_DECL_ISUPPORTS
+    NS_FORWARD_SAFE_NSIURISETTERS(mURI)
+    NS_DEFINE_NSIMUTATOR_COMMON
+
+    explicit Mutator() { }
+  private:
+    virtual ~Mutator() { }
+
+    friend class nsHostObjectURI;
+  };
 };
 
 #define NS_HOSTOBJECTURI_CID \
 { 0xf5475c51, 0x59a7, 0x4757, \
   { 0xb3, 0xd9, 0xe2, 0x11, 0xa9, 0x41, 0x08, 0x72 } }
 
 #endif /* nsHostObjectURI_h */
--- a/dom/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/jsurl/nsJSProtocolHandler.cpp
@@ -1370,16 +1370,30 @@ nsJSURI::StartClone(mozilla::net::nsSimp
       }
     }
 
     nsJSURI* url = new nsJSURI(baseClone);
     SetRefOnClone(url, refHandlingMode, newRef);
     return url;
 }
 
+NS_IMPL_ISUPPORTS(nsJSURI::Mutator, nsIURISetters, nsIURIMutator)
+
+NS_IMETHODIMP
+nsJSURI::Mutate(nsIURIMutator** aMutator)
+{
+    RefPtr<nsJSURI::Mutator> mutator = new nsJSURI::Mutator();
+    nsresult rv = mutator->InitFromURI(this);
+    if (NS_FAILED(rv)) {
+        return rv;
+    }
+    mutator.forget(aMutator);
+    return NS_OK;
+}
+
 /* virtual */ nsresult
 nsJSURI::EqualsInternal(nsIURI* aOther,
                         mozilla::net::nsSimpleURI::RefHandlingEnum aRefHandlingMode,
                         bool* aResult)
 {
     NS_ENSURE_ARG_POINTER(aOther);
     NS_PRECONDITION(aResult, "null pointer for outparam");
 
--- a/dom/jsurl/nsJSProtocolHandler.h
+++ b/dom/jsurl/nsJSProtocolHandler.h
@@ -76,16 +76,17 @@ public:
         return mBaseURI;
     }
 
     NS_DECL_ISUPPORTS_INHERITED
 
     // nsIURI overrides
     virtual mozilla::net::nsSimpleURI* StartClone(RefHandlingEnum refHandlingMode,
                                                   const nsACString& newRef) override;
+    NS_IMETHOD Mutate(nsIURIMutator * *_retval) override;
 
     // nsISerializable overrides
     NS_IMETHOD Read(nsIObjectInputStream* aStream) override;
     NS_IMETHOD Write(nsIObjectOutputStream* aStream) override;
 
     // nsIIPCSerializableURI overrides
     NS_DECL_NSIIPCSERIALIZABLEURI
 
@@ -97,11 +98,27 @@ public:
 protected:
     virtual ~nsJSURI() {}
 
     virtual nsresult EqualsInternal(nsIURI* other,
                                     RefHandlingEnum refHandlingMode,
                                     bool* result) override;
 private:
     nsCOMPtr<nsIURI> mBaseURI;
+
+public:
+    class Mutator
+        : public nsIURIMutator
+        , public BaseURIMutator<nsJSURI>
+    {
+        NS_DECL_ISUPPORTS
+        NS_FORWARD_SAFE_NSIURISETTERS(mURI)
+        NS_DEFINE_NSIMUTATOR_COMMON
+
+        explicit Mutator() { }
+    private:
+        virtual ~Mutator() { }
+
+        friend class nsJSURI;
+    };
 };
 
 #endif /* nsJSProtocolHandler_h___ */
--- a/image/decoders/icon/nsIconModule.cpp
+++ b/image/decoders/icon/nsIconModule.cpp
@@ -15,23 +15,27 @@
 //*****************************************************************************
 // Protocol CIDs
 
 #define NS_ICONPROTOCOL_CID { 0xd0f9db12, 0x249c, 0x11d5, \
                               { 0x99, 0x5, 0x0, 0x10, 0x83, 0x1, 0xe, 0x9b } }
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsIconProtocolHandler)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsMozIconURI)
+typedef nsMozIconURI::Mutator nsMozIconURIMutator;
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsMozIconURIMutator)
 
 NS_DEFINE_NAMED_CID(NS_ICONPROTOCOL_CID);
 NS_DEFINE_NAMED_CID(NS_MOZICONURI_CID);
+NS_DEFINE_NAMED_CID(NS_MOZICONURIMUTATOR_CID);
 
 static const mozilla::Module::CIDEntry kIconCIDs[] = {
   { &kNS_ICONPROTOCOL_CID, false, nullptr, nsIconProtocolHandlerConstructor },
   { &kNS_MOZICONURI_CID, false, nullptr, nsMozIconURIConstructor },
+  { &kNS_MOZICONURIMUTATOR_CID, false, nullptr, nsMozIconURIMutatorConstructor },
   { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kIconContracts[] = {
   { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "moz-icon", &kNS_ICONPROTOCOL_CID },
   { nullptr }
 };
 
--- a/image/decoders/icon/nsIconURI.cpp
+++ b/image/decoders/icon/nsIconURI.cpp
@@ -143,16 +143,30 @@ nsMozIconURI::GetDisplayPrePath(nsACStri
 
 NS_IMETHODIMP
 nsMozIconURI::GetHasRef(bool* result)
 {
   *result = false;
   return NS_OK;
 }
 
+NS_IMPL_ISUPPORTS(nsMozIconURI::Mutator, nsIURISetters, nsIURIMutator)
+
+NS_IMETHODIMP
+nsMozIconURI::Mutate(nsIURIMutator** aMutator)
+{
+    RefPtr<nsMozIconURI::Mutator> mutator = new nsMozIconURI::Mutator();
+    nsresult rv = mutator->InitFromURI(this);
+    if (NS_FAILED(rv)) {
+        return rv;
+    }
+    mutator.forget(aMutator);
+    return NS_OK;
+}
+
 // takes a string like ?size=32&contentType=text/html and returns a new string
 // containing just the attribute value. i.e you could pass in this string with
 // an attribute name of 'size=', this will return 32
 // Assumption: attribute pairs in the string are separated by '&'.
 void
 extractAttributeValue(const char* aSearchString,
                            const char* aAttributeName,
                            nsCString& aResult)
--- a/image/decoders/icon/nsIconURI.h
+++ b/image/decoders/icon/nsIconURI.h
@@ -7,16 +7,18 @@
 #ifndef mozilla_image_decoders_icon_nsIconURI_h
 #define mozilla_image_decoders_icon_nsIconURI_h
 
 #include "nsIIconURI.h"
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsIIPCSerializableURI.h"
 #include "nsINestedURI.h"
+#include "nsIURIMutator.h"
+
 
 class nsMozIconURI : public nsIMozIconURI
                    , public nsIIPCSerializableURI
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIURI
   NS_DECL_NSIMOZICONURI
@@ -34,16 +36,51 @@ protected:
                           // type
   nsCString mFileName; // for if we don't have an actual file path, we're just
                        // given a filename with an extension
   nsCString mStockIcon;
   int32_t mIconSize;   // -1 if not specified, otherwise index into
                        // kSizeStrings
   int32_t mIconState;  // -1 if not specified, otherwise index into
                        // kStateStrings
+
+public:
+  class Mutator
+      : public nsIURIMutator
+      , public BaseURIMutator<nsMozIconURI>
+  {
+    NS_DECL_ISUPPORTS
+    NS_FORWARD_SAFE_NSIURISETTERS(mURI)
+
+    NS_IMETHOD Deserialize(const mozilla::ipc::URIParams& aParams) override
+    {
+      return InitFromIPCParams(aParams);
+    }
+
+    NS_IMETHOD Read(nsIObjectInputStream* aStream) override
+    {
+      return NS_ERROR_NOT_IMPLEMENTED;
+    }
+
+    NS_IMETHOD Finalize(nsIURI** aURI) override
+    {
+      mURI.forget(aURI);
+      return NS_OK;
+    }
+
+    NS_IMETHOD SetSpec(const nsACString & aSpec) override {
+      return InitFromSpec(aSpec);
+    }
+
+    explicit Mutator() { }
+  private:
+    virtual ~Mutator() { }
+
+    friend class nsMozIconURI;
+  };
 };
 
 // For moz-icon URIs that point to an actual file on disk and are
 // therefore nested URIs
 class nsNestedMozIconURI final : public nsMozIconURI
                                , public nsINestedURI
 {
   NS_DECL_ISUPPORTS_INHERITED
--- a/image/nsIIconURI.idl
+++ b/image/nsIIconURI.idl
@@ -76,9 +76,17 @@ interface nsIMozIconURI : nsIURI
 #define NS_MOZICONURI_CID                            \
 {                                                    \
     0x43a88e0e,                                      \
     0x2d37,                                          \
     0x11d5,                                          \
     { 0x99, 0x7, 0x0, 0x10, 0x83, 0x1, 0xe, 0x9b }   \
 }
 
+#define NS_MOZICONURIMUTATOR_CID                     \
+{                                                    \
+    0x1460df3b,                                      \
+    0x774c,                                          \
+    0x4205,                                          \
+    {0x83, 0x49, 0x83, 0x8e, 0x50, 0x7c, 0x3e, 0xf9} \
+}
+
 %}
--- a/ipc/glue/URIUtils.cpp
+++ b/ipc/glue/URIUtils.cpp
@@ -16,26 +16,27 @@
 #include "nsJARURI.h"
 #include "nsIIconURI.h"
 #include "nsHostObjectURI.h"
 #include "NullPrincipalURI.h"
 #include "nsJSProtocolHandler.h"
 #include "nsNetCID.h"
 #include "nsSimpleNestedURI.h"
 #include "nsThreadUtils.h"
+#include "nsIURIMutator.h"
 
 using namespace mozilla::ipc;
 using mozilla::ArrayLength;
 
 namespace {
 
-NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
-NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID);
-NS_DEFINE_CID(kJARURICID, NS_JARURI_CID);
-NS_DEFINE_CID(kIconURICID, NS_MOZICONURI_CID);
+NS_DEFINE_CID(kSimpleURIMutatorCID, NS_SIMPLEURIMUTATOR_CID);
+NS_DEFINE_CID(kStandardURLMutatorCID, NS_STANDARDURLMUTATOR_CID);
+NS_DEFINE_CID(kJARURIMutatorCID, NS_JARURIMUTATOR_CID);
+NS_DEFINE_CID(kIconURIMutatorCID, NS_MOZICONURIMUTATOR_CID);
 
 } // namespace
 
 namespace mozilla {
 namespace ipc {
 
 void
 SerializeURI(nsIURI* aURI,
@@ -71,64 +72,67 @@ SerializeURI(nsIURI* aURI,
   }
 }
 
 already_AddRefed<nsIURI>
 DeserializeURI(const URIParams& aParams)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  nsCOMPtr<nsIIPCSerializableURI> serializable;
+  nsCOMPtr<nsIURIMutator> mutator;
 
   switch (aParams.type()) {
     case URIParams::TSimpleURIParams:
-      serializable = do_CreateInstance(kSimpleURICID);
+      mutator = do_CreateInstance(kSimpleURIMutatorCID);
       break;
 
     case URIParams::TStandardURLParams:
-      serializable = do_CreateInstance(kStandardURLCID);
+      mutator = do_CreateInstance(kStandardURLMutatorCID);
       break;
 
     case URIParams::TJARURIParams:
-      serializable = do_CreateInstance(kJARURICID);
+      mutator = do_CreateInstance(kJARURIMutatorCID);
       break;
 
     case URIParams::TJSURIParams:
-      serializable = new nsJSURI();
+      mutator = new nsJSURI::Mutator();
       break;
 
     case URIParams::TIconURIParams:
-      serializable = do_CreateInstance(kIconURICID);
+      mutator = do_CreateInstance(kIconURIMutatorCID);
       break;
 
     case URIParams::TNullPrincipalURIParams:
-      serializable = new NullPrincipalURI();
+      mutator = new NullPrincipalURI::Mutator();
       break;
 
     case URIParams::TSimpleNestedURIParams:
-      serializable = new nsSimpleNestedURI();
+      mutator = new nsSimpleNestedURI::Mutator();
       break;
 
     case URIParams::THostObjectURIParams:
-      serializable = new nsHostObjectURI();
+      mutator = new nsHostObjectURI::Mutator();
       break;
 
     default:
       MOZ_CRASH("Unknown params!");
   }
 
-  MOZ_ASSERT(serializable);
+  MOZ_ASSERT(mutator);
 
-  if (!serializable->Deserialize(aParams)) {
+  nsresult rv = mutator->Deserialize(aParams);
+  if (NS_FAILED(rv)) {
     MOZ_ASSERT(false, "Deserialize failed!");
     return nullptr;
   }
 
-  nsCOMPtr<nsIURI> uri = do_QueryInterface(serializable);
+  nsCOMPtr<nsIURI> uri;
+  DebugOnly<nsresult> rv2 = mutator->Finalize(getter_AddRefs(uri));
   MOZ_ASSERT(uri);
+  MOZ_ASSERT(NS_SUCCEEDED(rv2));
 
   return uri.forget();
 }
 
 already_AddRefed<nsIURI>
 DeserializeURI(const OptionalURIParams& aParams)
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/modules/libjar/nsJARFactory.cpp
+++ b/modules/libjar/nsJARFactory.cpp
@@ -17,26 +17,31 @@
 #include "nsJAR.h"
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsJAR)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsZipReaderCache)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsJARProtocolHandler,
                                          nsJARProtocolHandler::GetSingleton)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsJARURI)
 
+typedef nsJARURI::Mutator nsJARURIMutator;
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsJARURIMutator)
+
 NS_DEFINE_NAMED_CID(NS_ZIPREADER_CID);
 NS_DEFINE_NAMED_CID(NS_ZIPREADERCACHE_CID);
 NS_DEFINE_NAMED_CID(NS_JARPROTOCOLHANDLER_CID);
 NS_DEFINE_NAMED_CID(NS_JARURI_CID);
+NS_DEFINE_NAMED_CID(NS_JARURIMUTATOR_CID);
 
 static const mozilla::Module::CIDEntry kJARCIDs[] = {
     { &kNS_ZIPREADER_CID, false, nullptr, nsJARConstructor },
     { &kNS_ZIPREADERCACHE_CID, false, nullptr, nsZipReaderCacheConstructor },
     { &kNS_JARPROTOCOLHANDLER_CID, false, nullptr, nsJARProtocolHandlerConstructor },
     { &kNS_JARURI_CID, false, nullptr, nsJARURIConstructor },
+    { &kNS_JARURIMUTATOR_CID, false, nullptr, nsJARURIMutatorConstructor },
     { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kJARContracts[] = {
     { "@mozilla.org/libjar/zip-reader;1", &kNS_ZIPREADER_CID },
     { "@mozilla.org/libjar/zip-reader-cache;1", &kNS_ZIPREADERCACHE_CID },
     { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "jar", &kNS_JARPROTOCOLHANDLER_CID },
     { nullptr }
--- a/modules/libjar/nsJARURI.cpp
+++ b/modules/libjar/nsJARURI.cpp
@@ -259,16 +259,30 @@ nsJARURI::GetHasRef(bool *result)
 }
 
 NS_IMETHODIMP
 nsJARURI::SetSpec(const nsACString& aSpec)
 {
     return SetSpecWithBase(aSpec, nullptr);
 }
 
+NS_IMPL_ISUPPORTS(nsJARURI::Mutator, nsIURISetters, nsIURIMutator)
+
+NS_IMETHODIMP
+nsJARURI::Mutate(nsIURIMutator** aMutator)
+{
+    RefPtr<nsJARURI::Mutator> mutator = new nsJARURI::Mutator();
+    nsresult rv = mutator->InitFromURI(this);
+    if (NS_FAILED(rv)) {
+        return rv;
+    }
+    mutator.forget(aMutator);
+    return NS_OK;
+}
+
 nsresult
 nsJARURI::SetSpecWithBase(const nsACString &aSpec, nsIURI* aBaseURL)
 {
     nsresult rv;
 
     nsCOMPtr<nsIIOService> ioServ(do_GetIOService(&rv));
     NS_ENSURE_SUCCESS(rv, rv);
 
--- a/modules/libjar/nsJARURI.h
+++ b/modules/libjar/nsJARURI.h
@@ -9,16 +9,17 @@
 
 #include "nsIJARURI.h"
 #include "nsISerializable.h"
 #include "nsIClassInfo.h"
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsINestedURI.h"
 #include "nsIIPCSerializableURI.h"
+#include "nsIURIMutator.h"
 
 #define NS_THIS_JARURI_IMPL_CID                      \
 { /* 9a55f629-730b-4d08-b75b-fa7d9570a691 */         \
     0x9a55f629,                                      \
     0x730b,                                          \
     0x4d08,                                          \
     {0xb7, 0x5b, 0xfa, 0x7d, 0x95, 0x70, 0xa6, 0x91} \
 }
@@ -26,16 +27,23 @@
 #define NS_JARURI_CID                                \
 { /* 245abae2-b947-4ded-a46d-9829d3cca462 */         \
     0x245abae2,                                      \
     0xb947,                                          \
     0x4ded,                                          \
     {0xa4, 0x6d, 0x98, 0x29, 0xd3, 0xcc, 0xa4, 0x62} \
 }
 
+#define NS_JARURIMUTATOR_CID                         \
+{ /* 19d9161b-a2a9-4518-b2c9-fcb8296d6dcd */         \
+    0x19d9161b,                                      \
+    0xa2a9,                                          \
+    0x4518,                                          \
+    {0xb2, 0xc9, 0xfc, 0xb8, 0x29, 0x6d, 0x6d, 0xcd} \
+}
 
 class nsJARURI final : public nsIJARURI,
                        public nsISerializable,
                        public nsIClassInfo,
                        public nsINestedURI,
                        public nsIIPCSerializableURI
 {
 public:
@@ -84,13 +92,29 @@ protected:
                                       RefHandlingEnum refHandlingMode,
                                       const nsACString& newRef,
                                       nsIJARURI **result);
     nsCOMPtr<nsIURI> mJARFile;
     // mJarEntry stored as a URL so that we can easily access things
     // like extensions, refs, etc.
     nsCOMPtr<nsIURL> mJAREntry;
     nsCString        mCharsetHint;
+
+public:
+    class Mutator
+        : public nsIURIMutator
+        , public BaseURIMutator<nsJARURI>
+    {
+        NS_DECL_ISUPPORTS
+        NS_FORWARD_SAFE_NSIURISETTERS(mURI)
+        NS_DEFINE_NSIMUTATOR_COMMON
+
+        explicit Mutator() { }
+    private:
+        virtual ~Mutator() { }
+
+        friend class nsJARURI;
+    };
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsJARURI, NS_THIS_JARURI_IMPL_CID)
 
 #endif // nsJARURI_h__
--- a/netwerk/base/nsIURIMutator.idl
+++ b/netwerk/base/nsIURIMutator.idl
@@ -1,33 +1,120 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 "nsISupports.idl"
 interface nsIURI;
+interface nsIObjectInputStream;
 
 %{C++
 #include "nsStringGlue.h"
 
-#undef GetPort  // XXX Windows!
 #undef SetPort  // XXX Windows!
 
 namespace mozilla {
 class Encoding;
 }
+
+
+namespace mozilla {
+namespace ipc {
+class URIParams;
+} // namespace ipc
+} // namespace mozilla
+
+template <class T>
+class BaseURIMutator
+{
+// This is the base class that can be extended by implementors of nsIURIMutator
+// in order to avoid code duplication
+// Class type T should be the type of the class that implements nsIURI
+protected:
+    nsresult InitFromURI(T* aURI)
+    {
+        nsCOMPtr<nsIURI> clone;
+        nsresult rv = aURI->Clone(getter_AddRefs(clone));
+        if (NS_FAILED(rv)) {
+            return rv;
+        }
+        mURI = static_cast<T*>(clone.get());
+        return NS_OK;
+    }
+
+    nsresult InitFromInputStream(nsIObjectInputStream* aStream)
+    {
+        RefPtr<T> uri = new T();
+        nsresult rv = uri->Read(aStream);
+        if (NS_FAILED(rv)) {
+            return rv;
+        }
+        mURI = uri;
+        return NS_OK;
+    }
+
+    nsresult InitFromIPCParams(const mozilla::ipc::URIParams& aParams)
+    {
+        RefPtr<T> uri = new T();
+        bool ret = uri->Deserialize(aParams);
+        if (!ret) {
+          return NS_ERROR_FAILURE;
+        }
+        mURI = uri;
+        return NS_OK;
+    }
+
+    nsresult InitFromSpec(const nsACString& aSpec)
+    {
+        RefPtr<T> uri = new T();
+        nsresult rv = uri->SetSpec(aSpec);
+        if (NS_FAILED(rv)) {
+          return rv;
+        }
+        mURI = uri;
+        return NS_OK;
+    }
+
+    RefPtr<T> mURI;
+};
+
+// Since most implementations of nsIURIMutator would extend BaseURIMutator,
+// some methods would have the same implementation. We provide a useful macro
+// to avoid code duplication.
+#define NS_DEFINE_NSIMUTATOR_COMMON                                           \
+  NS_IMETHOD Deserialize(const mozilla::ipc::URIParams& aParams) override     \
+    { return InitFromIPCParams(aParams); }                                    \
+  NS_IMETHOD Read(nsIObjectInputStream* aStream) override                     \
+    { return InitFromInputStream(aStream); }                                  \
+  NS_IMETHOD Finalize(nsIURI** aURI) override                                 \
+    { mURI.forget(aURI); return NS_OK; }                                      \
+  NS_IMETHOD SetSpec(const nsACString & aSpec) override                       \
+    { return InitFromSpec(aSpec); }
+
 %}
 
 [ptr] native Encoding(const mozilla::Encoding);
+[ref] native const_URIParams_ref(const mozilla::ipc::URIParams);
+
+[scriptable, builtinclass, uuid(1fc53257-898b-4c5e-b69c-05bc84b4cd8f)]
+interface nsIURISetSpec : nsISupports
+{
+  /**
+   * This setter is different from all other setters because it may be used to
+   * initialize the object. We define it separately allowing mutator implementors
+   * to define it separately, while the rest of the setters may be simply
+   * forwarded to the mutable URI.
+   */
+  void setSpec(in AUTF8String aSpec);
+};
 
 [scriptable, builtinclass, uuid(5403a6ec-99d7-405e-8b45-9f805bbdfcef)]
-interface nsIURISetters : nsISupports
+interface nsIURISetters : nsIURISetSpec
 {
-  void setSpec(in AUTF8String aSpec);
   void setScheme(in AUTF8String aScheme);
   void setUserPass(in AUTF8String aUserPass);
   void setUsername(in AUTF8String aUsername);
   void setPassword(in AUTF8String aPassword);
   void setHostPort(in AUTF8String aHostPort);
   void setHostAndPort(in AUTF8String aHostAndPort);
   void setHost(in AUTF8String aHost);
   void setPort(in long aPort);
@@ -36,10 +123,28 @@ interface nsIURISetters : nsISupports
   void setFilePath(in AUTF8String aFilePath);
   void setQuery(in AUTF8String aQuery);
   [noscript] void setQueryWithEncoding(in AUTF8String query, in Encoding encoding);
 };
 
 [scriptable, builtinclass, uuid(4d1f3103-1c44-4dcd-b717-5d22a697a7d9)]
 interface nsIURIMutator : nsIURISetters
 {
+  /**
+   * Initializes the URI by reading from the input stream.
+   * The input stream must contain the serialization of the same object type.
+   * See nsISerializable.
+   */
+  void read(in nsIObjectInputStream aInputStream);
+
+  /**
+   * Initalizes the URI by reading IPC URIParams.
+   * See nsIIPCSerializableURI.
+   */
+  [noscript, notxpcom]
+  nsresult deserialize(in const_URIParams_ref aParams);
+
+  /**
+   * Finishes changing or constructing the URI and returns an immutable URI.
+   */
   nsIURI finalize();
 };
+
--- a/netwerk/base/nsSimpleNestedURI.cpp
+++ b/netwerk/base/nsSimpleNestedURI.cpp
@@ -181,10 +181,24 @@ NS_IMETHODIMP
 nsSimpleNestedURI::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
 {
     static NS_DEFINE_CID(kSimpleNestedURICID, NS_SIMPLENESTEDURI_CID);
 
     *aClassIDNoAlloc = kSimpleNestedURICID;
     return NS_OK;
 }
 
+NS_IMPL_ISUPPORTS(nsSimpleNestedURI::Mutator, nsIURISetters, nsIURIMutator)
+
+NS_IMETHODIMP
+nsSimpleNestedURI::Mutate(nsIURIMutator** aMutator)
+{
+    RefPtr<nsSimpleNestedURI::Mutator> mutator = new nsSimpleNestedURI::Mutator();
+    nsresult rv = mutator->InitFromURI(this);
+    if (NS_FAILED(rv)) {
+        return rv;
+    }
+    mutator.forget(aMutator);
+    return NS_OK;
+}
+
 } // namespace net
 } // namespace mozilla
--- a/netwerk/base/nsSimpleNestedURI.h
+++ b/netwerk/base/nsSimpleNestedURI.h
@@ -14,16 +14,17 @@
  */
 
 #ifndef nsSimpleNestedURI_h__
 #define nsSimpleNestedURI_h__
 
 #include "nsCOMPtr.h"
 #include "nsSimpleURI.h"
 #include "nsINestedURI.h"
+#include "nsIURIMutator.h"
 
 #include "nsIIPCSerializableURI.h"
 
 namespace mozilla {
 namespace net {
 
 class nsSimpleNestedURI : public nsSimpleURI,
                           public nsINestedURI
@@ -48,28 +49,46 @@ public:
     // Overrides for various methods nsSimpleURI implements follow.
 
     // nsSimpleURI overrides
     virtual nsresult EqualsInternal(nsIURI* other,
                                     RefHandlingEnum refHandlingMode,
                                     bool* result) override;
     virtual nsSimpleURI* StartClone(RefHandlingEnum refHandlingMode,
                                     const nsACString& newRef) override;
+    NS_IMETHOD Mutate(nsIURIMutator * *_retval) override;
 
     // nsISerializable overrides
     NS_IMETHOD Read(nsIObjectInputStream* aStream) override;
     NS_IMETHOD Write(nsIObjectOutputStream* aStream) override;
 
     // nsIIPCSerializableURI overrides
     NS_DECL_NSIIPCSERIALIZABLEURI
 
     // Override the nsIClassInfo method GetClassIDNoAlloc to make sure our
     // nsISerializable impl works right.
     NS_IMETHOD GetClassIDNoAlloc(nsCID *aClassIDNoAlloc) override;
 
 protected:
     nsCOMPtr<nsIURI> mInnerURI;
+
+
+public:
+    class Mutator
+        : public nsIURIMutator
+        , public BaseURIMutator<nsSimpleNestedURI>
+    {
+        NS_DECL_ISUPPORTS
+        NS_FORWARD_SAFE_NSIURISETTERS(mURI)
+        NS_DEFINE_NSIMUTATOR_COMMON
+
+        explicit Mutator() { }
+    private:
+        virtual ~Mutator() { }
+
+        friend class nsSimpleNestedURI;
+    };
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif /* nsSimpleNestedURI_h__ */
--- a/netwerk/base/nsSimpleURI.cpp
+++ b/netwerk/base/nsSimpleURI.cpp
@@ -16,16 +16,17 @@
 #include "nsNetCID.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 #include "nsEscape.h"
 #include "nsError.h"
 #include "nsIIPCSerializableURI.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/ipc/URIUtils.h"
+#include "nsIURIMutator.h"
 
 using namespace mozilla::ipc;
 
 namespace mozilla {
 namespace net {
 
 static NS_DEFINE_CID(kThisSimpleURIImplementationCID,
                      NS_THIS_SIMPLEURI_IMPLEMENTATION_CID);
@@ -878,10 +879,25 @@ nsSimpleURI::SetQuery(const nsACString& 
 
 NS_IMETHODIMP
 nsSimpleURI::SetQueryWithEncoding(const nsACString& aQuery,
                                   const Encoding* aEncoding)
 {
     return SetQuery(aQuery);
 }
 
+NS_IMPL_ISUPPORTS(nsSimpleURI::Mutator, nsIURISetters, nsIURIMutator)
+
+
+NS_IMETHODIMP
+nsSimpleURI::Mutate(nsIURIMutator** aMutator)
+{
+    RefPtr<nsSimpleURI::Mutator> mutator = new nsSimpleURI::Mutator();
+    nsresult rv = mutator->InitFromURI(this);
+    if (NS_FAILED(rv)) {
+        return rv;
+    }
+    mutator.forget(aMutator);
+    return NS_OK;
+}
+
 } // namespace net
 } // namespace mozilla
--- a/netwerk/base/nsSimpleURI.h
+++ b/netwerk/base/nsSimpleURI.h
@@ -9,16 +9,17 @@
 #include "mozilla/MemoryReporting.h"
 #include "nsIURI.h"
 #include "nsISerializable.h"
 #include "nsString.h"
 #include "nsIClassInfo.h"
 #include "nsIMutable.h"
 #include "nsISizeOf.h"
 #include "nsIIPCSerializableURI.h"
+#include "nsIURIMutator.h"
 
 namespace mozilla {
 namespace net {
 
 #define NS_THIS_SIMPLEURI_IMPLEMENTATION_CID         \
 { /* 0b9bb0c2-fee6-470b-b9b9-9fd9462b5e19 */         \
     0x0b9bb0c2,                                      \
     0xfee6,                                          \
@@ -104,14 +105,31 @@ protected:
 
     nsCString mScheme;
     nsCString mPath; // NOTE: mPath does not include ref, as an optimization
     nsCString mRef;  // so that URIs with different refs can share string data.
     nsCString mQuery;  // so that URLs with different querys can share string data.
     bool mMutable;
     bool mIsRefValid; // To distinguish between empty-ref and no-ref.
     bool mIsQueryValid; // To distinguish between empty-query and no-query.
+
+
+public:
+    class Mutator
+        : public nsIURIMutator
+        , public BaseURIMutator<nsSimpleURI>
+    {
+        NS_DECL_ISUPPORTS
+        NS_FORWARD_SAFE_NSIURISETTERS(mURI)
+        NS_DEFINE_NSIMUTATOR_COMMON
+
+        explicit Mutator() { }
+    private:
+        virtual ~Mutator() { }
+
+        friend class nsSimpleURI;
+    };
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // nsSimpleURI_h__
--- a/netwerk/base/nsStandardURL.cpp
+++ b/netwerk/base/nsStandardURL.cpp
@@ -2221,16 +2221,30 @@ nsStandardURL::SetPathQueryRef(const nsA
         mBasename.mLen = -1;
         mExtension.mLen = -1;
         mQuery.mLen = -1;
         mRef.mLen = -1;
     }
     return NS_OK;
 }
 
+NS_IMPL_ISUPPORTS(nsStandardURL::Mutator, nsIURISetters, nsIURIMutator)
+
+NS_IMETHODIMP
+nsStandardURL::Mutate(nsIURIMutator** aMutator)
+{
+    RefPtr<nsStandardURL::Mutator> mutator = new nsStandardURL::Mutator();
+    nsresult rv = mutator->InitFromURI(this);
+    if (NS_FAILED(rv)) {
+        return rv;
+    }
+    mutator.forget(aMutator);
+    return NS_OK;
+}
+
 NS_IMETHODIMP
 nsStandardURL::Equals(nsIURI *unknownOther, bool *result)
 {
     return EqualsInternal(unknownOther, eHonorRef, result);
 }
 
 NS_IMETHODIMP
 nsStandardURL::EqualsExceptRef(nsIURI *unknownOther, bool *result)
--- a/netwerk/base/nsStandardURL.h
+++ b/netwerk/base/nsStandardURL.h
@@ -16,16 +16,17 @@
 #include "nsURLHelper.h"
 #include "nsIClassInfo.h"
 #include "nsISizeOf.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/MemoryReporting.h"
 #include "nsIIPCSerializableURI.h"
 #include "nsISensitiveInfoHiddenURI.h"
+#include "nsIURIMutator.h"
 
 #ifdef NS_BUILD_REFCNT_LOGGING
 #define DEBUG_DUMP_URLS_AT_SHUTDOWN
 #endif
 
 class nsIBinaryInputStream;
 class nsIBinaryOutputStream;
 class nsIIDNService;
@@ -305,16 +306,32 @@ private:
     static const char                   gHostLimitDigits[];
     static bool                         gInitialized;
     static bool                         gPunycodeHost;
 
 public:
 #ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
     void PrintSpec() const { printf("  %s\n", mSpec.get()); }
 #endif
+
+public:
+    class Mutator
+        : public nsIURIMutator
+        , public BaseURIMutator<nsStandardURL>
+    {
+        NS_DECL_ISUPPORTS
+        NS_FORWARD_SAFE_NSIURISETTERS(mURI)
+        NS_DEFINE_NSIMUTATOR_COMMON
+
+        explicit Mutator() { }
+    private:
+        virtual ~Mutator() { }
+
+        friend class nsStandardURL;
+    };
 };
 
 #define NS_THIS_STANDARDURL_IMPL_CID                 \
 { /* b8e3e97b-1ccd-4b45-af5a-79596770f5d7 */         \
     0xb8e3e97b,                                      \
     0x1ccd,                                          \
     0x4b45,                                          \
     {0xaf, 0x5a, 0x79, 0x59, 0x67, 0x70, 0xf5, 0xd7} \
--- a/netwerk/build/nsNetCID.h
+++ b/netwerk/build/nsNetCID.h
@@ -76,16 +76,26 @@
 #define NS_SIMPLEURI_CID                              \
 { /* e0da1d70-2f7b-11d3-8cd0-0060b0fc14a3 */          \
      0xe0da1d70,                                      \
      0x2f7b,                                          \
      0x11d3,                                          \
      {0x8c, 0xd0, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3} \
 }
 
+#define NS_SIMPLEURIMUTATOR_CONTRACTID \
+    "@mozilla.org/network/simple-uri-mutator;1"
+#define NS_SIMPLEURIMUTATOR_CID                       \
+{ /* 2be14592-28d4-4a83-8fe9-08e778849f6e */          \
+     0x2be14592,                                      \
+     0x28d4,                                          \
+     0x4a83,                                          \
+     {0x8f, 0xe9, 0x08, 0xe7, 0x78, 0x84, 0x9f, 0x6e} \
+}
+
 // component inheriting from the simple URI component and also
 // implementing nsINestedURI.
 #define NS_SIMPLENESTEDURI_CID                           \
 { /* 56388dad-287b-4240-a785-85c394012503 */             \
      0x56388dad,                                         \
      0x287b,                                             \
      0x4240,                                             \
      { 0xa7, 0x85, 0x85, 0xc3, 0x94, 0x01, 0x25, 0x03 }  \
@@ -108,16 +118,26 @@
 #define NS_STANDARDURL_CID                           \
 { /* de9472d0-8034-11d3-9399-00104ba0fd40 */         \
     0xde9472d0,                                      \
     0x8034,                                          \
     0x11d3,                                          \
     {0x93, 0x99, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \
 }
 
+#define NS_STANDARDURLMUTATOR_CONTRACTID \
+    "@mozilla.org/network/standard-url-mutator;1"
+#define NS_STANDARDURLMUTATOR_CID                    \
+{ /* ce7d7da0-fb28-44a3-8c7b-000c165918f4 */         \
+    0xce7d7da0,                                      \
+    0xfb28,                                          \
+    0x44a3,                                          \
+    {0x8c, 0x7b, 0x00, 0x0c, 0x16, 0x59, 0x18, 0xf4} \
+}
+
 // service implementing nsIURLParser that assumes the URL will NOT contain an
 // authority section.
 #define NS_NOAUTHURLPARSER_CONTRACTID \
     "@mozilla.org/network/url-parser;1?auth=no"
 #define NS_NOAUTHURLPARSER_CID                       \
 { /* 78804a84-8173-42b6-bb94-789f0816a810 */         \
     0x78804a84,                                      \
     0x8173,                                          \
--- a/netwerk/build/nsNetModule.cpp
+++ b/netwerk/build/nsNetModule.cpp
@@ -360,18 +360,22 @@ WEB_SOCKET_HANDLER_CONSTRUCTOR(WebSocket
 #include "nsURLParsers.h"
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsNoAuthURLParser)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsAuthURLParser)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsStdURLParser)
 
 #include "nsStandardURL.h"
 typedef mozilla::net::nsStandardURL nsStandardURL;
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsStandardURL)
+typedef mozilla::net::nsStandardURL::Mutator nsStandardURLMutator;
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsStandardURLMutator)
 typedef mozilla::net::nsSimpleURI nsSimpleURI;
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSimpleURI)
+typedef mozilla::net::nsSimpleURI::Mutator nsSimpleURIMutator;
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsSimpleURIMutator)
 
 typedef mozilla::net::nsSimpleNestedURI nsSimpleNestedURI;
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSimpleNestedURI)
 
 ///////////////////////////////////////////////////////////////////////////////
 
 #include "nsIDNService.h"
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsIDNService, Init)
@@ -670,16 +674,17 @@ NS_DEFINE_NAMED_CID(NS_SOCKETTRANSPORTSE
 NS_DEFINE_NAMED_CID(NS_SERVERSOCKET_CID);
 NS_DEFINE_NAMED_CID(NS_TLSSERVERSOCKET_CID);
 NS_DEFINE_NAMED_CID(NS_UDPSOCKET_CID);
 NS_DEFINE_NAMED_CID(NS_SOCKETPROVIDERSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_DNSSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_IDNSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_EFFECTIVETLDSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_SIMPLEURI_CID);
+NS_DEFINE_NAMED_CID(NS_SIMPLEURIMUTATOR_CID);
 NS_DEFINE_NAMED_CID(NS_SIMPLENESTEDURI_CID);
 NS_DEFINE_NAMED_CID(NS_ASYNCSTREAMCOPIER_CID);
 NS_DEFINE_NAMED_CID(NS_INPUTSTREAMPUMP_CID);
 NS_DEFINE_NAMED_CID(NS_INPUTSTREAMCHANNEL_CID);
 NS_DEFINE_NAMED_CID(NS_STREAMLOADER_CID);
 NS_DEFINE_NAMED_CID(NS_INCREMENTALSTREAMLOADER_CID);
 NS_DEFINE_NAMED_CID(NS_UNICHARSTREAMLOADER_CID);
 NS_DEFINE_NAMED_CID(NS_DOWNLOADER_CID);
@@ -695,16 +700,17 @@ NS_DEFINE_NAMED_CID(NS_LOCALFILEOUTPUTST
 NS_DEFINE_NAMED_CID(NS_ATOMICLOCALFILEOUTPUTSTREAM_CID);
 NS_DEFINE_NAMED_CID(NS_SAFELOCALFILEOUTPUTSTREAM_CID);
 NS_DEFINE_NAMED_CID(NS_LOCALFILESTREAM_CID);
 NS_DEFINE_NAMED_CID(NS_INCREMENTALDOWNLOAD_CID);
 NS_DEFINE_NAMED_CID(NS_STDURLPARSER_CID);
 NS_DEFINE_NAMED_CID(NS_NOAUTHURLPARSER_CID);
 NS_DEFINE_NAMED_CID(NS_AUTHURLPARSER_CID);
 NS_DEFINE_NAMED_CID(NS_STANDARDURL_CID);
+NS_DEFINE_NAMED_CID(NS_STANDARDURLMUTATOR_CID);
 NS_DEFINE_NAMED_CID(NS_ARRAYBUFFERINPUTSTREAM_CID);
 NS_DEFINE_NAMED_CID(NS_BUFFEREDINPUTSTREAM_CID);
 NS_DEFINE_NAMED_CID(NS_BUFFEREDOUTPUTSTREAM_CID);
 NS_DEFINE_NAMED_CID(NS_MIMEINPUTSTREAM_CID);
 NS_DEFINE_NAMED_CID(NS_PROTOCOLPROXYSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_STREAMCONVERTERSERVICE_CID);
 #if defined(XP_WIN)
 NS_DEFINE_NAMED_CID(NS_NAMEDPIPESERVICE_CID);
@@ -788,16 +794,17 @@ static const mozilla::Module::CIDEntry k
     { &kNS_SERVERSOCKET_CID, false, nullptr, nsServerSocketConstructor },
     { &kNS_TLSSERVERSOCKET_CID, false, nullptr, TLSServerSocketConstructor },
     { &kNS_UDPSOCKET_CID, false, nullptr, nsUDPSocketConstructor },
     { &kNS_SOCKETPROVIDERSERVICE_CID, false, nullptr, nsSocketProviderService::Create },
     { &kNS_DNSSERVICE_CID, false, nullptr, nsIDNSServiceConstructor },
     { &kNS_IDNSERVICE_CID, false, nullptr, nsIDNServiceConstructor },
     { &kNS_EFFECTIVETLDSERVICE_CID, false, nullptr, nsEffectiveTLDServiceConstructor },
     { &kNS_SIMPLEURI_CID, false, nullptr, nsSimpleURIConstructor },
+    { &kNS_SIMPLEURIMUTATOR_CID, false, nullptr, nsSimpleURIMutatorConstructor },
     { &kNS_SIMPLENESTEDURI_CID, false, nullptr, nsSimpleNestedURIConstructor },
     { &kNS_ASYNCSTREAMCOPIER_CID, false, nullptr, nsAsyncStreamCopierConstructor },
     { &kNS_INPUTSTREAMPUMP_CID, false, nullptr, nsInputStreamPumpConstructor },
     { &kNS_INPUTSTREAMCHANNEL_CID, false, nullptr, nsInputStreamChannelConstructor },
     { &kNS_STREAMLOADER_CID, false, nullptr, mozilla::net::nsStreamLoader::Create },
     { &kNS_INCREMENTALSTREAMLOADER_CID, false, nullptr, nsIncrementalStreamLoader::Create },
     { &kNS_UNICHARSTREAMLOADER_CID, false, nullptr, nsUnicharStreamLoader::Create },
     { &kNS_DOWNLOADER_CID, false, nullptr, nsDownloaderConstructor },
@@ -815,16 +822,17 @@ static const mozilla::Module::CIDEntry k
     { &kNS_ATOMICLOCALFILEOUTPUTSTREAM_CID, false, nullptr, nsAtomicFileOutputStreamConstructor },
     { &kNS_SAFELOCALFILEOUTPUTSTREAM_CID, false, nullptr, nsSafeFileOutputStreamConstructor },
     { &kNS_LOCALFILESTREAM_CID, false, nullptr, nsFileStreamConstructor },
     { &kNS_INCREMENTALDOWNLOAD_CID, false, nullptr, net_NewIncrementalDownload },
     { &kNS_STDURLPARSER_CID, false, nullptr, nsStdURLParserConstructor },
     { &kNS_NOAUTHURLPARSER_CID, false, nullptr, nsNoAuthURLParserConstructor },
     { &kNS_AUTHURLPARSER_CID, false, nullptr, nsAuthURLParserConstructor },
     { &kNS_STANDARDURL_CID, false, nullptr, nsStandardURLConstructor },
+    { &kNS_STANDARDURLMUTATOR_CID, false, nullptr, nsStandardURLMutatorConstructor },
     { &kNS_ARRAYBUFFERINPUTSTREAM_CID, false, nullptr, ArrayBufferInputStreamConstructor },
     { &kNS_BUFFEREDINPUTSTREAM_CID, false, nullptr, nsBufferedInputStream::Create },
     { &kNS_BUFFEREDOUTPUTSTREAM_CID, false, nullptr, nsBufferedOutputStream::Create },
     { &kNS_MIMEINPUTSTREAM_CID, false, nullptr, nsMIMEInputStreamConstructor },
     { &kNS_PROTOCOLPROXYSERVICE_CID, true, nullptr, nsProtocolProxyServiceConstructor },
     { &kNS_STREAMCONVERTERSERVICE_CID, false, nullptr, CreateNewStreamConvServiceFactory },
 #if defined (XP_WIN)
     { &kNS_NAMEDPIPESERVICE_CID, false, NULL, mozilla::net::NamedPipeServiceConstructor },
@@ -913,16 +921,17 @@ static const mozilla::Module::ContractID
     { NS_SERVERSOCKET_CONTRACTID, &kNS_SERVERSOCKET_CID },
     { NS_TLSSERVERSOCKET_CONTRACTID, &kNS_TLSSERVERSOCKET_CID },
     { NS_UDPSOCKET_CONTRACTID, &kNS_UDPSOCKET_CID },
     { NS_SOCKETPROVIDERSERVICE_CONTRACTID, &kNS_SOCKETPROVIDERSERVICE_CID },
     { NS_DNSSERVICE_CONTRACTID, &kNS_DNSSERVICE_CID },
     { NS_IDNSERVICE_CONTRACTID, &kNS_IDNSERVICE_CID },
     { NS_EFFECTIVETLDSERVICE_CONTRACTID, &kNS_EFFECTIVETLDSERVICE_CID },
     { NS_SIMPLEURI_CONTRACTID, &kNS_SIMPLEURI_CID },
+    { NS_SIMPLEURIMUTATOR_CONTRACTID, &kNS_SIMPLEURIMUTATOR_CID },
     { NS_ASYNCSTREAMCOPIER_CONTRACTID, &kNS_ASYNCSTREAMCOPIER_CID },
     { NS_INPUTSTREAMPUMP_CONTRACTID, &kNS_INPUTSTREAMPUMP_CID },
     { NS_INPUTSTREAMCHANNEL_CONTRACTID, &kNS_INPUTSTREAMCHANNEL_CID },
     { NS_STREAMLOADER_CONTRACTID, &kNS_STREAMLOADER_CID },
     { NS_INCREMENTALSTREAMLOADER_CONTRACTID, &kNS_INCREMENTALSTREAMLOADER_CID },
     { NS_UNICHARSTREAMLOADER_CONTRACTID, &kNS_UNICHARSTREAMLOADER_CID },
     { NS_DOWNLOADER_CONTRACTID, &kNS_DOWNLOADER_CID },
     { NS_BACKGROUNDFILESAVEROUTPUTSTREAM_CONTRACTID, &kNS_BACKGROUNDFILESAVEROUTPUTSTREAM_CID },
@@ -937,16 +946,17 @@ static const mozilla::Module::ContractID
     { NS_ATOMICLOCALFILEOUTPUTSTREAM_CONTRACTID, &kNS_ATOMICLOCALFILEOUTPUTSTREAM_CID },
     { NS_SAFELOCALFILEOUTPUTSTREAM_CONTRACTID, &kNS_SAFELOCALFILEOUTPUTSTREAM_CID },
     { NS_LOCALFILESTREAM_CONTRACTID, &kNS_LOCALFILESTREAM_CID },
     { NS_INCREMENTALDOWNLOAD_CONTRACTID, &kNS_INCREMENTALDOWNLOAD_CID },
     { NS_STDURLPARSER_CONTRACTID, &kNS_STDURLPARSER_CID },
     { NS_NOAUTHURLPARSER_CONTRACTID, &kNS_NOAUTHURLPARSER_CID },
     { NS_AUTHURLPARSER_CONTRACTID, &kNS_AUTHURLPARSER_CID },
     { NS_STANDARDURL_CONTRACTID, &kNS_STANDARDURL_CID },
+    { NS_STANDARDURLMUTATOR_CONTRACTID, &kNS_STANDARDURLMUTATOR_CID },
     { NS_ARRAYBUFFERINPUTSTREAM_CONTRACTID, &kNS_ARRAYBUFFERINPUTSTREAM_CID },
     { NS_BUFFEREDINPUTSTREAM_CONTRACTID, &kNS_BUFFEREDINPUTSTREAM_CID },
     { NS_BUFFEREDOUTPUTSTREAM_CONTRACTID, &kNS_BUFFEREDOUTPUTSTREAM_CID },
     { NS_MIMEINPUTSTREAM_CONTRACTID, &kNS_MIMEINPUTSTREAM_CID },
     { NS_PROTOCOLPROXYSERVICE_CONTRACTID, &kNS_PROTOCOLPROXYSERVICE_CID },
     { NS_STREAMCONVERTERSERVICE_CONTRACTID, &kNS_STREAMCONVERTERSERVICE_CID },
 #if defined(XP_WIN)
     { NS_NAMEDPIPESERVICE_CONTRACTID, &kNS_NAMEDPIPESERVICE_CID },
--- a/netwerk/protocol/about/nsAboutProtocolHandler.cpp
+++ b/netwerk/protocol/about/nsAboutProtocolHandler.cpp
@@ -422,16 +422,30 @@ nsNestedAboutURI::StartClone(nsSimpleURI
 
     nsNestedAboutURI* url = new nsNestedAboutURI(innerClone, mBaseURI);
     SetRefOnClone(url, aRefHandlingMode, aNewRef);
     url->SetMutable(false);
 
     return url;
 }
 
+NS_IMPL_ISUPPORTS(nsNestedAboutURI::Mutator, nsIURISetters, nsIURIMutator)
+
+NS_IMETHODIMP
+nsNestedAboutURI::Mutate(nsIURIMutator** aMutator)
+{
+    RefPtr<nsNestedAboutURI::Mutator> mutator = new nsNestedAboutURI::Mutator();
+    nsresult rv = mutator->InitFromURI(this);
+    if (NS_FAILED(rv)) {
+        return rv;
+    }
+    mutator.forget(aMutator);
+    return NS_OK;
+}
+
 // nsIClassInfo
 NS_IMETHODIMP
 nsNestedAboutURI::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
 {
     *aClassIDNoAlloc = kNestedAboutURICID;
     return NS_OK;
 }
 
--- a/netwerk/protocol/about/nsAboutProtocolHandler.h
+++ b/netwerk/protocol/about/nsAboutProtocolHandler.h
@@ -5,16 +5,17 @@
 
 #ifndef nsAboutProtocolHandler_h___
 #define nsAboutProtocolHandler_h___
 
 #include "nsIProtocolHandler.h"
 #include "nsSimpleNestedURI.h"
 #include "nsWeakReference.h"
 #include "mozilla/Attributes.h"
+#include "nsIURIMutator.h"
 
 class nsIURI;
 
 namespace mozilla {
 namespace net {
 
 class nsAboutProtocolHandler : public nsIProtocolHandlerWithDynamicFlags
                              , public nsIProtocolHandler
@@ -60,31 +61,49 @@ public:
     {}
 
     // For use only from deserialization
     nsNestedAboutURI() : nsSimpleNestedURI() {}
 
     virtual ~nsNestedAboutURI() {}
 
     // Override QI so we can QI to our CID as needed
-    NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
+    NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
 
     // Override StartClone(), the nsISerializable methods, and
     // GetClassIDNoAlloc; this last is needed to make our nsISerializable impl
     // work right.
     virtual nsSimpleURI* StartClone(RefHandlingEnum aRefHandlingMode,
-                                    const nsACString& newRef);
-    NS_IMETHOD Read(nsIObjectInputStream* aStream);
-    NS_IMETHOD Write(nsIObjectOutputStream* aStream);
-    NS_IMETHOD GetClassIDNoAlloc(nsCID *aClassIDNoAlloc);
+                                    const nsACString& newRef) override;
+    NS_IMETHOD Mutate(nsIURIMutator * *_retval) override;
+
+    NS_IMETHOD Read(nsIObjectInputStream* aStream) override;
+    NS_IMETHOD Write(nsIObjectOutputStream* aStream) override;
+    NS_IMETHOD GetClassIDNoAlloc(nsCID *aClassIDNoAlloc) override;
 
     nsIURI* GetBaseURI() const {
         return mBaseURI;
     }
 
 protected:
     nsCOMPtr<nsIURI> mBaseURI;
+
+public:
+    class Mutator
+        : public nsIURIMutator
+        , public BaseURIMutator<nsNestedAboutURI>
+    {
+        NS_DECL_ISUPPORTS
+        NS_FORWARD_SAFE_NSIURISETTERS(mURI)
+        NS_DEFINE_NSIMUTATOR_COMMON
+
+        explicit Mutator() { }
+    private:
+        virtual ~Mutator() { }
+
+        friend class nsNestedAboutURI;
+    };
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif /* nsAboutProtocolHandler_h___ */