Home | History | Annotate | Download | only in html
      1 /*
      2  * Copyright (C) 2006, 2008, 2009, 2010 Apple Inc. All rights reserved.
      3  * Copyright (C) 2010, 2011, 2012 Google Inc. All rights reserved.
      4  *
      5  * This library is free software; you can redistribute it and/or
      6  * modify it under the terms of the GNU Library General Public
      7  * License as published by the Free Software Foundation; either
      8  * version 2 of the License, or (at your option) any later version.
      9  *
     10  * This library is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  * Library General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU Library General Public License
     16  * along with this library; see the file COPYING.LIB.  If not, write to
     17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18  * Boston, MA 02110-1301, USA.
     19  */
     20 
     21 #include "config.h"
     22 #include "core/html/FormController.h"
     23 
     24 #include "core/html/HTMLFormControlElementWithState.h"
     25 #include "core/html/HTMLFormElement.h"
     26 #include "core/html/HTMLInputElement.h"
     27 #include "core/platform/FileChooser.h"
     28 #include "wtf/HashTableDeletedValueType.h"
     29 #include "wtf/text/StringBuilder.h"
     30 
     31 namespace WebCore {
     32 
     33 using namespace HTMLNames;
     34 
     35 static inline HTMLFormElement* ownerFormForState(const HTMLFormControlElementWithState& control)
     36 {
     37     // Assume controls with form attribute have no owners because we restore
     38     // state during parsing and form owners of such controls might be
     39     // indeterminate.
     40     return control.fastHasAttribute(formAttr) ? 0 : control.form();
     41 }
     42 
     43 // ----------------------------------------------------------------------------
     44 
     45 // Serilized form of FormControlState:
     46 //  (',' means strings around it are separated in stateVector.)
     47 //
     48 // SerializedControlState ::= SkipState | RestoreState
     49 // SkipState ::= '0'
     50 // RestoreState ::= UnsignedNumber, ControlValue+
     51 // UnsignedNumber ::= [0-9]+
     52 // ControlValue ::= arbitrary string
     53 //
     54 // RestoreState has a sequence of ControlValues. The length of the
     55 // sequence is represented by UnsignedNumber.
     56 
     57 void FormControlState::serializeTo(Vector<String>& stateVector) const
     58 {
     59     ASSERT(!isFailure());
     60     stateVector.append(String::number(m_values.size()));
     61     for (size_t i = 0; i < m_values.size(); ++i)
     62         stateVector.append(m_values[i].isNull() ? emptyString() : m_values[i]);
     63 }
     64 
     65 FormControlState FormControlState::deserialize(const Vector<String>& stateVector, size_t& index)
     66 {
     67     if (index >= stateVector.size())
     68         return FormControlState(TypeFailure);
     69     size_t valueSize = stateVector[index++].toUInt();
     70     if (!valueSize)
     71         return FormControlState();
     72     if (index + valueSize > stateVector.size())
     73         return FormControlState(TypeFailure);
     74     FormControlState state;
     75     state.m_values.reserveCapacity(valueSize);
     76     for (size_t i = 0; i < valueSize; ++i)
     77         state.append(stateVector[index++]);
     78     return state;
     79 }
     80 
     81 // ----------------------------------------------------------------------------
     82 
     83 class FormElementKey {
     84 public:
     85     FormElementKey(StringImpl* = 0, StringImpl* = 0);
     86     ~FormElementKey();
     87     FormElementKey(const FormElementKey&);
     88     FormElementKey& operator=(const FormElementKey&);
     89 
     90     StringImpl* name() const { return m_name; }
     91     StringImpl* type() const { return m_type; }
     92 
     93     // Hash table deleted values, which are only constructed and never copied or destroyed.
     94     FormElementKey(WTF::HashTableDeletedValueType) : m_name(hashTableDeletedValue()) { }
     95     bool isHashTableDeletedValue() const { return m_name == hashTableDeletedValue(); }
     96 
     97 private:
     98     void ref() const;
     99     void deref() const;
    100 
    101     static StringImpl* hashTableDeletedValue() { return reinterpret_cast<StringImpl*>(-1); }
    102 
    103     StringImpl* m_name;
    104     StringImpl* m_type;
    105 };
    106 
    107 FormElementKey::FormElementKey(StringImpl* name, StringImpl* type)
    108     : m_name(name)
    109     , m_type(type)
    110 {
    111     ref();
    112 }
    113 
    114 FormElementKey::~FormElementKey()
    115 {
    116     deref();
    117 }
    118 
    119 FormElementKey::FormElementKey(const FormElementKey& other)
    120     : m_name(other.name())
    121     , m_type(other.type())
    122 {
    123     ref();
    124 }
    125 
    126 FormElementKey& FormElementKey::operator=(const FormElementKey& other)
    127 {
    128     other.ref();
    129     deref();
    130     m_name = other.name();
    131     m_type = other.type();
    132     return *this;
    133 }
    134 
    135 void FormElementKey::ref() const
    136 {
    137     if (name())
    138         name()->ref();
    139     if (type())
    140         type()->ref();
    141 }
    142 
    143 void FormElementKey::deref() const
    144 {
    145     if (name())
    146         name()->deref();
    147     if (type())
    148         type()->deref();
    149 }
    150 
    151 inline bool operator==(const FormElementKey& a, const FormElementKey& b)
    152 {
    153     return a.name() == b.name() && a.type() == b.type();
    154 }
    155 
    156 struct FormElementKeyHash {
    157     static unsigned hash(const FormElementKey&);
    158     static bool equal(const FormElementKey& a, const FormElementKey& b) { return a == b; }
    159     static const bool safeToCompareToEmptyOrDeleted = true;
    160 };
    161 
    162 unsigned FormElementKeyHash::hash(const FormElementKey& key)
    163 {
    164     return StringHasher::hashMemory<sizeof(FormElementKey)>(&key);
    165 }
    166 
    167 struct FormElementKeyHashTraits : WTF::GenericHashTraits<FormElementKey> {
    168     static void constructDeletedValue(FormElementKey& slot) { new (NotNull, &slot) FormElementKey(WTF::HashTableDeletedValue); }
    169     static bool isDeletedValue(const FormElementKey& value) { return value.isHashTableDeletedValue(); }
    170 };
    171 
    172 // ----------------------------------------------------------------------------
    173 
    174 class SavedFormState {
    175     WTF_MAKE_NONCOPYABLE(SavedFormState);
    176     WTF_MAKE_FAST_ALLOCATED;
    177 
    178 public:
    179     static PassOwnPtr<SavedFormState> create();
    180     static PassOwnPtr<SavedFormState> deserialize(const Vector<String>&, size_t& index);
    181     void serializeTo(Vector<String>&) const;
    182     bool isEmpty() const { return m_stateForNewFormElements.isEmpty(); }
    183     void appendControlState(const AtomicString& name, const AtomicString& type, const FormControlState&);
    184     FormControlState takeControlState(const AtomicString& name, const AtomicString& type);
    185 
    186     Vector<String> getReferencedFilePaths() const;
    187 
    188 private:
    189     SavedFormState() : m_controlStateCount(0) { }
    190 
    191     typedef HashMap<FormElementKey, Deque<FormControlState>, FormElementKeyHash, FormElementKeyHashTraits> FormElementStateMap;
    192     FormElementStateMap m_stateForNewFormElements;
    193     size_t m_controlStateCount;
    194 };
    195 
    196 PassOwnPtr<SavedFormState> SavedFormState::create()
    197 {
    198     return adoptPtr(new SavedFormState);
    199 }
    200 
    201 static bool isNotFormControlTypeCharacter(UChar ch)
    202 {
    203     return ch != '-' && (ch > 'z' || ch < 'a');
    204 }
    205 
    206 PassOwnPtr<SavedFormState> SavedFormState::deserialize(const Vector<String>& stateVector, size_t& index)
    207 {
    208     if (index >= stateVector.size())
    209         return nullptr;
    210     // FIXME: We need String::toSizeT().
    211     size_t itemCount = stateVector[index++].toUInt();
    212     if (!itemCount)
    213         return nullptr;
    214     OwnPtr<SavedFormState> savedFormState = adoptPtr(new SavedFormState);
    215     while (itemCount--) {
    216         if (index + 1 >= stateVector.size())
    217             return nullptr;
    218         String name = stateVector[index++];
    219         String type = stateVector[index++];
    220         FormControlState state = FormControlState::deserialize(stateVector, index);
    221         if (type.isEmpty() || type.find(isNotFormControlTypeCharacter) != notFound || state.isFailure())
    222             return nullptr;
    223         savedFormState->appendControlState(name, type, state);
    224     }
    225     return savedFormState.release();
    226 }
    227 
    228 void SavedFormState::serializeTo(Vector<String>& stateVector) const
    229 {
    230     stateVector.append(String::number(m_controlStateCount));
    231     for (FormElementStateMap::const_iterator it = m_stateForNewFormElements.begin(); it != m_stateForNewFormElements.end(); ++it) {
    232         const FormElementKey& key = it->key;
    233         const Deque<FormControlState>& queue = it->value;
    234         for (Deque<FormControlState>::const_iterator queIterator = queue.begin(); queIterator != queue.end(); ++queIterator) {
    235             stateVector.append(key.name());
    236             stateVector.append(key.type());
    237             queIterator->serializeTo(stateVector);
    238         }
    239     }
    240 }
    241 
    242 void SavedFormState::appendControlState(const AtomicString& name, const AtomicString& type, const FormControlState& state)
    243 {
    244     FormElementKey key(name.impl(), type.impl());
    245     FormElementStateMap::iterator it = m_stateForNewFormElements.find(key);
    246     if (it != m_stateForNewFormElements.end())
    247         it->value.append(state);
    248     else {
    249         Deque<FormControlState> stateList;
    250         stateList.append(state);
    251         m_stateForNewFormElements.set(key, stateList);
    252     }
    253     m_controlStateCount++;
    254 }
    255 
    256 FormControlState SavedFormState::takeControlState(const AtomicString& name, const AtomicString& type)
    257 {
    258     if (m_stateForNewFormElements.isEmpty())
    259         return FormControlState();
    260     FormElementStateMap::iterator it = m_stateForNewFormElements.find(FormElementKey(name.impl(), type.impl()));
    261     if (it == m_stateForNewFormElements.end())
    262         return FormControlState();
    263     ASSERT(it->value.size());
    264     FormControlState state = it->value.takeFirst();
    265     m_controlStateCount--;
    266     if (!it->value.size())
    267         m_stateForNewFormElements.remove(it);
    268     return state;
    269 }
    270 
    271 Vector<String> SavedFormState::getReferencedFilePaths() const
    272 {
    273     Vector<String> toReturn;
    274     for (FormElementStateMap::const_iterator it = m_stateForNewFormElements.begin(); it != m_stateForNewFormElements.end(); ++it) {
    275         const FormElementKey& key = it->key;
    276         if (!equal(key.type(), "file", 4))
    277             continue;
    278         const Deque<FormControlState>& queue = it->value;
    279         for (Deque<FormControlState>::const_iterator queIterator = queue.begin(); queIterator != queue.end(); ++queIterator) {
    280             const Vector<FileChooserFileInfo>& selectedFiles = HTMLInputElement::filesFromFileInputFormControlState(*queIterator);
    281             for (size_t i = 0; i < selectedFiles.size(); ++i)
    282                 toReturn.append(selectedFiles[i].path);
    283         }
    284     }
    285     return toReturn;
    286 }
    287 
    288 // ----------------------------------------------------------------------------
    289 
    290 class FormKeyGenerator {
    291     WTF_MAKE_NONCOPYABLE(FormKeyGenerator);
    292     WTF_MAKE_FAST_ALLOCATED;
    293 
    294 public:
    295     static PassOwnPtr<FormKeyGenerator> create() { return adoptPtr(new FormKeyGenerator); }
    296     AtomicString formKey(const HTMLFormControlElementWithState&);
    297     void willDeleteForm(HTMLFormElement*);
    298 
    299 private:
    300     FormKeyGenerator() { }
    301 
    302     typedef HashMap<HTMLFormElement*, AtomicString> FormToKeyMap;
    303     typedef HashMap<String, unsigned> FormSignatureToNextIndexMap;
    304     FormToKeyMap m_formToKeyMap;
    305     FormSignatureToNextIndexMap m_formSignatureToNextIndexMap;
    306 };
    307 
    308 static inline void recordFormStructure(const HTMLFormElement& form, StringBuilder& builder)
    309 {
    310     // 2 is enough to distinguish forms in webkit.org/b/91209#c0
    311     const size_t namedControlsToBeRecorded = 2;
    312     const Vector<FormAssociatedElement*>& controls = form.associatedElements();
    313     builder.append(" [");
    314     for (size_t i = 0, namedControls = 0; i < controls.size() && namedControls < namedControlsToBeRecorded; ++i) {
    315         if (!controls[i]->isFormControlElementWithState())
    316             continue;
    317         HTMLFormControlElementWithState* control = static_cast<HTMLFormControlElementWithState*>(controls[i]);
    318         if (!ownerFormForState(*control))
    319             continue;
    320         AtomicString name = control->name();
    321         if (name.isEmpty())
    322             continue;
    323         namedControls++;
    324         builder.append(name);
    325         builder.append(" ");
    326     }
    327     builder.append("]");
    328 }
    329 
    330 static inline String formSignature(const HTMLFormElement& form)
    331 {
    332     KURL actionURL = form.getURLAttribute(actionAttr);
    333     // Remove the query part because it might contain volatile parameters such
    334     // as a session key.
    335     actionURL.setQuery(String());
    336     StringBuilder builder;
    337     if (!actionURL.isEmpty())
    338         builder.append(actionURL.string());
    339 
    340     recordFormStructure(form, builder);
    341     return builder.toString();
    342 }
    343 
    344 AtomicString FormKeyGenerator::formKey(const HTMLFormControlElementWithState& control)
    345 {
    346     HTMLFormElement* form = ownerFormForState(control);
    347     if (!form) {
    348         DEFINE_STATIC_LOCAL(AtomicString, formKeyForNoOwner, ("No owner", AtomicString::ConstructFromLiteral));
    349         return formKeyForNoOwner;
    350     }
    351     FormToKeyMap::const_iterator it = m_formToKeyMap.find(form);
    352     if (it != m_formToKeyMap.end())
    353         return it->value;
    354 
    355     String signature = formSignature(*form);
    356     ASSERT(!signature.isNull());
    357     FormSignatureToNextIndexMap::AddResult result = m_formSignatureToNextIndexMap.add(signature, 0);
    358     unsigned nextIndex = result.iterator->value++;
    359 
    360     StringBuilder builder;
    361     builder.append(signature);
    362     builder.appendLiteral(" #");
    363     builder.appendNumber(nextIndex);
    364     AtomicString formKey = builder.toAtomicString();
    365     m_formToKeyMap.add(form, formKey);
    366     return formKey;
    367 }
    368 
    369 void FormKeyGenerator::willDeleteForm(HTMLFormElement* form)
    370 {
    371     ASSERT(form);
    372     m_formToKeyMap.remove(form);
    373 }
    374 
    375 // ----------------------------------------------------------------------------
    376 
    377 FormController::FormController()
    378 {
    379 }
    380 
    381 FormController::~FormController()
    382 {
    383 }
    384 
    385 static String formStateSignature()
    386 {
    387     // In the legacy version of serialized state, the first item was a name
    388     // attribute value of a form control. The following string literal should
    389     // contain some characters which are rarely used for name attribute values.
    390     DEFINE_STATIC_LOCAL(String, signature, ("\n\r?% WebKit serialized form state version 8 \n\r=&"));
    391     return signature;
    392 }
    393 
    394 PassOwnPtr<FormController::SavedFormStateMap> FormController::createSavedFormStateMap(const FormElementListHashSet& controlList)
    395 {
    396     OwnPtr<FormKeyGenerator> keyGenerator = FormKeyGenerator::create();
    397     OwnPtr<SavedFormStateMap> stateMap = adoptPtr(new SavedFormStateMap);
    398     for (FormElementListHashSet::const_iterator it = controlList.begin(); it != controlList.end(); ++it) {
    399         HTMLFormControlElementWithState* control = (*it).get();
    400         ASSERT(control->inDocument());
    401         if (!control->shouldSaveAndRestoreFormControlState())
    402             continue;
    403         SavedFormStateMap::AddResult result = stateMap->add(keyGenerator->formKey(*control).impl(), nullptr);
    404         if (result.isNewEntry)
    405             result.iterator->value = SavedFormState::create();
    406         result.iterator->value->appendControlState(control->name(), control->type(), control->saveFormControlState());
    407     }
    408     return stateMap.release();
    409 }
    410 
    411 Vector<String> FormController::formElementsState() const
    412 {
    413     OwnPtr<SavedFormStateMap> stateMap = createSavedFormStateMap(m_formElementsWithState);
    414     Vector<String> stateVector;
    415     stateVector.reserveInitialCapacity(m_formElementsWithState.size() * 4);
    416     stateVector.append(formStateSignature());
    417     for (SavedFormStateMap::const_iterator it = stateMap->begin(); it != stateMap->end(); ++it) {
    418         stateVector.append(it->key);
    419         it->value->serializeTo(stateVector);
    420     }
    421     bool hasOnlySignature = stateVector.size() == 1;
    422     if (hasOnlySignature)
    423         stateVector.clear();
    424     return stateVector;
    425 }
    426 
    427 void FormController::setStateForNewFormElements(const Vector<String>& stateVector)
    428 {
    429     formStatesFromStateVector(stateVector, m_savedFormStateMap);
    430 }
    431 
    432 FormControlState FormController::takeStateForFormElement(const HTMLFormControlElementWithState& control)
    433 {
    434     if (m_savedFormStateMap.isEmpty())
    435         return FormControlState();
    436     if (!m_formKeyGenerator)
    437         m_formKeyGenerator = FormKeyGenerator::create();
    438     SavedFormStateMap::iterator it = m_savedFormStateMap.find(m_formKeyGenerator->formKey(control).impl());
    439     if (it == m_savedFormStateMap.end())
    440         return FormControlState();
    441     FormControlState state = it->value->takeControlState(control.name(), control.type());
    442     if (it->value->isEmpty())
    443         m_savedFormStateMap.remove(it);
    444     return state;
    445 }
    446 
    447 void FormController::formStatesFromStateVector(const Vector<String>& stateVector, SavedFormStateMap& map)
    448 {
    449     map.clear();
    450 
    451     size_t i = 0;
    452     if (stateVector.size() < 1 || stateVector[i++] != formStateSignature())
    453         return;
    454 
    455     while (i + 1 < stateVector.size()) {
    456         AtomicString formKey = stateVector[i++];
    457         OwnPtr<SavedFormState> state = SavedFormState::deserialize(stateVector, i);
    458         if (!state) {
    459             i = 0;
    460             break;
    461         }
    462         map.add(formKey.impl(), state.release());
    463     }
    464     if (i != stateVector.size())
    465         map.clear();
    466 }
    467 
    468 void FormController::willDeleteForm(HTMLFormElement* form)
    469 {
    470     if (m_formKeyGenerator)
    471         m_formKeyGenerator->willDeleteForm(form);
    472 }
    473 
    474 void FormController::restoreControlStateFor(HTMLFormControlElementWithState& control)
    475 {
    476     // We don't save state of a control with shouldSaveAndRestoreFormControlState()
    477     // == false. But we need to skip restoring process too because a control in
    478     // another form might have the same pair of name and type and saved its state.
    479     if (!control.shouldSaveAndRestoreFormControlState())
    480         return;
    481     if (ownerFormForState(control))
    482         return;
    483     FormControlState state = takeStateForFormElement(control);
    484     if (state.valueSize() > 0)
    485         control.restoreFormControlState(state);
    486 }
    487 
    488 void FormController::restoreControlStateIn(HTMLFormElement& form)
    489 {
    490     const Vector<FormAssociatedElement*>& elements = form.associatedElements();
    491     for (size_t i = 0; i < elements.size(); ++i) {
    492         if (!elements[i]->isFormControlElementWithState())
    493             continue;
    494         HTMLFormControlElementWithState* control = static_cast<HTMLFormControlElementWithState*>(elements[i]);
    495         if (!control->shouldSaveAndRestoreFormControlState())
    496             continue;
    497         if (ownerFormForState(*control) != &form)
    498             continue;
    499         FormControlState state = takeStateForFormElement(*control);
    500         if (state.valueSize() > 0)
    501             control->restoreFormControlState(state);
    502     }
    503 }
    504 
    505 Vector<String> FormController::getReferencedFilePaths(const Vector<String>& stateVector)
    506 {
    507     Vector<String> toReturn;
    508     SavedFormStateMap map;
    509     formStatesFromStateVector(stateVector, map);
    510     for (SavedFormStateMap::const_iterator it = map.begin(); it != map.end(); ++it)
    511         toReturn.append(it->value->getReferencedFilePaths());
    512     return toReturn;
    513 }
    514 
    515 void FormController::registerFormElementWithState(HTMLFormControlElementWithState* control)
    516 {
    517     ASSERT(!m_formElementsWithState.contains(control));
    518     m_formElementsWithState.add(control);
    519 }
    520 
    521 void FormController::unregisterFormElementWithState(HTMLFormControlElementWithState* control)
    522 {
    523     RELEASE_ASSERT(m_formElementsWithState.contains(control));
    524     m_formElementsWithState.remove(control);
    525 }
    526 
    527 } // namespace WebCore
    528