Bug 1420954 - Make nsIURIMutator setters return nsIURIMutator so we can chain setters r=bagder draft
authorValentin Gosu <valentin.gosu@gmail.com>
Tue, 05 Dec 2017 02:35:21 +0100
changeset 707699 3c4f5b9ad8820353ae108b982026048dbf599d95
parent 707235 e19b017880c8d71385aed453bacbe2b473757e90
child 707700 ba9b5cde71ce851762db2704b0142552ef75e9d3
push id92189
push uservalentin.gosu@gmail.com
push dateTue, 05 Dec 2017 16:58:00 +0000
reviewersbagder
bugs1420954
milestone59.0a1
Bug 1420954 - Make nsIURIMutator setters return nsIURIMutator so we can chain setters r=bagder MozReview-Commit-ID: 53BD91hB2yi
caps/NullPrincipalURI.h
dom/file/nsHostObjectURI.h
dom/jsurl/nsJSProtocolHandler.h
image/decoders/icon/nsIconURI.h
modules/libjar/nsJARURI.h
netwerk/base/nsIURIMutator.idl
netwerk/base/nsSimpleNestedURI.h
netwerk/base/nsSimpleURI.h
netwerk/base/nsStandardURL.h
netwerk/protocol/about/nsAboutProtocolHandler.h
netwerk/test/unit/test_uri_mutator.js
netwerk/test/unit/xpcshell.ini
--- a/caps/NullPrincipalURI.h
+++ b/caps/NullPrincipalURI.h
@@ -53,17 +53,17 @@ private:
   nsAutoCStringN<NSID_LENGTH> mPath;
 
 public:
   class Mutator
       : public nsIURIMutator
       , public BaseURIMutator<NullPrincipalURI>
   {
     NS_DECL_ISUPPORTS
-    NS_FORWARD_SAFE_NSIURISETTERS(mURI)
+    NS_FORWARD_SAFE_NSIURISETTERS_RET(mURI)
 
     NS_IMETHOD Deserialize(const mozilla::ipc::URIParams& aParams) override
     {
       return InitFromIPCParams(aParams);
     }
 
     NS_IMETHOD Read(nsIObjectInputStream* aStream) override
     {
@@ -71,18 +71,19 @@ public:
     }
 
     NS_IMETHOD Finalize(nsIURI** aURI) override
     {
       mURI.forget(aURI);
       return NS_OK;
     }
 
-    NS_IMETHOD SetSpec(const nsACString & aSpec) override
+    NS_IMETHOD SetSpec(const nsACString & aSpec, nsIURIMutator** aMutator) override
     {
+      NS_ADDREF(*aMutator = this);
       return NS_ERROR_NOT_IMPLEMENTED;
     }
 
     explicit Mutator() { }
   private:
     virtual ~Mutator() { }
 
     friend class NullPrincipalURI;
--- a/dom/file/nsHostObjectURI.h
+++ b/dom/file/nsHostObjectURI.h
@@ -78,17 +78,17 @@ protected:
   virtual ~nsHostObjectURI() {}
 
 public:
   class Mutator
     : public nsIURIMutator
     , public BaseURIMutator<nsHostObjectURI>
   {
     NS_DECL_ISUPPORTS
-    NS_FORWARD_SAFE_NSIURISETTERS(mURI)
+    NS_FORWARD_SAFE_NSIURISETTERS_RET(mURI)
     NS_DEFINE_NSIMUTATOR_COMMON
 
     explicit Mutator() { }
   private:
     virtual ~Mutator() { }
 
     friend class nsHostObjectURI;
   };
--- a/dom/jsurl/nsJSProtocolHandler.h
+++ b/dom/jsurl/nsJSProtocolHandler.h
@@ -105,17 +105,17 @@ private:
     nsCOMPtr<nsIURI> mBaseURI;
 
 public:
     class Mutator
         : public nsIURIMutator
         , public BaseURIMutator<nsJSURI>
     {
         NS_DECL_ISUPPORTS
-        NS_FORWARD_SAFE_NSIURISETTERS(mURI)
+        NS_FORWARD_SAFE_NSIURISETTERS_RET(mURI)
         NS_DEFINE_NSIMUTATOR_COMMON
 
         explicit Mutator() { }
     private:
         virtual ~Mutator() { }
 
         friend class nsJSURI;
     };
--- a/image/decoders/icon/nsIconURI.h
+++ b/image/decoders/icon/nsIconURI.h
@@ -46,17 +46,17 @@ protected:
                        // kStateStrings
 
 public:
   class Mutator
       : public nsIURIMutator
       , public BaseURIMutator<nsMozIconURI>
   {
     NS_DECL_ISUPPORTS
-    NS_FORWARD_SAFE_NSIURISETTERS(mURI)
+    NS_FORWARD_SAFE_NSIURISETTERS_RET(mURI)
 
     NS_IMETHOD Deserialize(const mozilla::ipc::URIParams& aParams) override
     {
       return InitFromIPCParams(aParams);
     }
 
     NS_IMETHOD Read(nsIObjectInputStream* aStream) override
     {
@@ -64,17 +64,18 @@ public:
     }
 
     NS_IMETHOD Finalize(nsIURI** aURI) override
     {
       mURI.forget(aURI);
       return NS_OK;
     }
 
-    NS_IMETHOD SetSpec(const nsACString & aSpec) override {
+    NS_IMETHOD SetSpec(const nsACString & aSpec, nsIURIMutator** aMutator) override {
+      NS_ADDREF(*aMutator = this);
       return InitFromSpec(aSpec);
     }
 
     explicit Mutator() { }
   private:
     virtual ~Mutator() { }
 
     friend class nsMozIconURI;
--- a/modules/libjar/nsJARURI.h
+++ b/modules/libjar/nsJARURI.h
@@ -99,17 +99,17 @@ protected:
     nsCString        mCharsetHint;
 
 public:
     class Mutator
         : public nsIURIMutator
         , public BaseURIMutator<nsJARURI>
     {
         NS_DECL_ISUPPORTS
-        NS_FORWARD_SAFE_NSIURISETTERS(mURI)
+        NS_FORWARD_SAFE_NSIURISETTERS_RET(mURI)
         NS_DEFINE_NSIMUTATOR_COMMON
 
         explicit Mutator() { }
     private:
         virtual ~Mutator() { }
 
         friend class nsJARURI;
     };
--- a/netwerk/base/nsIURIMutator.idl
+++ b/netwerk/base/nsIURIMutator.idl
@@ -1,16 +1,17 @@
 /* -*- 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;
+interface nsIURIMutator;
 
 %{C++
 #include "nsStringGlue.h"
 
 #undef SetPort  // XXX Windows!
 
 namespace mozilla {
 class Encoding;
@@ -82,54 +83,96 @@ protected:
 // 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); }
-
+  NS_IMETHOD SetSpec(const nsACString & aSpec, nsIURIMutator** aMutator) override \
+    { NS_ADDREF(*aMutator = this); 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);
+  nsIURIMutator setSpec(in AUTF8String aSpec);
 };
 
+/**
+ * These methods allow the mutator to change various parts of the URI.
+ * They return the same nsIURIMutator so that we may chain setter operations:
+ * Example:
+ * let newURI = uri.mutate()
+ *                 .setSpec("http://example.com")
+ *                 .setQuery("hello")
+ *                 .finalize();
+ */
 [scriptable, builtinclass, uuid(5403a6ec-99d7-405e-8b45-9f805bbdfcef)]
 interface nsIURISetters : nsIURISetSpec
 {
-  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);
-  void setPathQueryRef(in AUTF8String aPathQueryRef);
-  void setRef(in AUTF8String aRef);
-  void setFilePath(in AUTF8String aFilePath);
-  void setQuery(in AUTF8String aQuery);
-  [noscript] void setQueryWithEncoding(in AUTF8String query, in Encoding encoding);
+  nsIURIMutator setScheme(in AUTF8String aScheme);
+  nsIURIMutator setUserPass(in AUTF8String aUserPass);
+  nsIURIMutator setUsername(in AUTF8String aUsername);
+  nsIURIMutator setPassword(in AUTF8String aPassword);
+  nsIURIMutator setHostPort(in AUTF8String aHostPort);
+  nsIURIMutator setHostAndPort(in AUTF8String aHostAndPort);
+  nsIURIMutator setHost(in AUTF8String aHost);
+  nsIURIMutator setPort(in long aPort);
+  nsIURIMutator setPathQueryRef(in AUTF8String aPathQueryRef);
+  nsIURIMutator setRef(in AUTF8String aRef);
+  nsIURIMutator setFilePath(in AUTF8String aFilePath);
+  nsIURIMutator setQuery(in AUTF8String aQuery);
+  [noscript] nsIURIMutator setQueryWithEncoding(in AUTF8String query, in Encoding encoding);
 };
 
+%{C++
+
+// Using this macro instead of NS_FORWARD_SAFE_NSIURISETTERS makes chaining
+// setter operations possible.
+#define NS_FORWARD_SAFE_NSIURISETTERS_RET(_to)                                                                         \
+  NS_IMETHOD SetScheme(const nsACString & aScheme, nsIURIMutator** aMutator) override                                  \
+    { NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetScheme(aScheme); }                    \
+  NS_IMETHOD SetUserPass(const nsACString & aUserPass, nsIURIMutator** aMutator) override                              \
+    { NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetUserPass(aUserPass); }                \
+  NS_IMETHOD SetUsername(const nsACString & aUsername, nsIURIMutator** aMutator) override                              \
+    { NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetUsername(aUsername); }                \
+  NS_IMETHOD SetPassword(const nsACString & aPassword, nsIURIMutator** aMutator) override                              \
+    { NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetPassword(aPassword); }                \
+  NS_IMETHOD SetHostPort(const nsACString & aHostPort, nsIURIMutator** aMutator) override                              \
+    { NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetHostPort(aHostPort); }                \
+  NS_IMETHOD SetHostAndPort(const nsACString & aHostAndPort, nsIURIMutator** aMutator) override                        \
+    { NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetHostAndPort(aHostAndPort); }          \
+  NS_IMETHOD SetHost(const nsACString & aHost, nsIURIMutator** aMutator) override                                      \
+    { NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetHost(aHost); }                        \
+  NS_IMETHOD SetPort(int32_t aPort, nsIURIMutator** aMutator) override                                                 \
+    { NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetPort(aPort); }                        \
+  NS_IMETHOD SetPathQueryRef(const nsACString & aPathQueryRef, nsIURIMutator** aMutator) override                      \
+    { NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetPathQueryRef(aPathQueryRef); }        \
+  NS_IMETHOD SetRef(const nsACString & aRef, nsIURIMutator** aMutator) override                                        \
+    { NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetRef(aRef); }                          \
+  NS_IMETHOD SetFilePath(const nsACString & aFilePath, nsIURIMutator** aMutator) override                              \
+    { NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetFilePath(aFilePath); }                \
+  NS_IMETHOD SetQuery(const nsACString & aQuery, nsIURIMutator** aMutator) override                                    \
+    { NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetQuery(aQuery); }                      \
+  NS_IMETHOD SetQueryWithEncoding(const nsACString & query, const mozilla::Encoding *encoding, nsIURIMutator** aMutator) override \
+    { NS_ADDREF(*aMutator = this); return !_to ? NS_ERROR_NULL_POINTER : _to->SetQueryWithEncoding(query, 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.
    */
--- a/netwerk/base/nsSimpleNestedURI.h
+++ b/netwerk/base/nsSimpleNestedURI.h
@@ -72,18 +72,18 @@ protected:
 
 
 public:
     class Mutator
         : public nsIURIMutator
         , public BaseURIMutator<nsSimpleNestedURI>
     {
         NS_DECL_ISUPPORTS
-        NS_FORWARD_SAFE_NSIURISETTERS(mURI)
         NS_DEFINE_NSIMUTATOR_COMMON
+        NS_FORWARD_SAFE_NSIURISETTERS_RET(mURI)
 
         explicit Mutator() { }
     private:
         virtual ~Mutator() { }
 
         friend class nsSimpleNestedURI;
     };
 };
--- a/netwerk/base/nsSimpleURI.h
+++ b/netwerk/base/nsSimpleURI.h
@@ -113,17 +113,17 @@ protected:
 
 
 public:
     class Mutator
         : public nsIURIMutator
         , public BaseURIMutator<nsSimpleURI>
     {
         NS_DECL_ISUPPORTS
-        NS_FORWARD_SAFE_NSIURISETTERS(mURI)
+        NS_FORWARD_SAFE_NSIURISETTERS_RET(mURI)
         NS_DEFINE_NSIMUTATOR_COMMON
 
         explicit Mutator() { }
     private:
         virtual ~Mutator() { }
 
         friend class nsSimpleURI;
     };
--- a/netwerk/base/nsStandardURL.h
+++ b/netwerk/base/nsStandardURL.h
@@ -313,17 +313,17 @@ public:
 #endif
 
 public:
     class Mutator
         : public nsIURIMutator
         , public BaseURIMutator<nsStandardURL>
     {
         NS_DECL_ISUPPORTS
-        NS_FORWARD_SAFE_NSIURISETTERS(mURI)
+        NS_FORWARD_SAFE_NSIURISETTERS_RET(mURI)
         NS_DEFINE_NSIMUTATOR_COMMON
 
         explicit Mutator() { }
     private:
         virtual ~Mutator() { }
 
         friend class nsStandardURL;
     };
--- a/netwerk/protocol/about/nsAboutProtocolHandler.h
+++ b/netwerk/protocol/about/nsAboutProtocolHandler.h
@@ -87,17 +87,17 @@ protected:
     nsCOMPtr<nsIURI> mBaseURI;
 
 public:
     class Mutator
         : public nsIURIMutator
         , public BaseURIMutator<nsNestedAboutURI>
     {
         NS_DECL_ISUPPORTS
-        NS_FORWARD_SAFE_NSIURISETTERS(mURI)
+        NS_FORWARD_SAFE_NSIURISETTERS_RET(mURI)
         NS_DEFINE_NSIMUTATOR_COMMON
 
         explicit Mutator() { }
     private:
         virtual ~Mutator() { }
 
         friend class nsNestedAboutURI;
     };
new file mode 100644
--- /dev/null
+++ b/netwerk/test/unit/test_uri_mutator.js
@@ -0,0 +1,23 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 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/. */
+
+"use strict";
+Cu.import("resource://gre/modules/NetUtil.jsm");
+
+function standardMutator()
+{
+  return Cc['@mozilla.org/network/standard-url-mutator;1']
+           .createInstance(Ci.nsIURIMutator);
+}
+
+add_task(async function test_simple_setter_chaining() {
+  let uri = standardMutator()
+              .setSpec("http://example.com/")
+              .setQuery("hello")
+              .setRef("bla")
+              .setScheme("ftp")
+              .finalize();
+  equal(uri.spec, "ftp://example.com/?hello#bla");
+});
--- a/netwerk/test/unit/xpcshell.ini
+++ b/netwerk/test/unit/xpcshell.ini
@@ -400,8 +400,9 @@ skip-if = os == "android"
 [test_channel_priority.js]
 [test_bug1312774_http1.js]
 [test_1351443-missing-NewChannel2.js]
 [test_bug1312782_http1.js]
 [test_bug1355539_http1.js]
 [test_bug1378385_http1.js]
 [test_tls_flags_separate_connections.js]
 [test_tls_flags.js]
+[test_uri_mutator.js]