1/* 2 * Copyright (C) 2014 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "LegacySessionStateCoding.h" 28 29#include "APIData.h" 30#include "SessionState.h" 31#include <mutex> 32#include <wtf/MallocPtr.h> 33#include <wtf/cf/TypeCasts.h> 34#include <wtf/text/StringView.h> 35 36namespace WebKit { 37 38// Session state keys. 39static const uint32_t sessionStateDataVersion = 2; 40 41static const CFStringRef sessionHistoryKey = CFSTR("SessionHistory"); 42static const CFStringRef provisionalURLKey = CFSTR("ProvisionalURL"); 43 44// Session history keys. 45static const uint32_t sessionHistoryVersion = 1; 46 47static const CFStringRef sessionHistoryVersionKey = CFSTR("SessionHistoryVersion"); 48static const CFStringRef sessionHistoryCurrentIndexKey = CFSTR("SessionHistoryCurrentIndex"); 49static const CFStringRef sessionHistoryEntriesKey = CFSTR("SessionHistoryEntries"); 50 51// Session history entry keys. 52static const CFStringRef sessionHistoryEntryURLKey = CFSTR("SessionHistoryEntryURL"); 53static CFStringRef sessionHistoryEntryTitleKey = CFSTR("SessionHistoryEntryTitle"); 54static CFStringRef sessionHistoryEntryOriginalURLKey = CFSTR("SessionHistoryEntryOriginalURL"); 55static CFStringRef sessionHistoryEntryDataKey = CFSTR("SessionHistoryEntryData"); 56 57// Session history entry data. 58const uint32_t sessionHistoryEntryDataVersion = 2; 59 60template<typename T> void isValidEnum(T); 61 62class HistoryEntryDataEncoder { 63public: 64 HistoryEntryDataEncoder() 65 : m_bufferSize(0) 66 , m_bufferCapacity(512) 67 , m_buffer(MallocPtr<uint8_t>::malloc(m_bufferCapacity)) 68 , m_bufferPointer(m_buffer.get()) 69 { 70 // Keep format compatibility by encoding an unused uint64_t here. 71 *this << static_cast<uint64_t>(0); 72 } 73 74 HistoryEntryDataEncoder& operator<<(uint32_t value) 75 { 76 return encodeArithmeticType(value); 77 } 78 79 HistoryEntryDataEncoder& operator<<(int32_t value) 80 { 81 return encodeArithmeticType(value); 82 } 83 84 HistoryEntryDataEncoder& operator<<(uint64_t value) 85 { 86 return encodeArithmeticType(value); 87 } 88 89 HistoryEntryDataEncoder& operator<<(int64_t value) 90 { 91 return encodeArithmeticType(value); 92 } 93 94 HistoryEntryDataEncoder& operator<<(float value) 95 { 96 return encodeArithmeticType(value); 97 } 98 99 HistoryEntryDataEncoder& operator<<(double value) 100 { 101 return encodeArithmeticType(value); 102 } 103 104 HistoryEntryDataEncoder& operator<<(bool value) 105 { 106 return encodeArithmeticType(value); 107 } 108 109 HistoryEntryDataEncoder& operator<<(const String& value) 110 { 111 // Special case the null string. 112 if (value.isNull()) 113 return *this << std::numeric_limits<uint32_t>::max(); 114 115 uint32_t length = value.length(); 116 *this << length; 117 118 *this << static_cast<uint64_t>(length * sizeof(UChar)); 119 encodeFixedLengthData(reinterpret_cast<const uint8_t*>(StringView(value).upconvertedCharacters().get()), length * sizeof(UChar), alignof(UChar)); 120 121 return *this; 122 } 123 124 HistoryEntryDataEncoder& operator<<(const Vector<uint8_t>& value) 125 { 126 *this << static_cast<uint64_t>(value.size()); 127 encodeFixedLengthData(value.data(), value.size(), 1); 128 129 return *this; 130 } 131 132 HistoryEntryDataEncoder& operator<<(const Vector<char>& value) 133 { 134 *this << static_cast<uint64_t>(value.size()); 135 encodeFixedLengthData(reinterpret_cast<const uint8_t*>(value.data()), value.size(), 1); 136 137 return *this; 138 } 139 140#if PLATFORM(IOS) 141 HistoryEntryDataEncoder& operator<<(WebCore::FloatRect value) 142 { 143 *this << value.x(); 144 *this << value.y(); 145 *this << value.width(); 146 *this << value.height(); 147 148 return *this; 149 } 150 151 HistoryEntryDataEncoder& operator<<(WebCore::IntRect value) 152 { 153 *this << value.x(); 154 *this << value.y(); 155 *this << value.width(); 156 *this << value.height(); 157 158 return *this; 159 } 160 161 HistoryEntryDataEncoder& operator<<(WebCore::FloatSize value) 162 { 163 *this << value.width(); 164 *this << value.height(); 165 166 return *this; 167 } 168 169 HistoryEntryDataEncoder& operator<<(WebCore::IntSize value) 170 { 171 *this << value.width(); 172 *this << value.height(); 173 174 return *this; 175 } 176#endif 177 178 template<typename T> 179 auto operator<<(T value) -> typename std::enable_if<std::is_enum<T>::value, HistoryEntryDataEncoder&>::type 180 { 181 return *this << static_cast<uint32_t>(value); 182 } 183 184 MallocPtr<uint8_t> finishEncoding(size_t& size) 185 { 186 size = m_bufferSize; 187 return WTF::move(m_buffer); 188 } 189 190private: 191 template<typename Type> 192 HistoryEntryDataEncoder& encodeArithmeticType(Type value) 193 { 194 static_assert(std::is_arithmetic<Type>::value, ""); 195 196 encodeFixedLengthData(reinterpret_cast<uint8_t*>(&value), sizeof(value), sizeof(value)); 197 return *this; 198 } 199 200 void encodeFixedLengthData(const uint8_t* data, size_t size, unsigned alignment) 201 { 202 ASSERT(!(reinterpret_cast<uintptr_t>(data) % alignment)); 203 204 uint8_t* buffer = grow(alignment, size); 205 memcpy(buffer, data, size); 206 } 207 208 uint8_t* grow(unsigned alignment, size_t size) 209 { 210 size_t alignedSize = ((m_bufferSize + alignment - 1) / alignment) * alignment; 211 212 growCapacity(alignedSize + size); 213 214 m_bufferSize = alignedSize + size; 215 m_bufferPointer = m_buffer.get() + m_bufferSize; 216 217 return m_buffer.get() + alignedSize; 218 } 219 220 void growCapacity(size_t newSize) 221 { 222 if (newSize <= m_bufferCapacity) 223 return; 224 225 size_t newCapacity = m_bufferCapacity * 2; 226 while (newCapacity < newSize) 227 newCapacity *= 2; 228 229 m_buffer.realloc(newCapacity); 230 m_bufferCapacity = newCapacity; 231 } 232 233 size_t m_bufferSize; 234 size_t m_bufferCapacity; 235 MallocPtr<uint8_t> m_buffer; 236 uint8_t* m_bufferPointer; 237}; 238 239enum class FormDataElementType { 240 Data = 0, 241 EncodedFile = 1, 242 EncodedBlob = 2, 243}; 244 245static bool isValidEnum(FormDataElementType type) 246{ 247 switch (type) { 248 case FormDataElementType::Data: 249 case FormDataElementType::EncodedFile: 250 case FormDataElementType::EncodedBlob: 251 return true; 252 } 253 254 return false; 255} 256 257static void encodeFormDataElement(HistoryEntryDataEncoder& encoder, const HTTPBody::Element& element) 258{ 259 switch (element.type) { 260 case HTTPBody::Element::Type::Data: 261 encoder << FormDataElementType::Data; 262 encoder << element.data; 263 break; 264 265 case HTTPBody::Element::Type::File: 266 encoder << FormDataElementType::EncodedFile; 267 encoder << element.filePath; 268 269 // Used to be generatedFilename. 270 encoder << String(); 271 272 // Used to be shouldGenerateFile. 273 encoder << false; 274 275 encoder << element.fileStart; 276 encoder << element.fileLength.valueOr(-1); 277 encoder << element.expectedFileModificationTime.valueOr(std::numeric_limits<double>::quiet_NaN()); 278 break; 279 280 case HTTPBody::Element::Type::Blob: 281 encoder << FormDataElementType::EncodedBlob; 282 encoder << element.blobURLString; 283 break; 284 } 285} 286 287static void encodeFormData(HistoryEntryDataEncoder& encoder, const HTTPBody& formData) 288{ 289 // Used to be alwaysStream. 290 encoder << false; 291 292 // Used to be boundary. 293 encoder << Vector<uint8_t>(); 294 295 encoder << static_cast<uint64_t>(formData.elements.size()); 296 for (const auto& element : formData.elements) 297 encodeFormDataElement(encoder, element); 298 299 // Used to be hasGeneratedFiles. 300 encoder << false; 301 302 // Used to be identifier. 303 encoder << static_cast<int64_t>(0); 304} 305 306static void encodeFrameStateNode(HistoryEntryDataEncoder& encoder, const FrameState& frameState) 307{ 308 encoder << static_cast<uint64_t>(frameState.children.size()); 309 310 for (const auto& childFrameState : frameState.children) { 311 encoder << childFrameState.originalURLString; 312 encoder << childFrameState.urlString; 313 314 encodeFrameStateNode(encoder, childFrameState); 315 } 316 317 encoder << frameState.documentSequenceNumber; 318 319 encoder << static_cast<uint64_t>(frameState.documentState.size()); 320 for (const auto& documentState : frameState.documentState) 321 encoder << documentState; 322 323 if (frameState.httpBody) { 324 encoder << frameState.httpBody.value().contentType; 325 encoder << true; 326 327 encodeFormData(encoder, frameState.httpBody.value()); 328 } else { 329 encoder << String(); 330 encoder << false; 331 } 332 333 encoder << frameState.itemSequenceNumber; 334 335 encoder << frameState.referrer; 336 337 encoder << frameState.scrollPoint.x(); 338 encoder << frameState.scrollPoint.y(); 339 340 encoder << frameState.pageScaleFactor; 341 342 encoder << !!frameState.stateObjectData; 343 if (frameState.stateObjectData) 344 encoder << frameState.stateObjectData.value(); 345 346 encoder << frameState.target; 347 348#if PLATFORM(IOS) 349 // FIXME: iOS should not use the legacy session state encoder. 350 encoder << frameState.exposedContentRect; 351 encoder << frameState.unobscuredContentRect; 352 encoder << frameState.minimumLayoutSizeInScrollViewCoordinates; 353 encoder << frameState.contentSize; 354 encoder << frameState.scaleIsInitial; 355#endif 356} 357 358static MallocPtr<uint8_t> encodeSessionHistoryEntryData(const FrameState& frameState, size_t& bufferSize) 359{ 360 HistoryEntryDataEncoder encoder; 361 362 encoder << sessionHistoryEntryDataVersion; 363 encodeFrameStateNode(encoder, frameState); 364 365 return encoder.finishEncoding(bufferSize); 366} 367 368static RetainPtr<CFDataRef> encodeSessionHistoryEntryData(const FrameState& frameState) 369{ 370 static CFAllocatorRef fastMallocDeallocator; 371 372 static std::once_flag onceFlag; 373 std::call_once(onceFlag, [] { 374 CFAllocatorContext context = { 375 0, // version 376 nullptr, // info 377 nullptr, // retain 378 nullptr, // release 379 nullptr, // copyDescription 380 nullptr, // allocate 381 nullptr, // reallocate 382 [](void *ptr, void *info) { 383 WTF::fastFree(ptr); 384 }, 385 nullptr, // preferredSize 386 }; 387 fastMallocDeallocator = CFAllocatorCreate(kCFAllocatorDefault, &context); 388 }); 389 390 size_t bufferSize; 391 auto buffer = encodeSessionHistoryEntryData(frameState, bufferSize); 392 393 return adoptCF(CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, buffer.leakPtr(), bufferSize, fastMallocDeallocator)); 394} 395 396static RetainPtr<CFDictionaryRef> createDictionary(std::initializer_list<std::pair<CFStringRef, CFTypeRef>> keyValuePairs) 397{ 398 Vector<CFTypeRef> keys; 399 Vector<CFTypeRef> values; 400 401 keys.reserveInitialCapacity(keyValuePairs.size()); 402 values.reserveInitialCapacity(keyValuePairs.size()); 403 404 for (const auto& keyValuePair : keyValuePairs) { 405 keys.uncheckedAppend(keyValuePair.first); 406 values.uncheckedAppend(keyValuePair.second); 407 } 408 409 return adoptCF(CFDictionaryCreate(kCFAllocatorDefault, keys.data(), values.data(), keyValuePairs.size(), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); 410} 411 412static RetainPtr<CFDictionaryRef> encodeSessionHistory(const BackForwardListState& backForwardListState) 413{ 414 ASSERT(!backForwardListState.currentIndex || backForwardListState.currentIndex.value() < backForwardListState.items.size()); 415 416 auto sessionHistoryVersionNumber = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &sessionHistoryVersion)); 417 418 if (!backForwardListState.currentIndex) 419 return createDictionary({ { sessionHistoryVersionKey, sessionHistoryVersionNumber.get() } }); 420 421 auto entries = adoptCF(CFArrayCreateMutable(kCFAllocatorDefault, backForwardListState.items.size(), &kCFTypeArrayCallBacks)); 422 423 for (const auto& item : backForwardListState.items) { 424 auto url = item.pageState.mainFrameState.urlString.createCFString(); 425 auto title = item.pageState.title.createCFString(); 426 auto originalURL = item.pageState.mainFrameState.originalURLString.createCFString(); 427 auto data = encodeSessionHistoryEntryData(item.pageState.mainFrameState); 428 429 auto entryDictionary = createDictionary({ { sessionHistoryEntryURLKey, url.get() }, { sessionHistoryEntryTitleKey, title.get() }, { sessionHistoryEntryOriginalURLKey, originalURL.get() }, { sessionHistoryEntryDataKey, data.get() } }); 430 431 CFArrayAppendValue(entries.get(), entryDictionary.get()); 432 } 433 434 uint32_t currentIndex = backForwardListState.currentIndex.value(); 435 auto currentIndexNumber = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, ¤tIndex)); 436 437 return createDictionary({ { sessionHistoryVersionKey, sessionHistoryVersionNumber.get() }, { sessionHistoryCurrentIndexKey, currentIndexNumber.get() }, { sessionHistoryEntriesKey, entries.get() } }); 438} 439 440RefPtr<API::Data> encodeLegacySessionState(const SessionState& sessionState) 441{ 442 auto sessionHistoryDictionary = encodeSessionHistory(sessionState.backForwardListState); 443 auto provisionalURLString = sessionState.provisionalURL.isNull() ? nullptr : sessionState.provisionalURL.string().createCFString(); 444 445 RetainPtr<CFDictionaryRef> stateDictionary; 446 if (provisionalURLString) 447 stateDictionary = createDictionary({ { sessionHistoryKey, sessionHistoryDictionary.get() }, { provisionalURLKey, provisionalURLString.get() } }); 448 else 449 stateDictionary = createDictionary({ { sessionHistoryKey, sessionHistoryDictionary.get() } }); 450 451 auto writeStream = adoptCF(CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault, nullptr)); 452 if (!writeStream) 453 return nullptr; 454 455 if (!CFWriteStreamOpen(writeStream.get())) 456 return nullptr; 457 458 if (!CFPropertyListWrite(stateDictionary.get(), writeStream.get(), kCFPropertyListBinaryFormat_v1_0, 0, nullptr)) 459 return nullptr; 460 461 auto data = adoptCF(static_cast<CFDataRef>(CFWriteStreamCopyProperty(writeStream.get(), kCFStreamPropertyDataWritten))); 462 463 CFIndex length = CFDataGetLength(data.get()); 464 465 size_t bufferSize = length + sizeof(uint32_t); 466 auto buffer = MallocPtr<uint8_t>::malloc(bufferSize); 467 468 // Put the session state version number at the start of the buffer 469 buffer.get()[0] = (sessionStateDataVersion & 0xff000000) >> 24; 470 buffer.get()[1] = (sessionStateDataVersion & 0x00ff0000) >> 16; 471 buffer.get()[2] = (sessionStateDataVersion & 0x0000ff00) >> 8; 472 buffer.get()[3] = (sessionStateDataVersion & 0x000000ff); 473 474 // Copy in the actual session state data 475 CFDataGetBytes(data.get(), CFRangeMake(0, length), buffer.get() + sizeof(uint32_t)); 476 477 return API::Data::createWithoutCopying(buffer.leakPtr(), bufferSize, [] (unsigned char* buffer, const void* context) { 478 fastFree(buffer); 479 }, nullptr); 480} 481 482class HistoryEntryDataDecoder { 483public: 484 HistoryEntryDataDecoder(const uint8_t* buffer, size_t bufferSize) 485 : m_buffer(buffer) 486 , m_bufferEnd(buffer + bufferSize) 487 { 488 // Keep format compatibility by decoding an unused uint64_t here. 489 uint64_t value; 490 *this >> value; 491 } 492 493 HistoryEntryDataDecoder& operator>>(bool& value) 494 { 495 return decodeArithmeticType(value); 496 } 497 498 HistoryEntryDataDecoder& operator>>(uint32_t& value) 499 { 500 return decodeArithmeticType(value); 501 } 502 503 HistoryEntryDataDecoder& operator>>(int32_t& value) 504 { 505 return *this >> reinterpret_cast<uint32_t&>(value); 506 } 507 508 HistoryEntryDataDecoder& operator>>(uint64_t& value) 509 { 510 return decodeArithmeticType(value); 511 } 512 513 HistoryEntryDataDecoder& operator>>(int64_t& value) 514 { 515 return *this >> reinterpret_cast<uint64_t&>(value); 516 } 517 518 HistoryEntryDataDecoder& operator>>(float& value) 519 { 520 return decodeArithmeticType(value); 521 } 522 523 HistoryEntryDataDecoder& operator>>(double& value) 524 { 525 return decodeArithmeticType(value); 526 } 527 528 HistoryEntryDataDecoder& operator>>(String& value) 529 { 530 value = String(); 531 532 uint32_t length; 533 *this >> length; 534 535 if (length == std::numeric_limits<uint32_t>::max()) { 536 // This is the null string. 537 value = String(); 538 return *this; 539 } 540 541 uint64_t lengthInBytes; 542 *this >> lengthInBytes; 543 544 if (lengthInBytes % sizeof(UChar) || lengthInBytes / sizeof(UChar) != length) { 545 markInvalid(); 546 return *this; 547 } 548 549 if (!bufferIsLargeEnoughToContain<UChar>(length)) { 550 markInvalid(); 551 return *this; 552 } 553 554 UChar* buffer; 555 auto string = String::createUninitialized(length, buffer); 556 decodeFixedLengthData(reinterpret_cast<uint8_t*>(buffer), length * sizeof(UChar), alignof(UChar)); 557 558 value = string; 559 return *this; 560 } 561 562 HistoryEntryDataDecoder& operator>>(Vector<uint8_t>& value) 563 { 564 value = { }; 565 566 uint64_t size; 567 *this >> size; 568 569 if (!alignBufferPosition(1, size)) 570 return *this; 571 572 const uint8_t* data = m_buffer; 573 m_buffer += size; 574 575 value.append(data, size); 576 return *this; 577 } 578 579 HistoryEntryDataDecoder& operator>>(Vector<char>& value) 580 { 581 value = { }; 582 583 uint64_t size; 584 *this >> size; 585 586 if (!alignBufferPosition(1, size)) 587 return *this; 588 589 const uint8_t* data = m_buffer; 590 m_buffer += size; 591 592 value.append(data, size); 593 return *this; 594 } 595 596#if PLATFORM(IOS) 597 HistoryEntryDataDecoder& operator>>(WebCore::FloatRect& value) 598 { 599 value = WebCore::FloatRect(); 600 601 float x; 602 *this >> x; 603 604 float y; 605 *this >> y; 606 607 float width; 608 *this >> width; 609 610 float height; 611 *this >> height; 612 613 value = WebCore::FloatRect(x, y, width, height); 614 return *this; 615 } 616 617 HistoryEntryDataDecoder& operator>>(WebCore::IntRect& value) 618 { 619 value = WebCore::IntRect(); 620 621 int32_t x; 622 *this >> x; 623 624 int32_t y; 625 *this >> y; 626 627 int32_t width; 628 *this >> width; 629 630 int32_t height; 631 *this >> height; 632 633 value = WebCore::IntRect(x, y, width, height); 634 return *this; 635 } 636 637 HistoryEntryDataDecoder& operator>>(WebCore::FloatSize& value) 638 { 639 value = WebCore::FloatSize(); 640 641 float width; 642 *this >> width; 643 644 float height; 645 *this >> height; 646 647 value = WebCore::FloatSize(width, height); 648 return *this; 649 } 650 651 HistoryEntryDataDecoder& operator>>(WebCore::IntSize& value) 652 { 653 value = WebCore::IntSize(); 654 655 int32_t width; 656 *this >> width; 657 658 int32_t height; 659 *this >> height; 660 661 value = WebCore::IntSize(width, height); 662 return *this; 663 } 664#endif 665 666 template<typename T> 667 auto operator>>(Optional<T>& value) -> typename std::enable_if<std::is_enum<T>::value, HistoryEntryDataDecoder&>::type 668 { 669 uint32_t underlyingEnumValue; 670 *this >> underlyingEnumValue; 671 672 if (!isValid() || !isValidEnum(static_cast<T>(underlyingEnumValue))) 673 value = Nullopt; 674 else 675 value = static_cast<T>(underlyingEnumValue); 676 677 return *this; 678 } 679 680 bool isValid() const { return m_buffer <= m_bufferEnd; } 681 void markInvalid() { m_buffer = m_bufferEnd + 1; } 682 683 bool finishDecoding() { return m_buffer == m_bufferEnd; } 684 685private: 686 template<typename Type> 687 HistoryEntryDataDecoder& decodeArithmeticType(Type& value) 688 { 689 static_assert(std::is_arithmetic<Type>::value, ""); 690 value = Type(); 691 692 decodeFixedLengthData(reinterpret_cast<uint8_t*>(&value), sizeof(value), sizeof(value)); 693 return *this; 694 } 695 696 void decodeFixedLengthData(uint8_t* data, size_t size, unsigned alignment) 697 { 698 if (!alignBufferPosition(alignment, size)) 699 return; 700 701 memcpy(data, m_buffer, size); 702 m_buffer += size; 703 } 704 705 bool alignBufferPosition(unsigned alignment, size_t size) 706 { 707 const uint8_t* alignedPosition = alignedBuffer(alignment); 708 if (!alignedBufferIsLargeEnoughToContain(alignedPosition, size)) { 709 // We've walked off the end of this buffer. 710 markInvalid(); 711 return false; 712 } 713 714 m_buffer = alignedPosition; 715 return true; 716 } 717 718 const uint8_t* alignedBuffer(unsigned alignment) const 719 { 720 ASSERT(alignment && !(alignment & (alignment - 1))); 721 722 uintptr_t alignmentMask = alignment - 1; 723 return reinterpret_cast<uint8_t*>((reinterpret_cast<uintptr_t>(m_buffer) + alignmentMask) & ~alignmentMask); 724 } 725 726 template<typename T> 727 bool bufferIsLargeEnoughToContain(size_t numElements) const 728 { 729 static_assert(std::is_arithmetic<T>::value, "Type T must have a fixed, known encoded size!"); 730 731 if (numElements > std::numeric_limits<size_t>::max() / sizeof(T)) 732 return false; 733 734 return bufferIsLargeEnoughToContain(alignof(T), numElements * sizeof(T)); 735 } 736 737 bool bufferIsLargeEnoughToContain(unsigned alignment, size_t size) const 738 { 739 return alignedBufferIsLargeEnoughToContain(alignedBuffer(alignment), size); 740 } 741 742 inline bool alignedBufferIsLargeEnoughToContain(const uint8_t* alignedPosition, size_t size) const 743 { 744 return m_bufferEnd >= alignedPosition && static_cast<size_t>(m_bufferEnd - alignedPosition) >= size; 745 } 746 747 const uint8_t* m_buffer; 748 const uint8_t* m_bufferEnd; 749}; 750 751static void decodeFormDataElement(HistoryEntryDataDecoder& decoder, HTTPBody::Element& formDataElement) 752{ 753 Optional<FormDataElementType> elementType; 754 decoder >> elementType; 755 if (!elementType) 756 return; 757 758 switch (elementType.value()) { 759 case FormDataElementType::Data: 760 formDataElement.type = HTTPBody::Element::Type::Data; 761 decoder >> formDataElement.data; 762 break; 763 764 case FormDataElementType::EncodedFile: { 765 decoder >> formDataElement.filePath; 766 767 String generatedFilename; 768 decoder >> generatedFilename; 769 770 bool shouldGenerateFile; 771 decoder >> shouldGenerateFile; 772 773 decoder >> formDataElement.fileStart; 774 if (formDataElement.fileStart < 0) { 775 decoder.markInvalid(); 776 return; 777 } 778 779 int64_t fileLength; 780 decoder >> fileLength; 781 if (fileLength != -1) { 782 if (fileLength < formDataElement.fileStart) 783 return; 784 785 formDataElement.fileLength = fileLength; 786 } 787 788 789 double expectedFileModificationTime; 790 decoder >> expectedFileModificationTime; 791 if (expectedFileModificationTime != std::numeric_limits<double>::quiet_NaN()) 792 formDataElement.expectedFileModificationTime = expectedFileModificationTime; 793 794 break; 795 } 796 797 case FormDataElementType::EncodedBlob: 798 decoder >> formDataElement.blobURLString; 799 break; 800 } 801} 802 803static void decodeFormData(HistoryEntryDataDecoder& decoder, HTTPBody& formData) 804{ 805 bool alwaysStream; 806 decoder >> alwaysStream; 807 808 Vector<uint8_t> boundary; 809 decoder >> boundary; 810 811 uint64_t formDataElementCount; 812 decoder >> formDataElementCount; 813 814 for (uint64_t i = 0; i < formDataElementCount; ++i) { 815 HTTPBody::Element formDataElement; 816 decodeFormDataElement(decoder, formDataElement); 817 818 if (!decoder.isValid()) 819 return; 820 821 formData.elements.append(WTF::move(formDataElement)); 822 } 823 824 bool hasGeneratedFiles; 825 decoder >> hasGeneratedFiles; 826 827 int64_t identifier; 828 decoder >> identifier; 829} 830 831static void decodeBackForwardTreeNode(HistoryEntryDataDecoder& decoder, FrameState& frameState) 832{ 833 uint64_t childCount; 834 decoder >> childCount; 835 836 for (uint64_t i = 0; i < childCount; ++i) { 837 FrameState childFrameState; 838 decoder >> childFrameState.originalURLString; 839 decoder >> childFrameState.urlString; 840 841 decodeBackForwardTreeNode(decoder, childFrameState); 842 843 if (!decoder.isValid()) 844 return; 845 846 frameState.children.append(WTF::move(childFrameState)); 847 } 848 849 decoder >> frameState.documentSequenceNumber; 850 851 uint64_t documentStateVectorSize; 852 decoder >> documentStateVectorSize; 853 854 for (uint64_t i = 0; i < documentStateVectorSize; ++i) { 855 String state; 856 decoder >> state; 857 858 if (!decoder.isValid()) 859 return; 860 861 frameState.documentState.append(WTF::move(state)); 862 } 863 864 String formContentType; 865 decoder >> formContentType; 866 867 bool hasFormData; 868 decoder >> hasFormData; 869 870 if (hasFormData) { 871 HTTPBody httpBody; 872 httpBody.contentType = WTF::move(formContentType); 873 874 decodeFormData(decoder, httpBody); 875 876 frameState.httpBody = WTF::move(httpBody); 877 } 878 879 decoder >> frameState.itemSequenceNumber; 880 881 decoder >> frameState.referrer; 882 883 int32_t scrollPointX; 884 decoder >> scrollPointX; 885 886 int32_t scrollPointY; 887 decoder >> scrollPointY; 888 889 frameState.scrollPoint = WebCore::IntPoint(scrollPointX, scrollPointY); 890 891 decoder >> frameState.pageScaleFactor; 892 893 bool hasStateObject; 894 decoder >> hasStateObject; 895 896 if (hasStateObject) { 897 Vector<uint8_t> stateObjectData; 898 decoder >> stateObjectData; 899 900 frameState.stateObjectData = WTF::move(stateObjectData); 901 } 902 903 decoder >> frameState.target; 904 905 // FIXME: iOS should not use the legacy session state decoder. 906#if PLATFORM(IOS) 907 decoder >> frameState.exposedContentRect; 908 decoder >> frameState.unobscuredContentRect; 909 decoder >> frameState.minimumLayoutSizeInScrollViewCoordinates; 910 decoder >> frameState.contentSize; 911 decoder >> frameState.scaleIsInitial; 912#endif 913} 914 915static bool decodeSessionHistoryEntryData(const uint8_t* buffer, size_t bufferSize, FrameState& mainFrameState) 916{ 917 HistoryEntryDataDecoder decoder { buffer, bufferSize }; 918 919 uint32_t version; 920 decoder >> version; 921 922 if (version != sessionHistoryEntryDataVersion) 923 return false; 924 925 decodeBackForwardTreeNode(decoder, mainFrameState); 926 927 return decoder.finishDecoding(); 928} 929 930static bool decodeSessionHistoryEntryData(CFDataRef historyEntryData, FrameState& mainFrameState) 931{ 932 return decodeSessionHistoryEntryData(CFDataGetBytePtr(historyEntryData), static_cast<size_t>(CFDataGetLength(historyEntryData)), mainFrameState); 933} 934 935static bool decodeSessionHistoryEntry(CFDictionaryRef entryDictionary, BackForwardListItemState& backForwardListItemState) 936{ 937 auto title = dynamic_cf_cast<CFStringRef>(CFDictionaryGetValue(entryDictionary, sessionHistoryEntryTitleKey)); 938 if (!title) 939 return false; 940 941 auto urlString = dynamic_cf_cast<CFStringRef>(CFDictionaryGetValue(entryDictionary, sessionHistoryEntryURLKey)); 942 if (!urlString) 943 return false; 944 945 auto originalURLString = dynamic_cf_cast<CFStringRef>(CFDictionaryGetValue(entryDictionary, sessionHistoryEntryOriginalURLKey)); 946 if (!originalURLString) 947 return false; 948 949 auto historyEntryData = dynamic_cf_cast<CFDataRef>(CFDictionaryGetValue(entryDictionary, sessionHistoryEntryDataKey)); 950 if (!historyEntryData) 951 return false; 952 953 if (!decodeSessionHistoryEntryData(historyEntryData, backForwardListItemState.pageState.mainFrameState)) 954 return false; 955 956 backForwardListItemState.pageState.title = title; 957 backForwardListItemState.pageState.mainFrameState.urlString = urlString; 958 backForwardListItemState.pageState.mainFrameState.originalURLString = originalURLString; 959 960 return true; 961} 962 963static bool decodeSessionHistoryEntries(CFArrayRef entriesArray, Vector<BackForwardListItemState>& entries) 964{ 965 for (CFIndex i = 0, size = CFArrayGetCount(entriesArray); i < size; ++i) { 966 auto entryDictionary = dynamic_cf_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(entriesArray, i)); 967 if (!entryDictionary) 968 return false; 969 970 BackForwardListItemState entry; 971 if (!decodeSessionHistoryEntry(entryDictionary, entry)) 972 return false; 973 974 entries.append(WTF::move(entry)); 975 } 976 977 return true; 978} 979 980static bool decodeV0SessionHistory(CFDictionaryRef sessionHistoryDictionary, BackForwardListState& backForwardListState) 981{ 982 auto currentIndexNumber = dynamic_cf_cast<CFNumberRef>(CFDictionaryGetValue(sessionHistoryDictionary, sessionHistoryCurrentIndexKey)); 983 if (!currentIndexNumber) 984 return false; 985 986 CFIndex currentIndex; 987 if (!CFNumberGetValue(currentIndexNumber, kCFNumberCFIndexType, ¤tIndex)) 988 return false; 989 990 if (currentIndex < -1) 991 return false; 992 993 auto historyEntries = dynamic_cf_cast<CFArrayRef>(CFDictionaryGetValue(sessionHistoryDictionary, sessionHistoryEntriesKey)); 994 if (!historyEntries) 995 return false; 996 997 // Version 0 session history relied on currentIndex == -1 to represent the same thing as not having a current index. 998 bool hasCurrentIndex = currentIndex != -1; 999 1000 if (!decodeSessionHistoryEntries(historyEntries, backForwardListState.items)) 1001 return false; 1002 1003 if (!hasCurrentIndex && CFArrayGetCount(historyEntries)) 1004 return false; 1005 1006 if (hasCurrentIndex) { 1007 if (static_cast<uint32_t>(currentIndex) >= backForwardListState.items.size()) 1008 return false; 1009 1010 backForwardListState.currentIndex = static_cast<uint32_t>(currentIndex); 1011 } 1012 1013 return true; 1014} 1015 1016static bool decodeV1SessionHistory(CFDictionaryRef sessionHistoryDictionary, BackForwardListState& backForwardListState) 1017{ 1018 auto currentIndexNumber = dynamic_cf_cast<CFNumberRef>(CFDictionaryGetValue(sessionHistoryDictionary, sessionHistoryCurrentIndexKey)); 1019 if (!currentIndexNumber) { 1020 // No current index means the dictionary represents an empty session. 1021 backForwardListState.currentIndex = Nullopt; 1022 backForwardListState.items = { }; 1023 return true; 1024 } 1025 1026 CFIndex currentIndex; 1027 if (!CFNumberGetValue(currentIndexNumber, kCFNumberCFIndexType, ¤tIndex)) 1028 return false; 1029 1030 if (currentIndex < 0) 1031 return false; 1032 1033 auto historyEntries = dynamic_cf_cast<CFArrayRef>(CFDictionaryGetValue(sessionHistoryDictionary, sessionHistoryEntriesKey)); 1034 if (!historyEntries) 1035 return false; 1036 1037 if (!decodeSessionHistoryEntries(historyEntries, backForwardListState.items)) 1038 return false; 1039 1040 backForwardListState.currentIndex = static_cast<uint32_t>(currentIndex); 1041 if (static_cast<uint32_t>(currentIndex) >= backForwardListState.items.size()) 1042 return false; 1043 1044 return true; 1045} 1046 1047static bool decodeSessionHistory(CFDictionaryRef backForwardListDictionary, BackForwardListState& backForwardListState) 1048{ 1049 auto sessionHistoryVersionNumber = dynamic_cf_cast<CFNumberRef>(CFDictionaryGetValue(backForwardListDictionary, sessionHistoryVersionKey)); 1050 if (!sessionHistoryVersionNumber) { 1051 // Version 0 session history dictionaries did not contain a version number. 1052 return decodeV0SessionHistory(backForwardListDictionary, backForwardListState); 1053 } 1054 1055 CFIndex sessionHistoryVersion; 1056 if (!CFNumberGetValue(sessionHistoryVersionNumber, kCFNumberCFIndexType, &sessionHistoryVersion)) 1057 return false; 1058 1059 if (sessionHistoryVersion == 1) 1060 return decodeV1SessionHistory(backForwardListDictionary, backForwardListState); 1061 1062 return false; 1063} 1064 1065bool decodeLegacySessionState(const uint8_t* bytes, size_t size, SessionState& sessionState) 1066{ 1067 if (size < sizeof(uint32_t)) 1068 return false; 1069 1070 uint32_t versionNumber = (bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + bytes[3]; 1071 1072 if (versionNumber != sessionStateDataVersion) 1073 return false; 1074 1075 auto sessionStateDictionary = adoptCF(dynamic_cf_cast<CFDictionaryRef>(CFPropertyListCreateWithData(kCFAllocatorDefault, adoptCF(CFDataCreate(kCFAllocatorDefault, bytes + sizeof(uint32_t), size - sizeof(uint32_t))).get(), kCFPropertyListImmutable, nullptr, nullptr))); 1076 if (!sessionStateDictionary) 1077 return false; 1078 1079 if (auto backForwardListDictionary = dynamic_cf_cast<CFDictionaryRef>(CFDictionaryGetValue(sessionStateDictionary.get(), sessionHistoryKey))) { 1080 if (!decodeSessionHistory(backForwardListDictionary, sessionState.backForwardListState)) 1081 return false; 1082 } 1083 1084 if (auto provisionalURLString = dynamic_cf_cast<CFStringRef>(CFDictionaryGetValue(sessionStateDictionary.get(), provisionalURLKey))) { 1085 sessionState.provisionalURL = WebCore::URL(WebCore::URL(), provisionalURLString); 1086 if (!sessionState.provisionalURL.isValid()) 1087 return false; 1088 } 1089 1090 return true; 1091} 1092 1093} // namespace WebKit 1094