Changeset 120895 in webkit


Ignore:
Timestamp:
Jun 20, 2012 6:31:08 PM (12 years ago)
Author:
tkent@chromium.org
Message:

Unmodified form control value are overwritten by another form
control value with the same name after navigating and going back
https://bugs.webkit.org/show_bug.cgi?id=89409

Reviewed by Hajime Morita.

Source/WebCore:

Detail of the bug:
If a page had multiple form controls of which names and types were
identical like the following:

<input type=text name=name1 id=input1>
<input type=text name=name1 id=input2>

and a user updated the value of the second control, then went to
another page and went back to the page again, we restored the updated
value to the first element, and didn't update the second element.

We didn't save unmodified control state, and the form state data
had no ways to represent "this control should be skipped".

How to resovle the bug:
We need to represent "this control should be skipped" in the
seriazlied form state vector.

  • A serialized control state had three items:

name, type, value.

Now we change it to:

name, type, flag, optional value

  • It is definitely incompatible with serizlized state produced by

older WebCore. So, we need to add the signature string to
represent the version of serialized state format.

  • Because the state for a form control is variable-length and we

can't deserialize it in reverse-order, we change the on-memory
representation from Vector<> to Deque<>.

Test: fast/forms/state-restore-to-non-edited-controls.html

  • html/FormController.cpp:

(WebCore::FormControlState::serializeTo):
Added. Serialize a state for a form control to a string vector.
(WebCore::FormControlState::deserialize):
Added. Produce a FormControlState object from the specified string vector.
It can produce a FromControlState of the failure type.
(WebCore::formStateSignature): The signature string of the serialized state.
(WebCore::FormController::formElementsState):

  • Capacity: The size of seirlized data for one form control is typically 4. +1 for the signature.
  • We need to store a FormControlState with no values.

(WebCore::FormController::setStateForNewFormElements):

  • We can't iterate over the stateVector in reverse order any more because serialized control state is variable-length.
  • We put FormControlState objects to HashMap instead of String objects.

(WebCore::FormController::takeStateForFormElement):

Updated for Deque<>.

  • html/FormController.h:

(FormControlState): Declare deserialize() and serializeTo().
(WebCore::FormControlState::isFailure): Added.
(WebCore::FormControlState::FormControlState):
Added to create a FormControlState with failure type.
(FormController):
Change the value type of m_stateForNewFormElements from Vector<String>
to Deque<FormControlState>.

LayoutTests:

  • fast/forms/resources/state-restore-broken-state-2.html:

Take care of the signature string at the beginning of the array.

  • fast/forms/state-restore-broken-state-expected.txt:

Updated for the serialized format change.

  • fast/forms/state-restore-to-non-edited-controls-expected.txt:
  • fast/forms/state-restore-to-non-edited-controls.html:

Add a test for a case of duplicated names.

Location:
trunk
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r120894 r120895  
     12012-06-20  Kent Tamura  <tkent@chromium.org>
     2
     3        Unmodified form control value are overwritten by another form
     4        control value with the same name after navigating and going back
     5        https://bugs.webkit.org/show_bug.cgi?id=89409
     6
     7        Reviewed by Hajime Morita.
     8
     9        * fast/forms/resources/state-restore-broken-state-2.html:
     10        Take care of the signature string at the beginning of the array.
     11        * fast/forms/state-restore-broken-state-expected.txt:
     12        Updated for the serialized format change.
     13        * fast/forms/state-restore-to-non-edited-controls-expected.txt:
     14        * fast/forms/state-restore-to-non-edited-controls.html:
     15        Add a test for a case of duplicated names.
     16
    1172012-06-20  Adam Barth  <abarth@webkit.org>
    218
  • trunk/LayoutTests/fast/forms/resources/state-restore-broken-state-2.html

    r120397 r120895  
    11<script>
    22setTimeout(function() {
    3     console.log('Generated state: [' + internals.formControlStateOfPreviousHistoryItem() + ']');
     3    var stateArray = internals.formControlStateOfPreviousHistoryItem();
     4    // Omit the signature string because it is volatile.
     5    console.log('Generated state: [' + stateArray.slice(1) + ']');
    46
    5     internals.setFormControlStateOfPreviousHistoryItem(['name1', 'text', 'modified', '***broken***']);
     7    stateArray.push('***broken***');
     8    internals.setFormControlStateOfPreviousHistoryItem(stateArray);
    69    parent.didLoadAnotherDocument();
    710}, 0);
  • trunk/LayoutTests/fast/forms/state-restore-broken-state-expected.txt

    r120397 r120895  
    1 CONSOLE MESSAGE: line 3: Generated state: [name1,text,modified]
     1CONSOLE MESSAGE: line 5: Generated state: [name1,text,1,modified]
    22The value was modified in the first load of state-restore-broken-state-1.html, but it should not be restored because the state-restore-broken-state-2.html breaks the state.
    33
  • trunk/LayoutTests/fast/forms/state-restore-to-non-edited-controls-expected.txt

    r120796 r120895  
    66PASS document.getElementById("reset").value is "2"
    77PASS document.getElementById("submit1").value is "2"
     8PASS document.getElementById("text0").value is "2"
    89PASS document.getElementById("text1").value is "edit"
    910PASS document.getElementById("text2").value is "2"
  • trunk/LayoutTests/fast/forms/state-restore-to-non-edited-controls.html

    r120796 r120895  
    1414<script>
    1515
    16 function makeForm(parent, buttonValue, hiddenValue, imageValue, resetValue, submitValue, textValue1, textValue2, textAreaValue) {
     16function makeForm(parent, buttonValue, hiddenValue, imageValue, resetValue, submitValue, textValue0, textValue1, textValue2, textAreaValue) {
    1717    document.write('<form action="data:text/html,<script>history.back()&lt;/script>" id=form1>'
    1818        + '<input name=button id=button type=button value="' + buttonValue + '">'
     
    2121        + '<input name=reset id=reset type=reset value="' + resetValue + '">'
    2222        + '<input name=submit1 id=submit1 type=submit value="' + submitValue + '">'
     23        + '<input name=text1 id=text0 type=text value="' + textValue0 + '">'
    2324        + '<input name=text1 id=text1 type=text value="' + textValue1 + '">'
    2425        + '<input name=text2 id=text2 type=text value="' + textValue2 + '">'
     
    3637            layoutTestController.waitUntilDone();
    3738        state.value = 'visited';
    38         makeForm(parent, '1', '1', '1', '1', '1', '1', '1', '1');
     39        makeForm(parent, '1', '1', '1', '1', '1', '1', '1', '1', '1');
    3940   
    4041        document.getElementById('text1').value = 'edit';
     
    4344    } else {
    4445        // Second visit.
    45         makeForm(parent, '2', '2', '2', '2', '2', '2', '2', '2');
     46        makeForm(parent, '2', '2', '2', '2', '2', '2', '2', '2', '2');
    4647   
    4748        shouldBe('document.getElementById("button").value', '"2"');
     
    5051        shouldBe('document.getElementById("reset").value', '"2"');
    5152        shouldBe('document.getElementById("submit1").value', '"2"');
     53        shouldBe('document.getElementById("text0").value', '"2"');
    5254        shouldBe('document.getElementById("text1").value', '"edit"');
    5355        shouldBe('document.getElementById("text2").value', '"2"');
  • trunk/Source/WebCore/ChangeLog

    r120893 r120895  
     12012-06-20  Kent Tamura  <tkent@chromium.org>
     2
     3        Unmodified form control value are overwritten by another form
     4        control value with the same name after navigating and going back
     5        https://bugs.webkit.org/show_bug.cgi?id=89409
     6
     7        Reviewed by Hajime Morita.
     8
     9        Detail of the bug:
     10        If a page had multiple form controls of which names and types were
     11        identical like the following:
     12          <input type=text name=name1 id=input1>
     13          <input type=text name=name1 id=input2>
     14        and a user updated the value of the second control, then went to
     15        another page and went back to the page again, we restored the updated
     16        value to the first element, and didn't update the second element.
     17
     18        We didn't save unmodified control state, and the form state data
     19        had no ways to represent "this control should be skipped".
     20
     21        How to resovle the bug:
     22        We need to represent "this control should be skipped" in the
     23        seriazlied form state vector.
     24
     25        - A serialized control state had three items:
     26                name, type, value.
     27          Now we change it to:
     28                name, type, flag, optional value
     29
     30        - It is definitely incompatible with serizlized state produced by
     31        older WebCore. So, we need to add the signature string to
     32        represent the version of serialized state format.
     33
     34        - Because the state for a form control is variable-length and we
     35        can't deserialize it in reverse-order, we change the on-memory
     36        representation from Vector<> to Deque<>.
     37
     38        Test: fast/forms/state-restore-to-non-edited-controls.html
     39
     40        * html/FormController.cpp:
     41        (WebCore::FormControlState::serializeTo):
     42        Added. Serialize a state for a form control to a string vector.
     43        (WebCore::FormControlState::deserialize):
     44        Added. Produce a FormControlState object from the specified string vector.
     45        It can produce a FromControlState of the failure type.
     46        (WebCore::formStateSignature): The signature string of the serialized state.
     47        (WebCore::FormController::formElementsState):
     48         - Capacity:
     49          The size of seirlized data for one form control is typically 4.
     50          +1 for the signature.
     51         - We need to store a FormControlState with no values.
     52        (WebCore::FormController::setStateForNewFormElements):
     53         - We can't iterate over the stateVector in reverse order any more
     54           because serialized control state is variable-length.
     55         - We put FormControlState objects to HashMap instead of String objects.
     56        (WebCore::FormController::takeStateForFormElement):
     57         Updated for Deque<>.
     58        * html/FormController.h:
     59        (FormControlState): Declare deserialize() and serializeTo().
     60        (WebCore::FormControlState::isFailure): Added.
     61        (WebCore::FormControlState::FormControlState):
     62        Added to create a FormControlState with failure type.
     63        (FormController):
     64        Change the value type of m_stateForNewFormElements from Vector<String>
     65        to Deque<FormControlState>.
     66
    1672012-06-20  Alexandru Chiculita  <achicu@adobe.com>
    268
  • trunk/Source/WebCore/html/FormController.cpp

    r120679 r120895  
    2828using namespace HTMLNames;
    2929
     30// ----------------------------------------------------------------------------
     31
     32// Serilized form of FormControlState:
     33//  (',' means strings around it are separated in stateVector.)
     34//
     35// SerializedControlState ::= SkipState | SingleValueState
     36// SkipState ::= '0'
     37// SingleValueState ::= '1', ControlValue
     38// ControlValue ::= arbitrary string
     39
     40void FormControlState::serializeTo(Vector<String>& stateVector) const
     41{
     42    ASSERT(!isFailure());
     43    if (!hasValue())
     44        stateVector.append("0");
     45    else {
     46        stateVector.append("1");
     47        stateVector.append(m_value);
     48    }
     49}
     50
     51FormControlState FormControlState::deserialize(const Vector<String>& stateVector, size_t& index)
     52{
     53    if (index >= stateVector.size())
     54        return FormControlState(TypeFailure);
     55    uint64_t valueSize = stateVector[index++].toUInt64();
     56    if (!valueSize)
     57        return FormControlState();
     58    if (valueSize != 1 || index + 1 > stateVector.size())
     59        return FormControlState(TypeFailure);
     60    return FormControlState(stateVector[index++]);
     61}
     62
     63// ----------------------------------------------------------------------------
     64
     65
    3066FormController::FormController()
    3167{
     
    3672}
    3773
     74static String formStateSignature()
     75{
     76    // In the legacy version of serialized state, the first item was a name
     77    // attribute value of a form control. The following string literal should
     78    // contain some characters which are rarely used for name attribute values.
     79    DEFINE_STATIC_LOCAL(String, signature, ("\n\r?% WebKit serialized form state version 1 \n\r=&"));
     80    return signature;
     81}
     82
    3883Vector<String> FormController::formElementsState() const
    3984{
    4085    Vector<String> stateVector;
    41     stateVector.reserveInitialCapacity(m_formElementsWithState.size() * 3);
     86    stateVector.reserveInitialCapacity(m_formElementsWithState.size() * 4 + 1);
     87    stateVector.append(formStateSignature());
    4288    typedef FormElementListHashSet::const_iterator Iterator;
    4389    Iterator end = m_formElementsWithState.end();
     
    4692        if (!elementWithState->shouldSaveAndRestoreFormControlState())
    4793            continue;
    48         FormControlState state = elementWithState->saveFormControlState();
    49         if (!state.hasValue())
    50             continue;
    5194        stateVector.append(elementWithState->name().string());
    5295        stateVector.append(elementWithState->formControlType().string());
    53         stateVector.append(state.value());
     96        elementWithState->saveFormControlState().serializeTo(stateVector);
    5497    }
    5598    return stateVector;
     
    63106void FormController::setStateForNewFormElements(const Vector<String>& stateVector)
    64107{
    65     // Walk the state vector backwards so that the value to use for each
    66     // name/type pair first is the one at the end of each individual vector
    67     // in the FormElementStateMap. We're using them like stacks.
    68108    typedef FormElementStateMap::iterator Iterator;
    69109    m_formElementsWithState.clear();
    70110
    71     if (stateVector.size() % 3)
     111    size_t i = 0;
     112    if (stateVector.size() < 1 || stateVector[i++] != formStateSignature())
    72113        return;
    73     for (size_t i = 0; i < stateVector.size(); i += 3) {
    74         if (stateVector[i + 1].find(isNotFormControlTypeCharacter) != notFound)
    75             return;
    76     }
    77 
    78     for (size_t i = stateVector.size() / 3 * 3; i; i -= 3) {
    79         AtomicString name = stateVector[i - 3];
    80         AtomicString type = stateVector[i - 2];
    81         const String& value = stateVector[i - 1];
     114
     115    while (i + 2 < stateVector.size()) {
     116        AtomicString name = stateVector[i++];
     117        AtomicString type = stateVector[i++];
     118        FormControlState state = FormControlState::deserialize(stateVector, i);
     119        if (type.isEmpty() || type.impl()->find(isNotFormControlTypeCharacter) != notFound || state.isFailure())
     120            break;
     121
    82122        FormElementKey key(name.impl(), type.impl());
    83123        Iterator it = m_stateForNewFormElements.find(key);
    84124        if (it != m_stateForNewFormElements.end())
    85             it->second.append(value);
     125            it->second.append(state);
    86126        else {
    87             Vector<String> valueList(1);
    88             valueList[0] = value;
    89             m_stateForNewFormElements.set(key, valueList);
     127            Deque<FormControlState> stateList;
     128            stateList.append(state);
     129            m_stateForNewFormElements.set(key, stateList);
    90130        }
    91131    }
     132    if (i != stateVector.size())
     133        m_stateForNewFormElements.clear();
    92134}
    93135
     
    104146        return FormControlState();
    105147    ASSERT(it->second.size());
    106     FormControlState state(it->second.last());
    107     if (it->second.size() > 1)
    108         it->second.removeLast();
    109     else
     148    FormControlState state = it->second.takeFirst();
     149    if (!it->second.size())
    110150        m_stateForNewFormElements.remove(it);
    111151    return state;
  • trunk/Source/WebCore/html/FormController.h

    r120679 r120895  
    2424
    2525#include "CheckedRadioButtons.h"
     26#include <wtf/Deque.h>
    2627#include <wtf/Forward.h>
    2728#include <wtf/ListHashSet.h>
     
    7879    FormControlState() : m_type(TypeSkip) { }
    7980    explicit FormControlState(const String& value) : m_type(TypeRestore), m_value(value) { }
     81    static FormControlState deserialize(const Vector<String>& stateVector, size_t& index);
    8082    FormControlState(const FormControlState& another) : m_type(another.m_type), m_value(another.m_value) { }
    8183    FormControlState& operator=(const FormControlState&);
    8284
     85    bool isFailure() const { return m_type == TypeFailure; }
    8386    bool hasValue() const { return m_type == TypeRestore; }
    8487    String value() const { return m_value; }
     88    void serializeTo(Vector<String>& stateVector) const;
    8589
    8690private:
    87     enum Type { TypeSkip, TypeRestore };
     91    enum Type { TypeSkip, TypeRestore, TypeFailure };
     92    explicit FormControlState(Type type) : m_type(type) { }
     93
    8894    Type m_type;
    8995    String m_value;
     
    130136    FormAssociatedElementListHashSet m_formElementsWithFormAttribute;
    131137
    132     typedef HashMap<FormElementKey, Vector<String>, FormElementKeyHash, FormElementKeyHashTraits> FormElementStateMap;
     138    typedef HashMap<FormElementKey, Deque<FormControlState>, FormElementKeyHash, FormElementKeyHashTraits> FormElementStateMap;
    133139    FormElementStateMap m_stateForNewFormElements;
    134140   
Note: See TracChangeset for help on using the changeset viewer.