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