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