blob: de1f5528f25a71684912dc444e3fb3b69c2da2d5 [file] [log] [blame]
/*
* Copyright (C) 2009, 2010 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SERIALIZATION_SERIALIZED_SCRIPT_VALUE_H_
#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SERIALIZATION_SERIALIZED_SCRIPT_VALUE_H_
#include <memory>
#include "base/containers/span.h"
#include "base/optional.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits.h"
#include "third_party/blink/renderer/bindings/core/v8/serialization/transferables.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
#include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
#include "third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer_contents.h"
#include "v8/include/v8.h"
namespace blink {
class BlobDataHandle;
class Transferables;
class ExceptionState;
class SharedBuffer;
class StaticBitmapImage;
class UnpackedSerializedScriptValue;
class WebBlobInfo;
class DOMSharedArrayBuffer;
typedef HashMap<String, scoped_refptr<BlobDataHandle>> BlobDataHandleMap;
typedef Vector<WebBlobInfo> WebBlobInfoArray;
typedef HeapVector<Member<DOMSharedArrayBuffer>> SharedArrayBufferArray;
class CORE_EXPORT SerializedScriptValue
: public ThreadSafeRefCounted<SerializedScriptValue> {
public:
using ArrayBufferContentsArray = Vector<WTF::ArrayBufferContents, 1>;
using SharedArrayBufferContentsArray = Vector<WTF::ArrayBufferContents, 1>;
using ImageBitmapContentsArray = Vector<scoped_refptr<StaticBitmapImage>, 1>;
using TransferredWasmModulesArray =
WTF::Vector<v8::WasmCompiledModule::TransferrableModule>;
// Increment this for each incompatible change to the wire format.
// Version 2: Added StringUCharTag for UChar v8 strings.
// Version 3: Switched to using uuids as blob data identifiers.
// Version 4: Extended File serialization to be complete.
// Version 5: Added CryptoKeyTag for Key objects.
// Version 6: Added indexed serialization for File, Blob, and FileList.
// Version 7: Extended File serialization with user visibility.
// Version 8: File.lastModified in milliseconds (seconds-based in earlier
// versions.)
// Version 9: Added Map and Set support.
// [versions skipped]
// Version 16: Separate versioning between V8 and Blink.
// Version 17: Remove unnecessary byte swapping.
// Version 18: Add a list of key-value pairs for ImageBitmap and ImageData to
// support color space information, compression, etc.
//
// The following versions cannot be used, in order to be able to
// deserialize version 0 SSVs. The class implementation has details.
// DO NOT USE: 35, 64, 68, 73, 78, 82, 83, 85, 91, 98, 102, 108, 123.
//
// WARNING: Increasing this value is a change which cannot safely be rolled
// back without breaking compatibility with data stored on disk. It is
// strongly recommended that you do not make such changes near a release
// milestone branch point.
//
// Recent changes are routinely reverted in preparation for branch, and this
// has been the cause of at least one bug in the past.
static constexpr uint32_t kWireFormatVersion = 18;
// This enumeration specifies whether we're serializing a value for storage;
// e.g. when writing to IndexedDB. This corresponds to the forStorage flag of
// the HTML spec:
// https://html.spec.whatwg.org/multipage/infrastructure.html#safe-passing-of-structured-data
enum StoragePolicy {
// Not persisted; used only during the execution of the browser.
kNotForStorage,
// May be written to disk and read during a subsequent execution of the
// browser.
kForStorage,
};
struct SerializeOptions {
enum WasmSerializationPolicy {
kUnspecified, // Invalid value, used as default initializer.
kTransfer, // In-memory transfer without (necessarily) serializing.
kSerialize, // Serialize to a byte stream.
kBlockedInNonSecureContext // Block transfer or serialization.
};
STACK_ALLOCATED();
SerializeOptions() = default;
explicit SerializeOptions(StoragePolicy for_storage)
: for_storage(for_storage) {}
Transferables* transferables = nullptr;
WebBlobInfoArray* blob_info = nullptr;
WasmSerializationPolicy wasm_policy = kTransfer;
StoragePolicy for_storage = kNotForStorage;
};
static scoped_refptr<SerializedScriptValue> Serialize(v8::Isolate*,
v8::Local<v8::Value>,
const SerializeOptions&,
ExceptionState&);
static scoped_refptr<SerializedScriptValue> SerializeAndSwallowExceptions(
v8::Isolate*,
v8::Local<v8::Value>);
static scoped_refptr<SerializedScriptValue> Create();
static scoped_refptr<SerializedScriptValue> Create(const String&);
static scoped_refptr<SerializedScriptValue> Create(
scoped_refptr<const SharedBuffer>);
static scoped_refptr<SerializedScriptValue> Create(const char* data,
size_t length);
~SerializedScriptValue();
static scoped_refptr<SerializedScriptValue> NullValue();
String ToWireString() const;
base::span<const uint8_t> GetWireData() const {
return {data_buffer_.get(), data_buffer_size_};
}
// Deserializes the value (in the current context). Returns a null value in
// case of failure.
struct DeserializeOptions {
STACK_ALLOCATED();
MessagePortArray* message_ports = nullptr;
const WebBlobInfoArray* blob_info = nullptr;
bool read_wasm_from_stream = false;
};
v8::Local<v8::Value> Deserialize(v8::Isolate* isolate) {
return Deserialize(isolate, DeserializeOptions());
}
v8::Local<v8::Value> Deserialize(v8::Isolate*, const DeserializeOptions&);
// Takes ownership of a reference and creates an "unpacked" version of this
// value, where the transferred contents have been turned into complete
// objects local to this thread. A SerializedScriptValue can only be unpacked
// once, and the result is bound to a thread.
// See UnpackedSerializedScriptValue.h for more details.
static UnpackedSerializedScriptValue* Unpack(
scoped_refptr<SerializedScriptValue>);
// Used for debugging. Returns true if there are "packed" transferred contents
// which would require this value to be unpacked before deserialization.
// See UnpackedSerializedScriptValue.h for more details.
bool HasPackedContents() const;
// Helper function which pulls the values out of a JS sequence and into a
// MessagePortArray. Also validates the elements per sections 4.1.13 and
// 4.1.15 of the WebIDL spec and section 8.3.3 of the HTML5 spec and generates
// exceptions as appropriate.
// Returns true if the array was filled, or false if the passed value was not
// of an appropriate type.
static bool ExtractTransferables(v8::Isolate*,
v8::Local<v8::Value>,
int,
Transferables&,
ExceptionState&);
static ArrayBufferArray ExtractNonSharedArrayBuffers(Transferables&);
// Helper function which pulls ArrayBufferContents out of an ArrayBufferArray
// and neuters the ArrayBufferArray. Returns nullptr if there is an
// exception.
static ArrayBufferContentsArray TransferArrayBufferContents(
v8::Isolate*,
const ArrayBufferArray&,
ExceptionState&);
static ImageBitmapContentsArray TransferImageBitmapContents(
v8::Isolate*,
const ImageBitmapArray&,
ExceptionState&);
// Informs V8 about external memory allocated and owned by this object.
// Large values should contribute to GC counters to eventually trigger a GC,
// otherwise flood of postMessage() can cause OOM.
// Ok to invoke multiple times (only adds memory once).
// The memory registration is revoked automatically in destructor.
void RegisterMemoryAllocatedWithCurrentScriptContext();
// The dual, unregistering / subtracting the external memory allocation costs
// of this SerializedScriptValue with the current context. This includes
// discounting the cost of the transferables.
//
// The value is updated and marked as having no allocations registered,
// hence subsequent calls will be no-ops.
void UnregisterMemoryAllocatedWithCurrentScriptContext();
const uint8_t* Data() const { return data_buffer_.get(); }
size_t DataLengthInBytes() const { return data_buffer_size_; }
TransferredWasmModulesArray& WasmModules() { return wasm_modules_; }
SharedArrayBufferContentsArray& SharedArrayBuffersContents() {
return shared_array_buffers_contents_;
}
BlobDataHandleMap& BlobDataHandles() { return blob_data_handles_; }
ArrayBufferContentsArray& GetArrayBufferContentsArray() {
return array_buffer_contents_array_;
}
void SetArrayBufferContentsArray(ArrayBufferContentsArray contents) {
array_buffer_contents_array_ = std::move(contents);
}
ImageBitmapContentsArray& GetImageBitmapContentsArray() {
return image_bitmap_contents_array_;
}
void SetImageBitmapContentsArray(ImageBitmapContentsArray contents);
private:
friend class ScriptValueSerializer;
friend class V8ScriptValueSerializer;
friend class UnpackedSerializedScriptValue;
struct BufferDeleter {
void operator()(uint8_t* buffer) { WTF::Partitions::BufferFree(buffer); }
};
using DataBufferPtr = std::unique_ptr<uint8_t[], BufferDeleter>;
SerializedScriptValue();
SerializedScriptValue(DataBufferPtr, size_t data_size);
static DataBufferPtr AllocateBuffer(size_t);
void SetData(DataBufferPtr data, size_t size) {
data_buffer_ = std::move(data);
data_buffer_size_ = size;
}
void TransferArrayBuffers(v8::Isolate*,
const ArrayBufferArray&,
ExceptionState&);
void TransferImageBitmaps(v8::Isolate*,
const ImageBitmapArray&,
ExceptionState&);
void TransferOffscreenCanvas(v8::Isolate*,
const OffscreenCanvasArray&,
ExceptionState&);
void CloneSharedArrayBuffers(SharedArrayBufferArray&);
DataBufferPtr data_buffer_;
size_t data_buffer_size_ = 0;
// These two have one-use transferred contents, and are stored in
// UnpackedSerializedScriptValue thereafter.
ArrayBufferContentsArray array_buffer_contents_array_;
ImageBitmapContentsArray image_bitmap_contents_array_;
// These do not have one-use transferred contents, like the above.
TransferredWasmModulesArray wasm_modules_;
BlobDataHandleMap blob_data_handles_;
SharedArrayBufferContentsArray shared_array_buffers_contents_;
bool has_registered_external_allocation_;
bool transferables_need_external_allocation_registration_;
#if DCHECK_IS_ON()
bool was_unpacked_ = false;
#endif
};
template <>
struct NativeValueTraits<SerializedScriptValue>
: public NativeValueTraitsBase<SerializedScriptValue> {
CORE_EXPORT static inline scoped_refptr<SerializedScriptValue> NativeValue(
v8::Isolate* isolate,
v8::Local<v8::Value> value,
const SerializedScriptValue::SerializeOptions& options,
ExceptionState& exception_state) {
return SerializedScriptValue::Serialize(isolate, value, options,
exception_state);
}
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SERIALIZATION_SERIALIZED_SCRIPT_VALUE_H_