/* * 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 #include "base/containers/span.h" #include "base/optional.h" #include "third_party/blink/public/common/messaging/message_port_channel.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/core/mojo/mojo_handle.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 DOMSharedArrayBuffer; class ExceptionState; class ExecutionContext; class MessagePort; class ScriptValue; class SharedBuffer; class StaticBitmapImage; class Transferables; class UnpackedSerializedScriptValue; class WebBlobInfo; typedef HashMap> BlobDataHandleMap; typedef Vector MojoScopedHandleArray; typedef Vector WebBlobInfoArray; typedef HeapVector> SharedArrayBufferArray; class CORE_EXPORT SerializedScriptValue : public ThreadSafeRefCounted { public: using ArrayBufferContentsArray = Vector; using SharedArrayBufferContentsArray = Vector; using ImageBitmapContentsArray = Vector, 1>; using TransferredWasmModulesArray = WTF::Vector; using MessagePortChannelArray = Vector; // 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. // Version 19: Add DetectedBarcode, DetectedFace, and DetectedText support. // // 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 = 19; // 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 { STACK_ALLOCATED(); public: 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. }; 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 Serialize(v8::Isolate*, v8::Local, const SerializeOptions&, ExceptionState&); static scoped_refptr SerializeAndSwallowExceptions( v8::Isolate*, v8::Local); static scoped_refptr Create(); static scoped_refptr Create(const String&); static scoped_refptr Create( scoped_refptr); static scoped_refptr Create(const char* data, size_t length); ~SerializedScriptValue(); static scoped_refptr NullValue(); String ToWireString() const; base::span 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(); public: MessagePortArray* message_ports = nullptr; const WebBlobInfoArray* blob_info = nullptr; bool read_wasm_from_stream = false; }; v8::Local Deserialize(v8::Isolate* isolate) { return Deserialize(isolate, DeserializeOptions()); } v8::Local 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); // 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, int, Transferables&, ExceptionState&); static bool ExtractTransferables(v8::Isolate*, const Vector&, 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_; } MojoScopedHandleArray& MojoHandles() { return mojo_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); MessagePortChannelArray& GetStreamChannels() { return stream_channels_; } bool IsLockedToAgentCluster() const { return !wasm_modules_.IsEmpty() || !shared_array_buffers_contents_.IsEmpty(); } 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; 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 TransferReadableStreams(ScriptState*, const ReadableStreamArray&, ExceptionState&); void TransferReadableStream(ScriptState* script_state, ExecutionContext* execution_context, ReadableStream* readable_streams, ExceptionState& exception_state); void TransferWritableStreams(ScriptState*, const WritableStreamArray&, ExceptionState&); void TransferWritableStream(ScriptState* script_state, ExecutionContext* execution_context, WritableStream* writable_streams, ExceptionState& exception_state); void TransferTransformStreams(ScriptState*, const TransformStreamArray&, ExceptionState&); MessagePort* AddStreamChannel(ExecutionContext*); 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_; // |stream_channels_| is also single-use but is special-cased because it works // with ServiceWorkers. MessagePortChannelArray stream_channels_; // These do not have one-use transferred contents, like the above. TransferredWasmModulesArray wasm_modules_; BlobDataHandleMap blob_data_handles_; MojoScopedHandleArray mojo_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 : public NativeValueTraitsBase { CORE_EXPORT static inline scoped_refptr NativeValue( v8::Isolate* isolate, v8::Local 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_