Bug 596455 - Do not sanitize input's value while we are parsing. r=bz a=blocking
authorMounir Lamouri <mounir.lamouri@gmail.com>
Mon, 20 Sep 2010 22:33:17 +0200
changeset 54366 82a48093cf930cbb57c48a2255c1d477241693d6
parent 54365 389b151696f6e635bd93e94c32d7e50bf62dfa98
child 54367 2a2ec6c26acf25ee71fe4f5f7703629b71547d5c
push idunknown
push userunknown
push dateunknown
reviewersbz, blocking
bugs596455
milestone2.0b7pre
Bug 596455 - Do not sanitize input's value while we are parsing. r=bz a=blocking
content/html/content/reftests/596455-1a.html
content/html/content/reftests/596455-1b.html
content/html/content/reftests/596455-2a.html
content/html/content/reftests/596455-2b.html
content/html/content/reftests/596455-ref-1.html
content/html/content/reftests/596455-ref-2.html
content/html/content/reftests/reftest.list
content/html/content/src/nsHTMLInputElement.cpp
new file mode 100644
--- /dev/null
+++ b/content/html/content/reftests/596455-1a.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+  <script>
+    function onLoadHandler()
+    {
+      document.getElementById('l').value = document.getElementById('i').value;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onLoadHandler();">
+    <input type='hidden' value='foo&#13;bar' id='i'>
+    <textarea id='l'></textarea>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/reftests/596455-1b.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+  <script>
+    function onLoadHandler()
+    {
+      document.getElementById('l').value = document.getElementById('i').value;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onLoadHandler();">
+    <input value='foo&#13;bar' type='hidden' id='i'>
+    <textarea id='l'></textarea>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/reftests/596455-2a.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+  <script>
+    function onLoadHandler()
+    {
+      document.getElementById('l').value = document.getElementById('i').value;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onLoadHandler();">
+    <input style="display:none;" type='text' value='foo&#13;bar' id='i'>
+    <textarea id='l'></textarea>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/reftests/596455-2b.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+  <script>
+    function onLoadHandler()
+    {
+      document.getElementById('l').value = document.getElementById('i').value;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onLoadHandler();">
+    <input style="display:none;" value='foo&#13;bar' type='text' id='i'>
+    <textarea id='l'></textarea>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/reftests/596455-ref-1.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <textarea>foo&#13;bar</textarea>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/reftests/596455-ref-2.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <textarea>foobar</textarea>
+  </body>
+</html>
--- a/content/html/content/reftests/reftest.list
+++ b/content/html/content/reftests/reftest.list
@@ -8,16 +8,20 @@
 == 468263-2.html 468263-2-ref.html
 == 468263-2.html 468263-2-alternate-ref.html
 == 484200-1.html 484200-1-ref.html
 == 485377.html 485377-ref.html
 == 557840.html 557840-ref.html
 == 560059-video-dimensions.html 560059-video-dimensions-ref.html
 == 573322-quirks.html 573322-quirks-ref.html
 == 573322-no-quirks.html 573322-no-quirks-ref.html
+== 596455-1a.html 596455-ref-1.html
+== 596455-1b.html 596455-ref-1.html
+== 596455-2a.html 596455-ref-2.html
+== 596455-2b.html 596455-ref-2.html
 == hidden-1a.html hidden-1-ref.html
 == hidden-1b.html hidden-1-ref.html
 == hidden-1c.html hidden-1-ref.html
 == hidden-1d.html hidden-1-ref.html
 == hidden-1e.html hidden-1-ref.html
 == hidden-1f.html hidden-1-ref.html
 == hidden-1g.html hidden-1-ref.html
 == hidden-2.svg hidden-2-ref.svg
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -1399,17 +1399,19 @@ nsHTMLInputElement::SetValueInternal(con
     return NS_ERROR_UNEXPECTED;
   }
 
   if (IsSingleLineTextControl(PR_FALSE)) {
     // At the moment, only single line text control have to sanitize their value
     // Because we have to create a new string for that, we should prevent doing
     // it if it's useless.
     nsAutoString value(aValue);
-    SanitizeValue(value);
+    if (!GET_BOOLBIT(mBitField, BF_PARSER_CREATING)) {
+      SanitizeValue(value);
+    }
 
     if (aSetValueChanged) {
       SetValueChanged(PR_TRUE);
     }
     mInputData.mState->SetValue(value, aUserInput);
 
     if (PlaceholderApplies() &&
         HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)) {
@@ -2541,76 +2543,84 @@ nsHTMLInputElement::UnbindFromTree(PRBoo
   UpdateBarredFromConstraintValidation();
 }
 
 void
 nsHTMLInputElement::HandleTypeChange(PRUint8 aNewType)
 {
   ValueModeType aOldValueMode = GetValueMode();
   nsAutoString aOldValue;
-  GetValue(aOldValue);
+
+  if (aOldValueMode == VALUE_MODE_VALUE && !GET_BOOLBIT(mBitField, BF_PARSER_CREATING)) {
+    GetValue(aOldValue);
+  }
 
   // Only single line text inputs have a text editor state.
   PRBool isNewTypeSingleLine =
     IsSingleLineTextControlInternal(PR_FALSE, aNewType);
   PRBool isCurrentTypeSingleLine =
     IsSingleLineTextControl(PR_FALSE);
   if (isNewTypeSingleLine && !isCurrentTypeSingleLine) {
     FreeData();
     mInputData.mState = new nsTextEditorState(this);
     NS_ADDREF(mInputData.mState);
   } else if (isCurrentTypeSingleLine && !isNewTypeSingleLine) {
     FreeData();
   }
 
   mType = aNewType;
 
-  /**
-   * The following code is trying to reproduce the algorithm described here:
-   * http://www.whatwg.org/specs/web-apps/current-work/complete.html#input-type-change
-   */
-  switch (GetValueMode()) {
-    case VALUE_MODE_DEFAULT:
-    case VALUE_MODE_DEFAULT_ON:
-      // If the previous value mode was value, we need to set the value content
-      // attribute to the previous value.
-      // There is no value sanitizing algorithm for elements in this mode.
-      if (aOldValueMode == VALUE_MODE_VALUE && !aOldValue.IsEmpty()) {
-        SetAttr(kNameSpaceID_None, nsGkAtoms::value, aOldValue, PR_TRUE);
-      }
-      break;
-    case VALUE_MODE_VALUE:
-      // If the previous value mode wasn't value, we have to set the value to
-      // the value content attribute.
-      // SetValueInternal is going to sanitize the value.
-      {
-        nsAutoString value;
-        if (aOldValueMode != VALUE_MODE_VALUE) {
-          GetAttr(kNameSpaceID_None, nsGkAtoms::value, value);
-        } else {
-          // We get the current value so we can sanitize it.
-          GetValue(value);
+  if (!GET_BOOLBIT(mBitField, BF_PARSER_CREATING)) {
+    /**
+     * The following code is trying to reproduce the algorithm described here:
+     * http://www.whatwg.org/specs/web-apps/current-work/complete.html#input-type-change
+     */
+    switch (GetValueMode()) {
+      case VALUE_MODE_DEFAULT:
+      case VALUE_MODE_DEFAULT_ON:
+        // If the previous value mode was value, we need to set the value content
+        // attribute to the previous value.
+        // There is no value sanitizing algorithm for elements in this mode.
+        if (aOldValueMode == VALUE_MODE_VALUE && !aOldValue.IsEmpty()) {
+          SetAttr(kNameSpaceID_None, nsGkAtoms::value, aOldValue, PR_TRUE);
         }
-        SetValueInternal(value, PR_FALSE, PR_FALSE);
-      }
-      break;
-    case VALUE_MODE_FILENAME:
-    default:
-      // We don't care about the value.
-      // There is no value sanitizing algorithm for elements in this mode.
-      break;
+        break;
+      case VALUE_MODE_VALUE:
+        // If the previous value mode wasn't value, we have to set the value to
+        // the value content attribute.
+        // SetValueInternal is going to sanitize the value.
+        {
+          nsAutoString value;
+          if (aOldValueMode != VALUE_MODE_VALUE) {
+            GetAttr(kNameSpaceID_None, nsGkAtoms::value, value);
+          } else {
+            // We get the current value so we can sanitize it.
+            GetValue(value);
+          }
+          SetValueInternal(value, PR_FALSE, PR_FALSE);
+        }
+        break;
+      case VALUE_MODE_FILENAME:
+      default:
+        // We don't care about the value.
+        // There is no value sanitizing algorithm for elements in this mode.
+        break;
+    }
   }
 
   // Do not notify, it will be done after if needed.
   UpdateAllValidityStates(PR_FALSE);
 }
 
 void
 nsHTMLInputElement::SanitizeValue(nsAString& aValue)
 {
+  NS_ASSERTION(!GET_BOOLBIT(mBitField, BF_PARSER_CREATING),
+               "The element parsing should be finished!");
+
   switch (mType) {
     case NS_FORM_INPUT_TEXT:
     case NS_FORM_INPUT_SEARCH:
     case NS_FORM_INPUT_TEL:
     case NS_FORM_INPUT_PASSWORD:
     case NS_FORM_INPUT_EMAIL:
       {
         PRUnichar crlf[] = { PRUnichar('\r'), PRUnichar('\n'), 0 };
@@ -3223,16 +3233,23 @@ nsHTMLInputElement::DoneCreatingElement(
   if (!restoredCheckedState &&
       GET_BOOLBIT(mBitField, BF_SHOULD_INIT_CHECKED)) {
     PRBool resetVal;
     GetDefaultChecked(&resetVal);
     DoSetChecked(resetVal, PR_FALSE, PR_TRUE);
     DoSetCheckedChanged(PR_FALSE, PR_FALSE);
   }
 
+  // Sanitize the value.
+  if (GetValueMode() == VALUE_MODE_VALUE) {
+    nsAutoString aValue;
+    GetValue(aValue);
+    SetValueInternal(aValue, PR_FALSE, PR_FALSE);
+  }
+
   SET_BOOLBIT(mBitField, BF_SHOULD_INIT_CHECKED, PR_FALSE);
 }
 
 PRInt32
 nsHTMLInputElement::IntrinsicState() const
 {
   // If you add states here, and they're type-dependent, you need to add them
   // to the type case in AfterSetAttr.
@@ -4315,17 +4332,19 @@ nsHTMLInputElement::GetRows()
 NS_IMETHODIMP_(void)
 nsHTMLInputElement::GetDefaultValueFromContent(nsAString& aValue)
 {
   nsTextEditorState *state = GetEditorState();
   if (state) {
     GetDefaultValue(aValue);
     // This is called by the frame to show the value.
     // We have to sanitize it when needed.
-    SanitizeValue(aValue);
+    if (!GET_BOOLBIT(mBitField, BF_PARSER_CREATING)) {
+      SanitizeValue(aValue);
+    }
   }
 }
 
 NS_IMETHODIMP_(PRBool)
 nsHTMLInputElement::ValueChanged() const
 {
   return GET_BOOLBIT(mBitField, BF_VALUE_CHANGED);
 }