OLD | NEW |
| (Empty) |
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/Deque.h" | |
29 #include "wtf/HashTableDeletedValueType.h" | |
30 #include "wtf/text/StringBuilder.h" | |
31 | |
32 namespace WebCore { | |
33 | |
34 using namespace HTMLNames; | |
35 | |
36 static inline HTMLFormElement* ownerFormForState(const HTMLFormControlElementWit
hState& 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 | |
58 void 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 | |
66 FormControlState 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 | |
84 class FormElementKey { | |
85 public: | |
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(hashTableDeletedValu
e()) { } | |
96 bool isHashTableDeletedValue() const { return m_name == hashTableDeletedValu
e(); } | |
97 | |
98 private: | |
99 void ref() const; | |
100 void deref() const; | |
101 | |
102 static StringImpl* hashTableDeletedValue() { return reinterpret_cast<StringI
mpl*>(-1); } | |
103 | |
104 StringImpl* m_name; | |
105 StringImpl* m_type; | |
106 }; | |
107 | |
108 FormElementKey::FormElementKey(StringImpl* name, StringImpl* type) | |
109 : m_name(name) | |
110 , m_type(type) | |
111 { | |
112 ref(); | |
113 } | |
114 | |
115 FormElementKey::~FormElementKey() | |
116 { | |
117 deref(); | |
118 } | |
119 | |
120 FormElementKey::FormElementKey(const FormElementKey& other) | |
121 : m_name(other.name()) | |
122 , m_type(other.type()) | |
123 { | |
124 ref(); | |
125 } | |
126 | |
127 FormElementKey& 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 | |
136 void FormElementKey::ref() const | |
137 { | |
138 if (name()) | |
139 name()->ref(); | |
140 if (type()) | |
141 type()->ref(); | |
142 } | |
143 | |
144 void FormElementKey::deref() const | |
145 { | |
146 if (name()) | |
147 name()->deref(); | |
148 if (type()) | |
149 type()->deref(); | |
150 } | |
151 | |
152 inline bool operator==(const FormElementKey& a, const FormElementKey& b) | |
153 { | |
154 return a.name() == b.name() && a.type() == b.type(); | |
155 } | |
156 | |
157 struct 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 | |
163 unsigned FormElementKeyHash::hash(const FormElementKey& key) | |
164 { | |
165 return StringHasher::hashMemory<sizeof(FormElementKey)>(&key); | |
166 } | |
167 | |
168 struct FormElementKeyHashTraits : WTF::GenericHashTraits<FormElementKey> { | |
169 static void constructDeletedValue(FormElementKey& slot) { new (NotNull, &slo
t) FormElementKey(WTF::HashTableDeletedValue); } | |
170 static bool isDeletedValue(const FormElementKey& value) { return value.isHas
hTableDeletedValue(); } | |
171 }; | |
172 | |
173 // ---------------------------------------------------------------------------- | |
174 | |
175 class SavedFormState { | |
176 WTF_MAKE_NONCOPYABLE(SavedFormState); | |
177 WTF_MAKE_FAST_ALLOCATED; | |
178 | |
179 public: | |
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 AtomicStri
ng& type); | |
186 | |
187 Vector<String> getReferencedFilePaths() const; | |
188 | |
189 private: | |
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 | |
197 PassOwnPtr<SavedFormState> SavedFormState::create() | |
198 { | |
199 return adoptPtr(new SavedFormState); | |
200 } | |
201 | |
202 static bool isNotFormControlTypeCharacter(UChar ch) | |
203 { | |
204 return ch != '-' && (ch > 'z' || ch < 'a'); | |
205 } | |
206 | |
207 PassOwnPtr<SavedFormState> SavedFormState::deserialize(const Vector<String>& sta
teVector, 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, inde
x); | |
222 if (type.isEmpty() || type.find(isNotFormControlTypeCharacter) != kNotFo
und || state.isFailure()) | |
223 return nullptr; | |
224 savedFormState->appendControlState(name, type, state); | |
225 } | |
226 return savedFormState.release(); | |
227 } | |
228 | |
229 void SavedFormState::serializeTo(Vector<String>& stateVector) const | |
230 { | |
231 stateVector.append(String::number(m_controlStateCount)); | |
232 for (FormElementStateMap::const_iterator it = m_stateForNewFormElements.begi
n(); 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 | |
243 void SavedFormState::appendControlState(const AtomicString& name, const AtomicSt
ring& 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 | |
257 FormControlState SavedFormState::takeControlState(const AtomicString& name, cons
t AtomicString& type) | |
258 { | |
259 if (m_stateForNewFormElements.isEmpty()) | |
260 return FormControlState(); | |
261 FormElementStateMap::iterator it = m_stateForNewFormElements.find(FormElemen
tKey(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 | |
272 Vector<String> SavedFormState::getReferencedFilePaths() const | |
273 { | |
274 Vector<String> toReturn; | |
275 for (FormElementStateMap::const_iterator it = m_stateForNewFormElements.begi
n(); 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 | |
291 class FormKeyGenerator { | |
292 WTF_MAKE_NONCOPYABLE(FormKeyGenerator); | |
293 WTF_MAKE_FAST_ALLOCATED; | |
294 | |
295 public: | |
296 static PassOwnPtr<FormKeyGenerator> create() { return adoptPtr(new FormKeyGe
nerator); } | |
297 AtomicString formKey(const HTMLFormControlElementWithState&); | |
298 void willDeleteForm(HTMLFormElement*); | |
299 | |
300 private: | |
301 FormKeyGenerator() { } | |
302 | |
303 typedef HashMap<HTMLFormElement*, AtomicString> FormToKeyMap; | |
304 typedef HashMap<String, unsigned> FormSignatureToNextIndexMap; | |
305 FormToKeyMap m_formToKeyMap; | |
306 FormSignatureToNextIndexMap m_formSignatureToNextIndexMap; | |
307 }; | |
308 | |
309 static inline void recordFormStructure(const HTMLFormElement& form, StringBuilde
r& builder) | |
310 { | |
311 // 2 is enough to distinguish forms in webkit.org/b/91209#c0 | |
312 const size_t namedControlsToBeRecorded = 2; | |
313 const Vector<FormAssociatedElement*>& controls = form.associatedElements(); | |
314 builder.append(" ["); | |
315 for (size_t i = 0, namedControls = 0; i < controls.size() && namedControls <
namedControlsToBeRecorded; ++i) { | |
316 if (!controls[i]->isFormControlElementWithState()) | |
317 continue; | |
318 HTMLFormControlElementWithState* control = toHTMLFormControlElementWithS
tate(controls[i]); | |
319 if (!ownerFormForState(*control)) | |
320 continue; | |
321 AtomicString name = control->name(); | |
322 if (name.isEmpty()) | |
323 continue; | |
324 namedControls++; | |
325 builder.append(name); | |
326 builder.append(" "); | |
327 } | |
328 builder.append("]"); | |
329 } | |
330 | |
331 static inline String formSignature(const HTMLFormElement& form) | |
332 { | |
333 KURL actionURL = form.getURLAttribute(actionAttr); | |
334 // Remove the query part because it might contain volatile parameters such | |
335 // as a session key. | |
336 actionURL.setQuery(String()); | |
337 StringBuilder builder; | |
338 if (!actionURL.isEmpty()) | |
339 builder.append(actionURL.string()); | |
340 | |
341 recordFormStructure(form, builder); | |
342 return builder.toString(); | |
343 } | |
344 | |
345 AtomicString FormKeyGenerator::formKey(const HTMLFormControlElementWithState& co
ntrol) | |
346 { | |
347 HTMLFormElement* form = ownerFormForState(control); | |
348 if (!form) { | |
349 DEFINE_STATIC_LOCAL(AtomicString, formKeyForNoOwner, ("No owner", Atomic
String::ConstructFromLiteral)); | |
350 return formKeyForNoOwner; | |
351 } | |
352 FormToKeyMap::const_iterator it = m_formToKeyMap.find(form); | |
353 if (it != m_formToKeyMap.end()) | |
354 return it->value; | |
355 | |
356 String signature = formSignature(*form); | |
357 ASSERT(!signature.isNull()); | |
358 FormSignatureToNextIndexMap::AddResult result = m_formSignatureToNextIndexMa
p.add(signature, 0); | |
359 unsigned nextIndex = result.iterator->value++; | |
360 | |
361 StringBuilder builder; | |
362 builder.append(signature); | |
363 builder.appendLiteral(" #"); | |
364 builder.appendNumber(nextIndex); | |
365 AtomicString formKey = builder.toAtomicString(); | |
366 m_formToKeyMap.add(form, formKey); | |
367 return formKey; | |
368 } | |
369 | |
370 void FormKeyGenerator::willDeleteForm(HTMLFormElement* form) | |
371 { | |
372 ASSERT(form); | |
373 m_formToKeyMap.remove(form); | |
374 } | |
375 | |
376 // ---------------------------------------------------------------------------- | |
377 | |
378 FormController::FormController() | |
379 { | |
380 } | |
381 | |
382 FormController::~FormController() | |
383 { | |
384 } | |
385 | |
386 static String formStateSignature() | |
387 { | |
388 // In the legacy version of serialized state, the first item was a name | |
389 // attribute value of a form control. The following string literal should | |
390 // contain some characters which are rarely used for name attribute values. | |
391 DEFINE_STATIC_LOCAL(String, signature, ("\n\r?% WebKit serialized form state
version 8 \n\r=&")); | |
392 return signature; | |
393 } | |
394 | |
395 PassOwnPtr<FormController::SavedFormStateMap> FormController::createSavedFormSta
teMap(const FormElementListHashSet& controlList) | |
396 { | |
397 OwnPtr<FormKeyGenerator> keyGenerator = FormKeyGenerator::create(); | |
398 OwnPtr<SavedFormStateMap> stateMap = adoptPtr(new SavedFormStateMap); | |
399 for (FormElementListHashSet::const_iterator it = controlList.begin(); it !=
controlList.end(); ++it) { | |
400 HTMLFormControlElementWithState* control = (*it).get(); | |
401 ASSERT(control->inDocument()); | |
402 if (!control->shouldSaveAndRestoreFormControlState()) | |
403 continue; | |
404 SavedFormStateMap::AddResult result = stateMap->add(keyGenerator->formKe
y(*control).impl(), nullptr); | |
405 if (result.isNewEntry) | |
406 result.iterator->value = SavedFormState::create(); | |
407 result.iterator->value->appendControlState(control->name(), control->typ
e(), control->saveFormControlState()); | |
408 } | |
409 return stateMap.release(); | |
410 } | |
411 | |
412 Vector<String> FormController::formElementsState() const | |
413 { | |
414 OwnPtr<SavedFormStateMap> stateMap = createSavedFormStateMap(m_formElementsW
ithState); | |
415 Vector<String> stateVector; | |
416 stateVector.reserveInitialCapacity(m_formElementsWithState.size() * 4); | |
417 stateVector.append(formStateSignature()); | |
418 for (SavedFormStateMap::const_iterator it = stateMap->begin(); it != stateMa
p->end(); ++it) { | |
419 stateVector.append(it->key); | |
420 it->value->serializeTo(stateVector); | |
421 } | |
422 bool hasOnlySignature = stateVector.size() == 1; | |
423 if (hasOnlySignature) | |
424 stateVector.clear(); | |
425 return stateVector; | |
426 } | |
427 | |
428 void FormController::setStateForNewFormElements(const Vector<String>& stateVecto
r) | |
429 { | |
430 formStatesFromStateVector(stateVector, m_savedFormStateMap); | |
431 } | |
432 | |
433 FormControlState FormController::takeStateForFormElement(const HTMLFormControlEl
ementWithState& control) | |
434 { | |
435 if (m_savedFormStateMap.isEmpty()) | |
436 return FormControlState(); | |
437 if (!m_formKeyGenerator) | |
438 m_formKeyGenerator = FormKeyGenerator::create(); | |
439 SavedFormStateMap::iterator it = m_savedFormStateMap.find(m_formKeyGenerator
->formKey(control).impl()); | |
440 if (it == m_savedFormStateMap.end()) | |
441 return FormControlState(); | |
442 FormControlState state = it->value->takeControlState(control.name(), control
.type()); | |
443 if (it->value->isEmpty()) | |
444 m_savedFormStateMap.remove(it); | |
445 return state; | |
446 } | |
447 | |
448 void FormController::formStatesFromStateVector(const Vector<String>& stateVector
, SavedFormStateMap& map) | |
449 { | |
450 map.clear(); | |
451 | |
452 size_t i = 0; | |
453 if (stateVector.size() < 1 || stateVector[i++] != formStateSignature()) | |
454 return; | |
455 | |
456 while (i + 1 < stateVector.size()) { | |
457 AtomicString formKey = stateVector[i++]; | |
458 OwnPtr<SavedFormState> state = SavedFormState::deserialize(stateVector,
i); | |
459 if (!state) { | |
460 i = 0; | |
461 break; | |
462 } | |
463 map.add(formKey.impl(), state.release()); | |
464 } | |
465 if (i != stateVector.size()) | |
466 map.clear(); | |
467 } | |
468 | |
469 void FormController::willDeleteForm(HTMLFormElement* form) | |
470 { | |
471 if (m_formKeyGenerator) | |
472 m_formKeyGenerator->willDeleteForm(form); | |
473 } | |
474 | |
475 void FormController::restoreControlStateFor(HTMLFormControlElementWithState& con
trol) | |
476 { | |
477 // We don't save state of a control with shouldSaveAndRestoreFormControlStat
e() | |
478 // == false. But we need to skip restoring process too because a control in | |
479 // another form might have the same pair of name and type and saved its stat
e. | |
480 if (!control.shouldSaveAndRestoreFormControlState()) | |
481 return; | |
482 if (ownerFormForState(control)) | |
483 return; | |
484 FormControlState state = takeStateForFormElement(control); | |
485 if (state.valueSize() > 0) | |
486 control.restoreFormControlState(state); | |
487 } | |
488 | |
489 void FormController::restoreControlStateIn(HTMLFormElement& form) | |
490 { | |
491 const Vector<FormAssociatedElement*>& elements = form.associatedElements(); | |
492 for (size_t i = 0; i < elements.size(); ++i) { | |
493 if (!elements[i]->isFormControlElementWithState()) | |
494 continue; | |
495 HTMLFormControlElementWithState* control = toHTMLFormControlElementWithS
tate(elements[i]); | |
496 if (!control->shouldSaveAndRestoreFormControlState()) | |
497 continue; | |
498 if (ownerFormForState(*control) != &form) | |
499 continue; | |
500 FormControlState state = takeStateForFormElement(*control); | |
501 if (state.valueSize() > 0) | |
502 control->restoreFormControlState(state); | |
503 } | |
504 } | |
505 | |
506 Vector<String> FormController::getReferencedFilePaths(const Vector<String>& stat
eVector) | |
507 { | |
508 Vector<String> toReturn; | |
509 SavedFormStateMap map; | |
510 formStatesFromStateVector(stateVector, map); | |
511 for (SavedFormStateMap::const_iterator it = map.begin(); it != map.end(); ++
it) | |
512 toReturn.append(it->value->getReferencedFilePaths()); | |
513 return toReturn; | |
514 } | |
515 | |
516 void FormController::registerFormElementWithState(HTMLFormControlElementWithStat
e* control) | |
517 { | |
518 ASSERT(!m_formElementsWithState.contains(control)); | |
519 m_formElementsWithState.add(control); | |
520 } | |
521 | |
522 void FormController::unregisterFormElementWithState(HTMLFormControlElementWithSt
ate* control) | |
523 { | |
524 RELEASE_ASSERT(m_formElementsWithState.contains(control)); | |
525 m_formElementsWithState.remove(control); | |
526 } | |
527 | |
528 } // namespace WebCore | |
OLD | NEW |