Bug 1093611 - AnchorElement.hash should be the encoded version of the href attribute's fragment r=smaug
☠☠ backed out by 38465268cda5 ☠ ☠
authorValentin Gosu <valentin.gosu@gmail.com>
Wed, 12 Nov 2014 03:14:04 +0200
changeset 217559 ec354ea4ace067706a28d4ca5302d911c5c0d820
parent 217558 8887aaafa0c3e40cd8c9d3ae4667fd8139ad733b
child 217560 17d1b075e274ce2ca6072a5105380a55da4c01d7
push id52315
push uservalentin.gosu@gmail.com
push dateWed, 26 Nov 2014 09:02:53 +0000
treeherdermozilla-inbound@d37a1340fa0b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1093611
milestone36.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 1093611 - AnchorElement.hash should be the encoded version of the href attribute's fragment r=smaug
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
--- a/dom/base/Link.cpp
+++ b/dom/base/Link.cpp
@@ -436,18 +436,20 @@ Link::GetHash(nsAString &_hash, ErrorRes
     // Do not throw!  Not having a valid URI should result in an empty
     // string.
     return;
   }
 
   nsAutoCString ref;
   nsresult rv = uri->GetRef(ref);
   if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
-    NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes!
     _hash.Assign(char16_t('#'));
+    if (!nsContentUtils::ShouldEncodeURLHash()) {
+      NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes!
+    }
     AppendUTF8toUTF16(ref, _hash);
   }
 }
 
 void
 Link::ResetLinkState(bool aNotify, bool aHasHref)
 {
   nsLinkState defaultState;
--- a/dom/base/URL.cpp
+++ b/dom/base/URL.cpp
@@ -509,18 +509,20 @@ URL::SetSearchParams(URLSearchParams& aS
 void
 URL::GetHash(nsString& aHash, ErrorResult& aRv) const
 {
   aHash.Truncate();
 
   nsAutoCString ref;
   nsresult rv = mURI->GetRef(ref);
   if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
-    NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes!
     aHash.Assign(char16_t('#'));
+    if (!nsContentUtils::ShouldEncodeURLHash()) {
+      NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes!
+    }
     AppendUTF8toUTF16(ref, aHash);
   }
 }
 
 void
 URL::SetHash(const nsAString& aHash, ErrorResult& aRv)
 {
   mURI->SetRef(NS_ConvertUTF16toUTF8(aHash));
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -231,16 +231,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;
 
 uint32_t nsContentUtils::sHandlingInputTimeout = 1000;
 
 nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nullptr;
 nsIParser* nsContentUtils::sXMLFragmentParser = nullptr;
 nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nullptr;
 bool nsContentUtils::sFragmentParsingActive = false;
 
@@ -508,16 +509,19 @@ 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::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");
 #endif
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -1848,16 +1848,21 @@ public:
   /*
    * Returns true if the performance timing APIs are enabled.
    */
   static bool IsResourceTimingEnabled()
   {
     return sIsResourceTimingEnabled;
   }
 
+  static bool ShouldEncodeURLHash()
+  {
+    return sEncodeURLHash;
+  }
+
   /**
    * 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.
    */
   static bool HasPluginWithUncontrolledEventDispatch(nsIDocument* aDoc);
 
@@ -2299,16 +2304,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 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
@@ -293,38 +293,46 @@ nsLocation::GetHash(nsAString& aHash)
   if (NS_FAILED(rv) || !uri) {
     return rv;
   }
 
   nsAutoCString ref;
   nsAutoString unicodeRef;
 
   rv = uri->GetRef(ref);
-  if (NS_SUCCEEDED(rv)) {
-    nsCOMPtr<nsITextToSubURI> textToSubURI(
-        do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv));
 
+  if (!nsContentUtils::ShouldEncodeURLHash()) {
     if (NS_SUCCEEDED(rv)) {
-      nsAutoCString charset;
-      uri->GetOriginCharset(charset);
-        
-      rv = textToSubURI->UnEscapeURIForUI(charset, ref, unicodeRef);
+      nsCOMPtr<nsITextToSubURI> textToSubURI(
+          do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv));
+
+      if (NS_SUCCEEDED(rv)) {
+        nsAutoCString charset;
+        uri->GetOriginCharset(charset);
+
+        rv = textToSubURI->UnEscapeURIForUI(charset, ref, unicodeRef);
+      }
+
+      if (NS_FAILED(rv)) {
+        // Oh, well.  No intl here!
+        NS_UnescapeURL(ref);
+        CopyASCIItoUTF16(ref, unicodeRef);
+        rv = NS_OK;
+      }
     }
-      
-    if (NS_FAILED(rv)) {
-      // Oh, well.  No intl here!
-      NS_UnescapeURL(ref);
-      CopyASCIItoUTF16(ref, unicodeRef);
-      rv = NS_OK;
+
+    if (NS_SUCCEEDED(rv) && !unicodeRef.IsEmpty()) {
+      aHash.Assign(char16_t('#'));
+      aHash.Append(unicodeRef);
     }
-  }
-
-  if (NS_SUCCEEDED(rv) && !unicodeRef.IsEmpty()) {
-    aHash.Assign(char16_t('#'));
-    aHash.Append(unicodeRef);
+  } else { // URL Hash should be encoded
+    if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
+      aHash.Assign(char16_t('#'));
+      AppendASCIItoUTF16(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;
   } else {
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -156,16 +156,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 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);
 #endif