Bug 1415205 - Add nsIURIMutator impls for all objects implementing nsIURI r=bagder draft
authorValentin Gosu <valentin.gosu@gmail.com>
Mon, 20 Nov 2017 17:11:30 +0100
changeset 701160 e146624c5ae423f7f69a738aaaafaa55dd0940d9
parent 701159 7deeb367424056f3e86bf42e77326bf1414a809a
child 741108 21a625a4da601851ed4df31c2a2b7bbd84d9cd6b
push id90095
push uservalentin.gosu@gmail.com
push dateTue, 21 Nov 2017 09:46:06 +0000
reviewersbagder
bugs1415205
milestone59.0a1
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___ */