Bug 1093611 - nsStandardURL::SetRef only does percent-encoding if dom.url.encode_decode_hash is true r=honzab
authorValentin Gosu <valentin.gosu@gmail.com>
Tue, 13 Jan 2015 02:11:02 +0200
changeset 250567 c270a096d97aecf4a398e675cdfc9aa36274d70b
parent 250566 c602d8753a4e90d3bb31046106319e388c710a0f
child 250568 948c42f9cd3a7acac6ef89c569d328ab64d1dde5
push idunknown
push userunknown
push dateunknown
reviewershonzab
bugs1093611
milestone38.0a1
Bug 1093611 - nsStandardURL::SetRef only does percent-encoding if dom.url.encode_decode_hash is true r=honzab
dom/base/Link.cpp
dom/base/URL.cpp
dom/base/nsContentUtils.cpp
dom/base/nsContentUtils.h
dom/base/nsLocation.cpp
modules/libpref/init/all.js
netwerk/base/src/nsStandardURL.cpp
--- a/dom/base/Link.cpp
+++ b/dom/base/Link.cpp
@@ -437,17 +437,17 @@ Link::GetHash(nsAString &_hash, ErrorRes
     // string.
     return;
   }
 
   nsAutoCString ref;
   nsresult rv = uri->GetRef(ref);
   if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
     _hash.Assign(char16_t('#'));
-    if (!nsContentUtils::ShouldEncodeURLHash()) {
+    if (nsContentUtils::EncodeDecodeURLHash()) {
       NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes!
     }
     AppendUTF8toUTF16(ref, _hash);
   }
 }
 
 void
 Link::ResetLinkState(bool aNotify, bool aHasHref)
--- a/dom/base/URL.cpp
+++ b/dom/base/URL.cpp
@@ -510,17 +510,17 @@ void
 URL::GetHash(nsString& aHash, ErrorResult& aRv) const
 {
   aHash.Truncate();
 
   nsAutoCString ref;
   nsresult rv = mURI->GetRef(ref);
   if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
     aHash.Assign(char16_t('#'));
-    if (!nsContentUtils::ShouldEncodeURLHash()) {
+    if (nsContentUtils::EncodeDecodeURLHash()) {
       NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes!
     }
     AppendUTF8toUTF16(ref, aHash);
   }
 }
 
 void
 URL::SetHash(const nsAString& aHash, ErrorResult& aRv)
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -238,17 +238,17 @@ nsString* nsContentUtils::sModifierSepar
 
 bool nsContentUtils::sInitialized = false;
 bool nsContentUtils::sIsFullScreenApiEnabled = false;
 bool nsContentUtils::sTrustedFullScreenOnly = true;
 bool nsContentUtils::sFullscreenApiIsContentOnly = false;
 bool nsContentUtils::sIsPerformanceTimingEnabled = false;
 bool nsContentUtils::sIsResourceTimingEnabled = false;
 bool nsContentUtils::sIsExperimentalAutocompleteEnabled = false;
-bool nsContentUtils::sEncodeURLHash = true;
+bool nsContentUtils::sEncodeDecodeURLHash = false;
 
 uint32_t nsContentUtils::sHandlingInputTimeout = 1000;
 
 nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nullptr;
 nsIParser* nsContentUtils::sXMLFragmentParser = nullptr;
 nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nullptr;
 bool nsContentUtils::sFragmentParsingActive = false;
 
@@ -516,18 +516,18 @@ nsContentUtils::Init()
                                "dom.enable_performance", true);
 
   Preferences::AddBoolVarCache(&sIsResourceTimingEnabled,
                                "dom.enable_resource_timing", true);
 
   Preferences::AddBoolVarCache(&sIsExperimentalAutocompleteEnabled,
                                "dom.forms.autocomplete.experimental", false);
 
-  Preferences::AddBoolVarCache(&sEncodeURLHash,
-                               "dom.url.encode_hash", true);
+  Preferences::AddBoolVarCache(&sEncodeDecodeURLHash,
+                               "dom.url.encode_decode_hash", false);
 
   Preferences::AddUintVarCache(&sHandlingInputTimeout,
                                "dom.event.handling-user-input-time-limit",
                                1000);
 
 #if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
   Preferences::AddBoolVarCache(&sDOMWindowDumpEnabled,
                                "browser.dom.window.dump.enabled");
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -1855,19 +1855,23 @@ public:
   /*
    * Returns true if the performance timing APIs are enabled.
    */
   static bool IsResourceTimingEnabled()
   {
     return sIsResourceTimingEnabled;
   }
 
-  static bool ShouldEncodeURLHash()
+  /*
+   * Returns true if URL setters should percent encode the Hash/Ref segment
+   * and getters should return the percent decoded value of the segment
+   */
+  static bool EncodeDecodeURLHash()
   {
-    return sEncodeURLHash;
+    return sEncodeDecodeURLHash;
   }
 
   /**
    * Returns true if the doc tree branch which contains aDoc contains any
    * plugins which we don't control event dispatch for, i.e. do any plugins
    * in the same tab as this document receive key events outside of our
    * control? This always returns false on MacOSX.
    */
@@ -2323,17 +2327,17 @@ private:
   static bool sAllowXULXBL_for_file;
   static bool sIsFullScreenApiEnabled;
   static bool sTrustedFullScreenOnly;
   static bool sFullscreenApiIsContentOnly;
   static uint32_t sHandlingInputTimeout;
   static bool sIsPerformanceTimingEnabled;
   static bool sIsResourceTimingEnabled;
   static bool sIsExperimentalAutocompleteEnabled;
-  static bool sEncodeURLHash;
+  static bool sEncodeDecodeURLHash;
 
   static nsHtml5StringParser* sHTMLFragmentParser;
   static nsIParser* sXMLFragmentParser;
   static nsIFragmentContentSink* sXMLFragmentSink;
 
   /**
    * True if there's a fragment parser activation on the stack.
    */
--- a/dom/base/nsLocation.cpp
+++ b/dom/base/nsLocation.cpp
@@ -294,17 +294,17 @@ nsLocation::GetHash(nsAString& aHash)
     return rv;
   }
 
   nsAutoCString ref;
   nsAutoString unicodeRef;
 
   rv = uri->GetRef(ref);
 
-  if (!nsContentUtils::ShouldEncodeURLHash()) {
+  if (nsContentUtils::EncodeDecodeURLHash()) {
     if (NS_SUCCEEDED(rv)) {
       nsCOMPtr<nsITextToSubURI> textToSubURI(
           do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv));
 
       if (NS_SUCCEEDED(rv)) {
         nsAutoCString charset;
         uri->GetOriginCharset(charset);
 
@@ -318,20 +318,20 @@ nsLocation::GetHash(nsAString& aHash)
         rv = NS_OK;
       }
     }
 
     if (NS_SUCCEEDED(rv) && !unicodeRef.IsEmpty()) {
       aHash.Assign(char16_t('#'));
       aHash.Append(unicodeRef);
     }
-  } else { // URL Hash should be encoded
+  } else { // URL Hash should simply return the value of the Ref segment
     if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
       aHash.Assign(char16_t('#'));
-      AppendASCIItoUTF16(ref, aHash);
+      AppendUTF8toUTF16(ref, aHash);
     }
   }
 
   if (aHash == mCachedHash) {
     // Work around ShareThis stupidly polling location.hash every
     // 5ms all the time by handing out the same exact string buffer
     // we handed out last time.
     aHash = mCachedHash;
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -166,18 +166,19 @@ pref("dom.keyboardevent.code.enabled", t
 #endif
 
 // Whether the WebCrypto API is enabled
 pref("dom.webcrypto.enabled", true);
 
 // Whether the UndoManager API is enabled
 pref("dom.undo_manager.enabled", false);
 
-// Whether URL,nsLocation,Link::GetHash should be percent encoded.
-pref("dom.url.encode_hash", true);
+// Whether URL,nsLocation,Link::GetHash should be percent encoded
+// in setter and percent decoded in getter (old behaviour = true)
+pref("dom.url.encode_decode_hash", false);
 
 // Whether to run add-on code in different compartments from browser code. This
 // causes a separate compartment for each (addon, global) combination, which may
 // significantly increase the number of compartments in the system.
 #ifdef NIGHTLY_BUILD
 pref("dom.compartment_per_addon", true);
 #else
 pref("dom.compartment_per_addon", false);
--- a/netwerk/base/src/nsStandardURL.cpp
+++ b/netwerk/base/src/nsStandardURL.cpp
@@ -19,16 +19,17 @@
 #include "nsAutoPtr.h"
 #include "nsIProgrammingLanguage.h"
 #include "nsIURLParser.h"
 #include "nsNetCID.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/ipc/URIUtils.h"
 #include <algorithm>
 #include "mozilla/dom/EncodingUtils.h"
+#include "nsContentUtils.h"
 
 using mozilla::dom::EncodingUtils;
 using namespace mozilla::ipc;
 
 static NS_DEFINE_CID(kThisImplCID, NS_THIS_STANDARDURL_IMPL_CID);
 static NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID);
 
 nsIIDNService *nsStandardURL::gIDN = nullptr;
@@ -548,18 +549,26 @@ nsStandardURL::BuildNormalizedSpec(const
         approxLen += encoder.EncodeSegmentCount(spec, mExtension, esc_FileExtension, encExtension, useEncExtension, 1);
 
         // These next ones *always* add their leading character even if length is 0
         // Handles items like "http://#"
         // ?query
         if (mQuery.mLen >= 0)
             approxLen += 1 + queryEncoder.EncodeSegmentCount(spec, mQuery, esc_Query,        encQuery,     useEncQuery);
         // #ref
-        if (mRef.mLen >= 0)
-            approxLen += 1 + encoder.EncodeSegmentCount(spec, mRef,       esc_Ref,           encRef,       useEncRef);
+
+        if (mRef.mLen >= 0) {
+            if (nsContentUtils::EncodeDecodeURLHash()) {
+                approxLen += 1 + encoder.EncodeSegmentCount(spec, mRef, esc_Ref,
+                                                            encRef, useEncRef);
+            } else {
+                approxLen += 1 + mRef.mLen;
+                useEncRef = false;
+            }
+        }
     }
 
     // do not escape the hostname, if IPv6 address literal, mHost will
     // already point to a [ ] delimited IPv6 address literal.
     // However, perform Unicode normalization on it, as IDN does.
     mHostEncoding = eEncoding_ASCII;
     // Note that we don't disallow URLs without a host - file:, etc
     if (mHost.mLen > 0) {
@@ -2453,25 +2462,27 @@ nsStandardURL::SetRef(const nsACString &
     
     if (mRef.mLen < 0) {
         mSpec.Append('#');
         ++mPath.mLen;  // Include the # in the path.
         mRef.mPos = mSpec.Length();
         mRef.mLen = 0;
     }
 
-    // encode ref if necessary
-    nsAutoCString buf;
-    bool encoded;
-    GET_SEGMENT_ENCODER(encoder);
-    encoder.EncodeSegmentCount(ref, URLSegment(0, refLen), esc_Ref,
-                               buf, encoded);
-    if (encoded) {
-        ref = buf.get();
-        refLen = buf.Length();
+    if (nsContentUtils::EncodeDecodeURLHash()) {
+        // encode ref if necessary
+        nsAutoCString buf;
+        bool encoded;
+        GET_SEGMENT_ENCODER(encoder);
+        encoder.EncodeSegmentCount(ref, URLSegment(0, refLen), esc_Ref,
+                                   buf, encoded);
+        if (encoded) {
+            ref = buf.get();
+            refLen = buf.Length();
+        }
     }
 
     int32_t shift = ReplaceSegment(mRef.mPos, mRef.mLen, ref, refLen);
     mPath.mLen += shift;
     mRef.mLen = refLen;
     return NS_OK;
 }