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 32 namespace blink { 33 34 using namespace HTMLNames; 35 36 static 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 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(hashTableDeletedValue()) { } 96 bool isHashTableDeletedValue() const { return m_name == hashTableDeletedValue(); } 97 98 private: 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 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, bool) { new (NotNull, &slot) FormElementKey(WTF::HashTableDeletedValue); } 170 static bool isDeletedValue(const FormElementKey& value) { return value.isHashTableDeletedValue(); } 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 AtomicString& 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>& 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 229 void 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 243 void 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 257 FormControlState 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 272 Vector<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 291 class FormKeyGenerator FINAL : public NoBaseWillBeGarbageCollectedFinalized<FormKeyGenerator> { 292 WTF_MAKE_NONCOPYABLE(FormKeyGenerator); 293 WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED; 294 295 public: 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 306 private: 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 315 static 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 337 static 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 353 const 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 377 void FormKeyGenerator::willDeleteForm(HTMLFormElement* form) 378 { 379 ASSERT(form); 380 m_formToKeyMap.remove(form); 381 } 382 383 // ---------------------------------------------------------------------------- 384 385 PassRefPtrWillBeRawPtr<DocumentState> DocumentState::create() 386 { 387 return adoptRefWillBeNoop(new DocumentState); 388 } 389 390 DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(DocumentState) 391 392 void DocumentState::trace(Visitor* visitor) 393 { 394 #if ENABLE(OILPAN) 395 visitor->trace(m_formControls); 396 #endif 397 } 398 399 void DocumentState::addControl(HTMLFormControlElementWithState* control) 400 { 401 ASSERT(!m_formControls.contains(control)); 402 m_formControls.add(control); 403 } 404 405 void DocumentState::removeControl(HTMLFormControlElementWithState* control) 406 { 407 RELEASE_ASSERT(m_formControls.contains(control)); 408 m_formControls.remove(control); 409 } 410 411 static 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 420 Vector<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 450 FormController::FormController() 451 : m_documentState(DocumentState::create()) 452 { 453 } 454 455 FormController::~FormController() 456 { 457 } 458 459 void FormController::trace(Visitor* visitor) 460 { 461 visitor->trace(m_radioButtonGroupScope); 462 visitor->trace(m_documentState); 463 visitor->trace(m_formKeyGenerator); 464 } 465 466 DocumentState* FormController::formElementsState() const 467 { 468 return m_documentState.get(); 469 } 470 471 void FormController::setStateForNewFormElements(const Vector<String>& stateVector) 472 { 473 formStatesFromStateVector(stateVector, m_savedFormStateMap); 474 } 475 476 FormControlState 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 491 void 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 512 void FormController::willDeleteForm(HTMLFormElement* form) 513 { 514 if (m_formKeyGenerator) 515 m_formKeyGenerator->willDeleteForm(form); 516 } 517 518 void 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 532 void 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 549 Vector<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 559 void FormController::registerStatefulFormControl(HTMLFormControlElementWithState& control) 560 { 561 m_documentState->addControl(&control); 562 } 563 564 void FormController::unregisterStatefulFormControl(HTMLFormControlElementWithState& control) 565 { 566 m_documentState->removeControl(&control); 567 } 568 569 } // namespace blink 570