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 70213 835e9789e934e5b9c1cda65ab10547dd5bcc52a4
parent 70212 add8d8d67ba80f21adcc4971be3a26dfbb86c16b
child 70214 a006860c018dbce03376d95c83f4cc85c6fb2162
push id11
push userffxbld
push dateThu, 11 Aug 2011 21:43:38 +0000
treeherdermozilla-release@cf0a29826586 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, biesi
bugs308590
milestone6.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 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], "#");