Bug 658949 patch 1: Teach nsDataHandler::ParseURI about #ref, and transfer 'isRefValid' flag in nsSimpleURI::Clone. r=bz
authorDaniel Holbert <dholbert@cs.stanford.edu>
Tue, 24 May 2011 17:40:10 +0200
changeset 70100 c4d58bb8f5ad793fd6c647fd42ff7a8d692b5028
parent 70099 41371c9fe361b1de4111af9d1cfbafeb592a25f1
child 70101 f5c062e991969ae7c3314009951c27d0f8c4e502
push id20185
push usermlamouri@mozilla.com
push dateTue, 24 May 2011 15:47:08 +0000
treeherdermozilla-central@837f762860af [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs658949
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 658949 patch 1: Teach nsDataHandler::ParseURI about #ref, and transfer 'isRefValid' flag in nsSimpleURI::Clone. r=bz
netwerk/base/src/nsSimpleURI.cpp
netwerk/protocol/data/nsDataChannel.cpp
netwerk/protocol/data/nsDataHandler.cpp
netwerk/protocol/data/nsDataHandler.h
--- a/netwerk/base/src/nsSimpleURI.cpp
+++ b/netwerk/base/src/nsSimpleURI.cpp
@@ -110,18 +110,20 @@ nsSimpleURI::Read(nsIObjectInputStream* 
     if (NS_FAILED(rv)) return rv;
     if (isRefValid != PR_TRUE && isRefValid != PR_FALSE) {
         NS_WARNING("Unexpected boolean value");
         return NS_ERROR_UNEXPECTED;
     }
     mIsRefValid = isRefValid;
 
     if (isRefValid) {
-      rv = aStream->ReadCString(mRef);
-      if (NS_FAILED(rv)) return rv;
+        rv = aStream->ReadCString(mRef);
+        if (NS_FAILED(rv)) return rv;
+    } else {
+        mRef.Truncate(); // invariant: mRef should be empty when it's not valid
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSimpleURI::Write(nsIObjectOutputStream* aStream)
 {
@@ -161,16 +163,17 @@ nsSimpleURI::Read(const IPC::Message *aM
         return PR_FALSE;
 
     mMutable = isMutable;
     mIsRefValid = isRefValid;
 
     if (mIsRefValid) {
         return ReadParam(aMsg, aIter, &mRef);
     }
+    mRef.Truncate(); // invariant: mRef should be empty when it's not valid
 
     return PR_TRUE;
 }
 
 void
 nsSimpleURI::Write(IPC::Message *aMsg)
 {
     WriteParam(aMsg, bool(mMutable));
@@ -186,16 +189,18 @@ nsSimpleURI::Write(IPC::Message *aMsg)
 // nsIURI methods:
 
 NS_IMETHODIMP
 nsSimpleURI::GetSpec(nsACString &result)
 {
     result = mScheme + NS_LITERAL_CSTRING(":") + mPath;
     if (mIsRefValid) {
         result += NS_LITERAL_CSTRING("#") + mRef;
+    } else {
+        NS_ABORT_IF_FALSE(mRef.IsEmpty(), "mIsRefValid/mRef invariant broken");
     }
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSimpleURI::SetSpec(const nsACString &aSpec)
 {
     NS_ENSURE_STATE(mMutable);
@@ -363,28 +368,30 @@ nsSimpleURI::GetPath(nsACString &result)
 NS_IMETHODIMP
 nsSimpleURI::SetPath(const nsACString &path)
 {
     NS_ENSURE_STATE(mMutable);
     
     PRInt32 hashPos = path.FindChar('#');
     if (hashPos < 0) {
         mIsRefValid = PR_FALSE;
+        mRef.Truncate(); // invariant: mRef should be empty when it's not valid
         mPath = path;
         return NS_OK;
     }
 
     mPath = StringHead(path, hashPos);
     return SetRef(Substring(path, PRUint32(hashPos)));
 }
 
 NS_IMETHODIMP
 nsSimpleURI::GetRef(nsACString &result)
 {
     if (!mIsRefValid) {
+      NS_ABORT_IF_FALSE(mRef.IsEmpty(), "mIsRefValid/mRef invariant broken");
       result.Truncate();
     } else {
       result = mRef;
     }
 
     return NS_OK;
 }
 
@@ -393,17 +400,17 @@ nsSimpleURI::GetRef(nsACString &result)
 NS_IMETHODIMP
 nsSimpleURI::SetRef(const nsACString &aRef)
 {
     NS_ENSURE_STATE(mMutable);
 
     if (aRef.IsEmpty()) {
       // Empty string means to remove ref completely.
       mIsRefValid = PR_FALSE;
-      mRef.Truncate();
+      mRef.Truncate(); // invariant: mRef should be empty when it's not valid
       return NS_OK;
     }
 
     mIsRefValid = PR_TRUE;
 
     // Gracefully skip initial hash
     if (aRef[0] == '#') {
         mRef = Substring(aRef, 1);
@@ -498,16 +505,17 @@ nsSimpleURI::CloneInternal(nsSimpleURI::
         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;
     if (refHandlingMode == eHonorRef) {
         url->mRef = mRef;
+        url->mIsRefValid = mIsRefValid;
     }
 
     url.forget(result);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSimpleURI::Resolve(const nsACString &relativePath, nsACString &result) 
--- a/netwerk/protocol/data/nsDataChannel.cpp
+++ b/netwerk/protocol/data/nsDataChannel.cpp
@@ -57,20 +57,20 @@ nsDataChannel::OpenContentStream(PRBool 
     NS_ENSURE_TRUE(URI(), NS_ERROR_NOT_INITIALIZED);
 
     nsresult rv;
 
     nsCAutoString spec;
     rv = URI()->GetAsciiSpec(spec);
     if (NS_FAILED(rv)) return rv;
 
-    nsCString contentType, contentCharset, dataBuffer;
+    nsCString contentType, contentCharset, dataBuffer, hashRef;
     PRBool lBase64;
     rv = nsDataHandler::ParseURI(spec, contentType, contentCharset,
-                                 lBase64, dataBuffer);
+                                 lBase64, dataBuffer, hashRef);
 
     NS_UnescapeURL(dataBuffer);
 
     if (lBase64) {
         // Don't allow spaces in base64-encoded content. This is only
         // relevant for escaped spaces; other spaces are stripped in
         // NewURI.
         dataBuffer.StripWhitespace();
--- a/netwerk/protocol/data/nsDataHandler.cpp
+++ b/netwerk/protocol/data/nsDataHandler.cpp
@@ -109,19 +109,19 @@ nsDataHandler::NewURI(const nsACString &
         // Looks like a reference instead of a fully-specified URI.
         // --> initialize |uri| as a clone of |aBaseURI|, with ref appended.
         rv = aBaseURI->Clone(getter_AddRefs(uri));
         if (NS_FAILED(rv))
             return rv;
         rv = uri->SetRef(spec);
     } else {
         // Otherwise, we'll assume |spec| is a fully-specified data URI
-        nsCAutoString contentType, contentCharset, dataBuffer;
+        nsCAutoString contentType, contentCharset, dataBuffer, hashRef;
         PRBool base64;
-        rv = ParseURI(spec, contentType, contentCharset, base64, dataBuffer);
+        rv = ParseURI(spec, contentType, contentCharset, base64, dataBuffer, hashRef);
         if (NS_FAILED(rv))
             return rv;
 
         // Strip whitespace unless this is text, where whitespace is important
         // Don't strip escaped whitespace though (bug 391951)
         if (base64 || (strncmp(contentType.get(),"text/",5) != 0 &&
                        contentType.Find("xml") == kNotFound)) {
             // it's ascii encoded binary, don't let any spaces in
@@ -166,17 +166,18 @@ nsDataHandler::AllowPort(PRInt32 port, c
     return NS_OK;
 }
 
 nsresult
 nsDataHandler::ParseURI(nsCString& spec,
                         nsCString& contentType,
                         nsCString& contentCharset,
                         PRBool&    isBase64,
-                        nsCString& dataBuffer) {
+                        nsCString& dataBuffer,
+                        nsCString& hashRef) {
     isBase64 = PR_FALSE;
 
     // move past "data:"
     char *buffer = (char *) PL_strcasestr(spec.BeginWriting(), "data:");
     if (!buffer) {
         // malformed uri
         return NS_ERROR_MALFORMED_URI;
     }
@@ -225,12 +226,21 @@ nsDataHandler::ParseURI(nsCString& spec,
 
     *comma = ',';
     if (isBase64)
         *base64 = ';';
 
     contentType.StripWhitespace();
     contentCharset.StripWhitespace();
 
-    dataBuffer.Assign(comma + 1);
+    // Split encoded data from terminal "#ref" (if present)
+    char *data = comma + 1;
+    char *hash = strchr(data, '#');
+    if (!hash) {
+        dataBuffer.Assign(data);
+        hashRef.Truncate();
+    } else {
+        dataBuffer.Assign(data, hash - data);
+        hashRef.Assign(hash);
+    }
 
     return NS_OK;
 }
--- a/netwerk/protocol/data/nsDataHandler.h
+++ b/netwerk/protocol/data/nsDataHandler.h
@@ -58,12 +58,13 @@ public:
 
     // Parse a data: URI and return the individual parts
     // (the given spec will temporarily be modified but will be returned
     //  to the original before returning)
     static NS_HIDDEN_(nsresult) ParseURI(nsCString& spec,
                                          nsCString& contentType,
                                          nsCString& contentCharset,
                                          PRBool&    isBase64,
-                                         nsCString& dataBuffer);
+                                         nsCString& dataBuffer,
+                                         nsCString& hashRef);
 };
 
 #endif /* nsDataHandler_h___ */