| Index: third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.cpp
|
| diff --git a/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.cpp b/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.cpp
|
| index 8efc23cd4283067ed3ef31ede6ae472dd36ef848..4e43b3d324bd3af9203debf156b7a6782bd7fedf 100644
|
| --- a/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.cpp
|
| +++ b/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.cpp
|
| @@ -35,6 +35,7 @@
|
| #include "bindings/core/v8/DOMWrapperWorld.h"
|
| #include "bindings/core/v8/ExceptionState.h"
|
| #include "bindings/core/v8/ScriptState.h"
|
| +#include "bindings/core/v8/SerializationTag.h"
|
| #include "bindings/core/v8/SerializedScriptValueFactory.h"
|
| #include "bindings/core/v8/Transferables.h"
|
| #include "bindings/core/v8/V8ArrayBuffer.h"
|
| @@ -54,6 +55,7 @@
|
| #include "platform/wtf/ByteOrder.h"
|
| #include "platform/wtf/PtrUtil.h"
|
| #include "platform/wtf/Vector.h"
|
| +#include "platform/wtf/dtoa/utils.h"
|
| #include "platform/wtf/text/StringBuffer.h"
|
| #include "platform/wtf/text/StringHash.h"
|
|
|
| @@ -89,22 +91,124 @@ PassRefPtr<SerializedScriptValue> SerializedScriptValue::Create(
|
| return AdoptRef(new SerializedScriptValue(data));
|
| }
|
|
|
| +// Versions 16 and below (prior to April 2017) used ntohs() to byte-swap SSV
|
| +// data when converting it to the wire format. This was a historical accient.
|
| +//
|
| +// As IndexedDB stores SSVs to disk indefinitely, we still need to keep around
|
| +// the code needed to deserialize the old format.
|
| +inline static bool IsByteSwappedWiredData(const char* data, size_t length) {
|
| + // TODO(pwnall): Return false early if we're on big-endian hardware. Chromium
|
| + // doesn't currently support big-endian hardware, and there's no header
|
| + // exposing endianness to Blink yet. ARCH_CPU_LITTLE_ENDIAN seems promising,
|
| + // but Blink is not currently allowed to include files from build/.
|
| +
|
| + // The first SSV version without byte-swapping has two envelopes (Blink, V8),
|
| + // each of which is at least 2 bytes long.
|
| + if (length < 4)
|
| + return true;
|
| +
|
| + // This code handles the following cases:
|
| + //
|
| + // v0 (byte-swapped) - [d, t, ...], t = tag byte, d = first data byte
|
| + // v1-16 (byte-swapped) - [v, 0xFF, ...], v = version (1 <= v <= 16)
|
| + // v17+ - [0xFF, v, ...], v = first byte of version varint
|
| +
|
| + if (static_cast<uint8_t>(data[0]) == kVersionTag) {
|
| + // The only case where byte-swapped data can have 0xFF in byte zero is
|
| + // version 0. This can only happen if byte one is a tag (supported in
|
| + // version 0) that takes in extra data, and the first byte of extra data is
|
| + // 0xFF. There are 13 such tags, listed below. These tags cannot be used as
|
| + // version numbers in the Blink-side SSV envelope.
|
| + //
|
| + // 35 - 0x23 - # - ImageDataTag
|
| + // 64 - 0x40 - @ - SparseArrayTag
|
| + // 68 - 0x44 - D - DateTag
|
| + // 73 - 0x49 - I - Int32Tag
|
| + // 78 - 0x4E - N - NumberTag
|
| + // 82 - 0x52 - R - RegExpTag
|
| + // 83 - 0x53 - S - StringTag
|
| + // 85 - 0x55 - U - Uint32Tag
|
| + // 91 - 0x5B - [ - ArrayTag
|
| + // 98 - 0x62 - b - BlobTag
|
| + // 102 - 0x66 - f - FileTag
|
| + // 108 - 0x6C - l - FileListTag
|
| + // 123 - 0x7B - { - ObjectTag
|
| + //
|
| + // Why we care about version 0:
|
| + //
|
| + // IndexedDB stores values using the SSV format. Currently, IndexedDB does
|
| + // not do any sort of migration, so a value written with a SSV version will
|
| + // be stored with that version until it is removed via an update or delete.
|
| + //
|
| + // IndexedDB was shipped in Chrome 11, which was released on April 27, 2011.
|
| + // SSV version 1 was added in WebKit r91698, which was shipped in Chrome 14,
|
| + // which was released on September 16, 2011.
|
| + static_assert(
|
| + SerializedScriptValue::kWireFormatVersion != 35 &&
|
| + SerializedScriptValue::kWireFormatVersion != 64 &&
|
| + SerializedScriptValue::kWireFormatVersion != 68 &&
|
| + SerializedScriptValue::kWireFormatVersion != 73 &&
|
| + SerializedScriptValue::kWireFormatVersion != 78 &&
|
| + SerializedScriptValue::kWireFormatVersion != 82 &&
|
| + SerializedScriptValue::kWireFormatVersion != 83 &&
|
| + SerializedScriptValue::kWireFormatVersion != 85 &&
|
| + SerializedScriptValue::kWireFormatVersion != 91 &&
|
| + SerializedScriptValue::kWireFormatVersion != 98 &&
|
| + SerializedScriptValue::kWireFormatVersion != 102 &&
|
| + SerializedScriptValue::kWireFormatVersion != 108 &&
|
| + SerializedScriptValue::kWireFormatVersion != 123,
|
| + "Using a burned version will prevent us from reading SSV version 0");
|
| +
|
| + // Fast path until the Blink-side SSV envelope reaches version 35.
|
| + if (SerializedScriptValue::kWireFormatVersion < 35) {
|
| + if (static_cast<uint8_t>(data[1]) < 35)
|
| + return false;
|
| +
|
| + // TODO(pwnall): Add UMA metric here.
|
| + return true;
|
| + }
|
| +
|
| + // Slower path that would kick in after version 35, assuming we don't remove
|
| + // support for SSV version 0 by then.
|
| + static constexpr uint8_t version0Tags[] = {35, 64, 68, 73, 78, 82, 83,
|
| + 85, 91, 98, 102, 108, 123};
|
| + return std::find(std::begin(version0Tags), std::end(version0Tags),
|
| + data[1]) != std::end(version0Tags);
|
| + }
|
| +
|
| + if (static_cast<uint8_t>(data[1]) == kVersionTag) {
|
| + // The last SSV format that used byte-swapping was version 16. The version
|
| + // number is stored (before byte-swapping) after a serialization tag, which
|
| + // is 0xFF.
|
| + return static_cast<uint8_t>(data[0]) != kVersionTag;
|
| + }
|
| +
|
| + // If kVersionTag isn't in any of the first two bytes, this is SSV version 0,
|
| + // which was byte-swapped.
|
| + return true;
|
| +}
|
| +
|
| PassRefPtr<SerializedScriptValue> SerializedScriptValue::Create(
|
| const char* data,
|
| size_t length) {
|
| if (!data)
|
| return Create();
|
|
|
| - // Decode wire data from big endian to host byte order.
|
| DCHECK(!(length % sizeof(UChar)));
|
| - size_t string_length = length / sizeof(UChar);
|
| - StringBuffer<UChar> buffer(string_length);
|
| const UChar* src = reinterpret_cast<const UChar*>(data);
|
| - UChar* dst = buffer.Characters();
|
| - for (size_t i = 0; i < string_length; i++)
|
| - dst[i] = ntohs(src[i]);
|
| + size_t string_length = length / sizeof(UChar);
|
|
|
| - return AdoptRef(new SerializedScriptValue(String::Adopt(buffer)));
|
| + if (IsByteSwappedWiredData(data, length)) {
|
| + // Decode wire data from big endian to host byte order.
|
| + StringBuffer<UChar> buffer(string_length);
|
| + UChar* dst = buffer.Characters();
|
| + for (size_t i = 0; i < string_length; ++i)
|
| + dst[i] = ntohs(src[i]);
|
| +
|
| + return AdoptRef(new SerializedScriptValue(String::Adopt(buffer)));
|
| + }
|
| +
|
| + return AdoptRef(new SerializedScriptValue(String(src, string_length)));
|
| }
|
|
|
| SerializedScriptValue::SerializedScriptValue()
|
| @@ -134,8 +238,9 @@ SerializedScriptValue::~SerializedScriptValue() {
|
| }
|
|
|
| PassRefPtr<SerializedScriptValue> SerializedScriptValue::NullValue() {
|
| - // UChar rather than uint8_t here to get host endian behavior.
|
| - static const UChar kNullData[] = {0xff09, 0x3000};
|
| + // The format here may fall a bit out of date, because we support
|
| + // deserializing SSVs written by old browser versions.
|
| + static const uint8_t kNullData[] = {0xFF, 17, 0xFF, 13, '0', 0x00};
|
| return Create(reinterpret_cast<const char*>(kNullData), sizeof(kNullData));
|
| }
|
|
|
| @@ -152,22 +257,17 @@ String SerializedScriptValue::ToWireString() const {
|
| return wire_string;
|
| }
|
|
|
| -// Convert serialized string to big endian wire data.
|
| void SerializedScriptValue::ToWireBytes(Vector<char>& result) const {
|
| DCHECK(result.IsEmpty());
|
|
|
| - size_t wire_size_bytes = (data_buffer_size_ + 1) & ~1;
|
| - result.Resize(wire_size_bytes);
|
| + size_t result_size = (data_buffer_size_ + 1) & ~1;
|
| + result.Resize(result_size);
|
| + memcpy(result.Data(), data_buffer_.get(), data_buffer_size_);
|
|
|
| - const UChar* src = reinterpret_cast<UChar*>(data_buffer_.get());
|
| - UChar* dst = reinterpret_cast<UChar*>(result.Data());
|
| - for (size_t i = 0; i < data_buffer_size_ / 2; i++)
|
| - dst[i] = htons(src[i]);
|
| -
|
| - // This is equivalent to swapping the byte order of the two bytes (x, 0),
|
| - // depending on endianness.
|
| - if (data_buffer_size_ % 2)
|
| - dst[wire_size_bytes / 2 - 1] = data_buffer_[data_buffer_size_ - 1] << 8;
|
| + if (result_size > data_buffer_size_) {
|
| + DCHECK_EQ(result_size, data_buffer_size_ + 1);
|
| + result[data_buffer_size_] = 0;
|
| + }
|
| }
|
|
|
| static void AccumulateArrayBuffersForAllWorlds(
|
|
|