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