Bug 308590 patch 3.5: Add nsIURI::CloneIgnoringRef interface & impls. r=bz sr=biesi
authorDaniel Holbert <dholbert@cs.stanford.edu>
Sat, 21 May 2011 18:12:45 -0700
changeset 69984 835e9789e934e5b9c1cda65ab10547dd5bcc52a4
parent 69983 add8d8d67ba80f21adcc4971be3a26dfbb86c16b
child 69985 a006860c018dbce03376d95c83f4cc85c6fb2162
push id99
push usereakhgari@mozilla.com
push dateTue, 24 May 2011 18:03:59 +0000
treeherdermozilla-aurora@26d6981b3d6a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, biesi
bugs308590
milestone6.0a1
Bug 308590 patch 3.5: Add nsIURI::CloneIgnoringRef interface & impls. r=bz sr=biesi
caps/src/nsNullPrincipalURI.cpp
content/base/src/nsFileDataProtocolHandler.cpp
modules/libjar/nsJARURI.cpp
modules/libjar/nsJARURI.h
modules/libpr0n/decoders/icon/nsIconURI.cpp
netwerk/base/public/nsIURI.idl
netwerk/base/src/nsSimpleNestedURI.cpp
netwerk/base/src/nsSimpleNestedURI.h
netwerk/base/src/nsSimpleURI.cpp
netwerk/base/src/nsSimpleURI.h
netwerk/base/src/nsStandardURL.cpp
netwerk/base/src/nsStandardURL.h
netwerk/test/unit/test_URIs.js
--- a/caps/src/nsNullPrincipalURI.cpp
+++ b/caps/src/nsNullPrincipalURI.cpp
@@ -232,22 +232,29 @@ nsNullPrincipalURI::SetUserPass(const ns
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsNullPrincipalURI::Clone(nsIURI **_newURI)
 {
   nsCOMPtr<nsIURI> uri =
     new nsNullPrincipalURI(mScheme + NS_LITERAL_CSTRING(":") + mPath);
-  NS_ENSURE_TRUE(uri, NS_ERROR_OUT_OF_MEMORY);
   uri.forget(_newURI);
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsNullPrincipalURI::CloneIgnoringRef(nsIURI **_newURI)
+{
+  // GetRef/SetRef not supported by nsNullPrincipalURI, so
+  // CloneIgnoringRef() is the same as Clone().
+  return Clone(_newURI);
+}
+
+NS_IMETHODIMP
 nsNullPrincipalURI::Equals(nsIURI *aOther, PRBool *_equals)
 {
   *_equals = PR_FALSE;
   nsNullPrincipalURI *otherURI;
   nsresult rv = aOther->QueryInterface(kNullPrincipalURIImplementationCID,
                                        (void **)&otherURI);
   if (NS_SUCCEEDED(rv)) {
     *_equals = (mScheme == otherURI->mScheme && mPath == otherURI->mPath);
--- a/content/base/src/nsFileDataProtocolHandler.cpp
+++ b/content/base/src/nsFileDataProtocolHandler.cpp
@@ -142,24 +142,25 @@ public:
   // For use only from deserialization
   nsFileDataURI() : nsSimpleURI() {}
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIURIWITHPRINCIPAL
   NS_DECL_NSISERIALIZABLE
   NS_DECL_NSICLASSINFO
 
-  // Override Clone() and EqualsInternal()
-  NS_IMETHOD Clone(nsIURI** aClone);
+  // Override CloneInternal() and EqualsInternal()
+  virtual nsresult CloneInternal(RefHandlingEnum aRefHandlingMode,
+                                 nsIURI** aClone);
   virtual nsresult EqualsInternal(nsIURI* aOther,
                                   RefHandlingEnum aRefHandlingMode,
                                   PRBool* aResult);
 
   // Override StartClone to hand back a nsFileDataURI
-  virtual nsSimpleURI* StartClone()
+  virtual nsSimpleURI* StartClone(RefHandlingEnum /* unused */)
   { return new nsFileDataURI(); }
 
   nsCOMPtr<nsIPrincipal> mPrincipal;
 };
 
 NS_IMPL_ADDREF_INHERITED(nsFileDataURI, nsSimpleURI)
 NS_IMPL_RELEASE_INHERITED(nsFileDataURI, nsSimpleURI)
 NS_INTERFACE_MAP_BEGIN(nsFileDataURI)
@@ -210,22 +211,23 @@ nsFileDataURI::Write(nsIObjectOutputStre
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_WriteOptionalCompoundObject(aStream, mPrincipal,
                                         NS_GET_IID(nsIPrincipal),
                                         PR_TRUE);
 }
 
 // nsIURI methods:
-
-NS_IMETHODIMP
-nsFileDataURI::Clone(nsIURI** aClone)
+nsresult
+nsFileDataURI::CloneInternal(nsSimpleURI::RefHandlingEnum aRefHandlingMode,
+                             nsIURI** aClone)
 {
   nsCOMPtr<nsIURI> simpleClone;
-  nsresult rv = nsSimpleURI::Clone(getter_AddRefs(simpleClone));
+  nsresult rv =
+    nsSimpleURI::CloneInternal(aRefHandlingMode, getter_AddRefs(simpleClone));
   NS_ENSURE_SUCCESS(rv, rv);
 
 #ifdef DEBUG
   nsRefPtr<nsFileDataURI> uriCheck;
   rv = simpleClone->QueryInterface(kFILEDATAURICID, getter_AddRefs(uriCheck));
   NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv) && uriCheck,
 		    "Unexpected!");
 #endif
--- a/modules/libjar/nsJARURI.cpp
+++ b/modules/libjar/nsJARURI.cpp
@@ -509,17 +509,29 @@ nsJARURI::SchemeIs(const char *i_Scheme,
 }
 
 NS_IMETHODIMP
 nsJARURI::Clone(nsIURI **result)
 {
     nsresult rv;
 
     nsCOMPtr<nsIJARURI> uri;
-    rv = CloneWithJARFile(mJARFile, getter_AddRefs(uri));
+    rv = CloneWithJARFileInternal(mJARFile, eHonorRef, getter_AddRefs(uri));
+    if (NS_FAILED(rv)) return rv;
+
+    return CallQueryInterface(uri, result);
+}
+
+NS_IMETHODIMP
+nsJARURI::CloneIgnoringRef(nsIURI **result)
+{
+    nsresult rv;
+
+    nsCOMPtr<nsIJARURI> uri;
+    rv = CloneWithJARFileInternal(mJARFile, eIgnoreRef, getter_AddRefs(uri));
     if (NS_FAILED(rv)) return rv;
 
     return CallQueryInterface(uri, result);
 }
 
 NS_IMETHODIMP
 nsJARURI::Resolve(const nsACString &relativePath, nsACString &result)
 {
@@ -777,47 +789,53 @@ nsJARURI::SetJAREntry(const nsACString &
 {
     return CreateEntryURL(entryPath, mCharsetHint.get(),
                           getter_AddRefs(mJAREntry));
 }
 
 NS_IMETHODIMP
 nsJARURI::CloneWithJARFile(nsIURI *jarFile, nsIJARURI **result)
 {
+    return CloneWithJARFileInternal(jarFile, eHonorRef, result);
+}
+
+nsresult
+nsJARURI::CloneWithJARFileInternal(nsIURI *jarFile,
+                                   nsJARURI::RefHandlingEnum refHandlingMode,
+                                   nsIJARURI **result)
+{
     if (!jarFile) {
         return NS_ERROR_INVALID_ARG;
     }
 
     nsresult rv;
 
     nsCOMPtr<nsIURI> newJARFile;
     rv = jarFile->Clone(getter_AddRefs(newJARFile));
     if (NS_FAILED(rv)) return rv;
 
     NS_TryToSetImmutable(newJARFile);
 
     nsCOMPtr<nsIURI> newJAREntryURI;
-    rv = mJAREntry->Clone(getter_AddRefs(newJAREntryURI));
+    rv = refHandlingMode == eHonorRef ?
+        mJAREntry->Clone(getter_AddRefs(newJAREntryURI)) :
+        mJAREntry->CloneIgnoringRef(getter_AddRefs(newJAREntryURI));
+
     if (NS_FAILED(rv)) return rv;
 
     nsCOMPtr<nsIURL> newJAREntry(do_QueryInterface(newJAREntryURI));
     NS_ASSERTION(newJAREntry, "This had better QI to nsIURL!");
     
     nsJARURI* uri = new nsJARURI();
-    if (uri) {
-        NS_ADDREF(uri);
-        uri->mJARFile = newJARFile;
-        uri->mJAREntry = newJAREntry;
-        *result = uri;
-        rv = NS_OK;
-    } else {
-        rv = NS_ERROR_OUT_OF_MEMORY;
-    }
+    NS_ADDREF(uri);
+    uri->mJARFile = newJARFile;
+    uri->mJAREntry = newJAREntry;
+    *result = uri;
 
-    return rv;
+    return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 NS_IMETHODIMP
 nsJARURI::GetInnerURI(nsIURI **uri)
 {
     return NS_EnsureSafeToReturn(mJARFile, uri);
--- a/modules/libjar/nsJARURI.h
+++ b/modules/libjar/nsJARURI.h
@@ -100,16 +100,20 @@ protected:
         eHonorRef
     };
 
     // Helper to share code between Equals methods.
     virtual nsresult EqualsInternal(nsIURI* other,
                                     RefHandlingEnum refHandlingMode,
                                     PRBool* result);
 
+    // Helper to share code between Clone methods.
+    nsresult CloneWithJARFileInternal(nsIURI *jarFile,
+                                      RefHandlingEnum refHandlingMode,
+                                      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;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsJARURI, NS_THIS_JARURI_IMPL_CID)
--- a/modules/libpr0n/decoders/icon/nsIconURI.cpp
+++ b/modules/libpr0n/decoders/icon/nsIconURI.cpp
@@ -444,32 +444,37 @@ nsMozIconURI::Clone(nsIURI **result)
     if (NS_FAILED(rv))
       return rv;
     newIconURL = do_QueryInterface(newURI, &rv);
     if (NS_FAILED(rv))
       return rv;
   }
 
   nsMozIconURI *uri = new nsMozIconURI();
-  if (!uri)
-    return NS_ERROR_OUT_OF_MEMORY;
- 
   newIconURL.swap(uri->mIconURL);
   uri->mSize = mSize;
   uri->mContentType = mContentType;
   uri->mFileName = mFileName;
   uri->mStockIcon = mStockIcon;
   uri->mIconSize = mIconSize;
   uri->mIconState = mIconState;
   NS_ADDREF(*result = uri);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsMozIconURI::CloneIgnoringRef(nsIURI **result)
+{
+  // GetRef/SetRef not supported by nsMozIconURI, so
+  // CloneIgnoringRef() is the same as Clone().
+  return Clone(result);
+}
+
+NS_IMETHODIMP
 nsMozIconURI::Resolve(const nsACString &relativePath, nsACString &result)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsMozIconURI::GetAsciiSpec(nsACString &aSpecA)
 {
--- a/netwerk/base/public/nsIURI.idl
+++ b/netwerk/base/public/nsIURI.idl
@@ -215,16 +215,21 @@ interface nsIURI : nsISupports
     boolean schemeIs(in string scheme);
 
     /**
      * Clones the current URI.
      */
     nsIURI clone();
 
     /**
+     * Clones the current URI, clearing the 'ref' attribute in the clone.
+     */
+    nsIURI cloneIgnoringRef();
+
+    /**
      * This method resolves a relative string into an absolute URI string,
      * using this URI as the base. 
      *
      * NOTE: some implementations may have no concept of a relative URI.
      */
     AUTF8String resolve(in AUTF8String relativePath);
 
 
--- a/netwerk/base/src/nsSimpleNestedURI.cpp
+++ b/netwerk/base/src/nsSimpleNestedURI.cpp
@@ -157,22 +157,25 @@ nsSimpleNestedURI::EqualsInternal(nsIURI
             }
         }
     }
 
     return NS_OK;
 }
 
 /* virtual */ nsSimpleURI*
-nsSimpleNestedURI::StartClone()
+nsSimpleNestedURI::StartClone(nsSimpleURI::RefHandlingEnum refHandlingMode)
 {
     NS_ENSURE_TRUE(mInnerURI, nsnull);
     
     nsCOMPtr<nsIURI> innerClone;
-    nsresult rv = mInnerURI->Clone(getter_AddRefs(innerClone));
+    nsresult rv = refHandlingMode == eHonorRef ?
+        mInnerURI->Clone(getter_AddRefs(innerClone)) :
+        mInnerURI->CloneIgnoringRef(getter_AddRefs(innerClone));
+
     if (NS_FAILED(rv)) {
         return nsnull;
     }
 
     nsSimpleNestedURI* url = new nsSimpleNestedURI(innerClone);
     if (url) {
         url->SetMutable(PR_FALSE);
     }
--- a/netwerk/base/src/nsSimpleNestedURI.h
+++ b/netwerk/base/src/nsSimpleNestedURI.h
@@ -72,17 +72,17 @@ public:
     NS_DECL_NSIIPCSERIALIZABLE
 
     // Overrides for various methods nsSimpleURI implements follow.
   
     // nsSimpleURI overrides
     virtual nsresult EqualsInternal(nsIURI* other,
                                     RefHandlingEnum refHandlingMode,
                                     PRBool* result);
-    virtual nsSimpleURI* StartClone();
+    virtual nsSimpleURI* StartClone(RefHandlingEnum refHandlingMode);
 
     // nsISerializable overrides
     NS_IMETHOD Read(nsIObjectInputStream* aStream);
     NS_IMETHOD Write(nsIObjectOutputStream* aStream);
 
     // Override the nsIClassInfo method GetClassIDNoAlloc to make sure our
     // nsISerializable impl works right.
     NS_IMETHOD GetClassIDNoAlloc(nsCID *aClassIDNoAlloc);  
--- a/netwerk/base/src/nsSimpleURI.cpp
+++ b/netwerk/base/src/nsSimpleURI.cpp
@@ -390,25 +390,40 @@ nsSimpleURI::SchemeIs(const char *i_Sche
     } else {
         *o_Equals = PR_FALSE;
     }
 
     return NS_OK;
 }
 
 /* virtual */ nsSimpleURI*
-nsSimpleURI::StartClone()
+nsSimpleURI::StartClone(nsSimpleURI::RefHandlingEnum /* ignored */)
 {
     return new nsSimpleURI();
 }
 
 NS_IMETHODIMP
-nsSimpleURI::Clone(nsIURI* *result)
+nsSimpleURI::Clone(nsIURI** result)
+{
+    return CloneInternal(eHonorRef, result);
+}
+
+NS_IMETHODIMP
+nsSimpleURI::CloneIgnoringRef(nsIURI** result)
 {
-    nsSimpleURI* url = StartClone();
+    return CloneInternal(eIgnoreRef, result);
+}
+
+nsresult
+nsSimpleURI::CloneInternal(nsSimpleURI::RefHandlingEnum refHandlingMode,
+                           nsIURI** result)
+{
+    // XXXdholbert Mostly ignoring refHandlingMode so far, but I'll make use
+    // of it in next patch, when I add support for .ref to this class.
+    nsSimpleURI* url = StartClone(refHandlingMode);
     if (url == nsnull)
         return NS_ERROR_OUT_OF_MEMORY;
 
     // Note: |url| may well have mMutable false at this point, so
     // don't call any setter methods.
     url->mScheme = mScheme;
     url->mPath = mPath;
 
--- a/netwerk/base/src/nsSimpleURI.h
+++ b/netwerk/base/src/nsSimpleURI.h
@@ -75,22 +75,28 @@ public:
 
 protected:
     // enum used in a few places to specify how .ref attribute should be handled
     enum RefHandlingEnum {
         eIgnoreRef,
         eHonorRef
     };
 
-    // Helper to share code between Equals methods.  Subclasses can override
-    // for custom Equals behavior.
+    // Helper to share code between Equals methods.
     virtual nsresult EqualsInternal(nsIURI* other,
                                     RefHandlingEnum refHandlingMode,
                                     PRBool* result);
 
-    virtual nsSimpleURI* StartClone();
+    // NOTE: This takes the refHandlingMode as an argument because
+    // nsSimpleNestedURI's specialized version needs to know how to clone
+    // its inner URI.
+    virtual nsSimpleURI* StartClone(RefHandlingEnum refHandlingMode);
 
+    // Helper to share code between Clone methods.
+    virtual nsresult CloneInternal(RefHandlingEnum refHandlingMode,
+                                   nsIURI** clone);
+    
     nsCString mScheme;
     nsCString mPath;
     PRBool mMutable;
 };
 
 #endif // nsSimpleURI_h__
--- a/netwerk/base/src/nsStandardURL.cpp
+++ b/netwerk/base/src/nsStandardURL.cpp
@@ -1692,17 +1692,32 @@ nsStandardURL::StartClone()
 {
     nsStandardURL *clone = new nsStandardURL();
     return clone;
 }
 
 NS_IMETHODIMP
 nsStandardURL::Clone(nsIURI **result)
 {
-    nsStandardURL *clone = StartClone();
+    return CloneInternal(eHonorRef, result);
+}
+
+
+NS_IMETHODIMP
+nsStandardURL::CloneIgnoringRef(nsIURI **result)
+{
+    return CloneInternal(eIgnoreRef, result);
+}
+
+nsresult
+nsStandardURL::CloneInternal(nsStandardURL::RefHandlingEnum refHandlingMode,
+                             nsIURI **result)
+
+{
+    nsRefPtr<nsStandardURL> clone = StartClone();
     if (!clone)
         return NS_ERROR_OUT_OF_MEMORY;
 
     clone->mSpec = mSpec;
     clone->mDefaultPort = mDefaultPort;
     clone->mPort = mPort;
     clone->mScheme = mScheme;
     clone->mAuthority = mAuthority;
@@ -1722,17 +1737,21 @@ nsStandardURL::Clone(nsIURI **result)
     clone->mParser = mParser;
     clone->mFile = mFile;
     clone->mHostA = mHostA ? nsCRT::strdup(mHostA) : nsnull;
     clone->mMutable = PR_TRUE;
     clone->mSupportsFileURL = mSupportsFileURL;
     clone->mHostEncoding = mHostEncoding;
     clone->mSpecEncoding = mSpecEncoding;
 
-    NS_ADDREF(*result = clone);
+    if (refHandlingMode == eIgnoreRef) {
+        clone->SetRef(EmptyCString());
+    }
+
+    clone.forget(result);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::Resolve(const nsACString &in, nsACString &out)
 {
     const nsPromiseFlatCString &flat = PromiseFlatCString(in);
     const char *relpath = flat.get();
--- a/netwerk/base/src/nsStandardURL.h
+++ b/netwerk/base/src/nsStandardURL.h
@@ -162,16 +162,20 @@ protected:
     // Helper to share code between Equals and EqualsExceptRef
     // NOTE: *not* virtual, because no one needs to override this so far...
     nsresult EqualsInternal(nsIURI* unknownOther,
                             RefHandlingEnum refHandlingMode,
                             PRBool* result);
 
     virtual nsStandardURL* StartClone();
 
+    // Helper to share code between Clone methods.
+    nsresult CloneInternal(RefHandlingEnum aRefHandlingMode,
+                           nsIURI** aClone);
+
     // Helper for subclass implementation of GetFile().  Subclasses that map
     // URIs to files in a special way should implement this method.  It should
     // ensure that our mFile is initialized, if it's possible.
     // returns NS_ERROR_NO_INTERFACE if the url does not map to a file
     virtual nsresult EnsureFile();
 
 private:
     PRInt32  Port() { return mPort == -1 ? mDefaultPort : mPort; }
--- a/netwerk/test/unit/test_URIs.js
+++ b/netwerk/test/unit/test_URIs.js
@@ -191,16 +191,17 @@ function do_check_property(aTest, aURI, 
 
 // Test that a given URI parses correctly into its various components.
 function do_test_uri_basic(aTest) {
   var URI = NetUtil.newURI(aTest.spec);
 
   // Sanity-check
   do_info("testing " + aTest.spec + " equals a clone of itself");
   do_check_uri_eq(URI, URI.clone());
+  do_check_uri_eq(URI, URI.cloneIgnoringRef());
   do_info("testing " + aTest.spec + " instanceof nsIURL");
   do_check_eq(URI instanceof Ci.nsIURL, aTest.nsIURL);
   do_info("testing " + aTest.spec + " instanceof nsINestedURI");
   do_check_eq(URI instanceof Ci.nsINestedURI,
               aTest.nsINestedURI);
 
   // Check the various components
   do_check_property(aTest, URI, "scheme");
@@ -243,16 +244,27 @@ function do_test_uri_with_hash_suffix(aT
   if (aTest.nsIURL) {
     var URL = testURI.QueryInterface(Ci.nsIURL);
     do_check_property(aTest, URL, "ref",
                       function(aStr) { return aSuffix.substr(1); });
 
     do_info("testing " + aTest.spec +
           " is equalExceptRef to self with '" + aSuffix + "' appended");
     do_check_uri_eqExceptRef(origURI, testURI);
+
+    do_info("testing cloneIgnoringRef on " + testURI.spec +
+            " is equal to no-ref version but not equal to ref version");
+    var cloneNoRef = testURI.cloneIgnoringRef();
+    if (aTest.spec == "http://" && aSuffix == "#") {
+      do_info("TODO: bug 657033");
+      do_check_uri_eq(cloneNoRef, origURI, todo_check_true);
+    } else {
+      do_check_uri_eq(cloneNoRef, origURI);
+    }
+    do_check_false(cloneNoRef.equals(testURI));
   }
 }
 
 // Tests various ways of setting & clearing a ref on a URI.
 function do_test_mutate_ref(aTest, aSuffix) {
   do_info("making sure caller is using suffix that starts with '#'");
   do_check_eq(aSuffix[0], "#");