/* * Copyright (C) 2009, 2013, 2016 Apple 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: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. * */ #pragma once #include "Blob.h" #include "DetachedRTCDataChannel.h" #include "ExceptionOr.h" #include #include #include #include #include #include #include typedef const struct OpaqueJSContext* JSContextRef; typedef const struct OpaqueJSValue* JSValueRef; #if ENABLE(WEBASSEMBLY) namespace JSC { namespace Wasm { class Module; class MemoryHandle; } } #endif namespace WebCore { #if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS) class DetachedOffscreenCanvas; #endif class IDBValue; class MessagePort; class ImageBitmapBacking; class FragmentedSharedBuffer; enum class SerializationReturnCode; enum class SerializationErrorMode { NonThrowing, Throwing }; enum class SerializationContext { Default, WorkerPostMessage, WindowPostMessage }; using ArrayBufferContentsArray = Vector; #if ENABLE(WEBASSEMBLY) using WasmModuleArray = Vector>; using WasmMemoryHandleArray = Vector>; #endif DECLARE_ALLOCATOR_WITH_HEAP_IDENTIFIER(SerializedScriptValue); class SerializedScriptValue : public ThreadSafeRefCounted { WTF_MAKE_FAST_ALLOCATED_WITH_HEAP_IDENTIFIER(SerializedScriptValue); public: WEBCORE_EXPORT static ExceptionOr> create(JSC::JSGlobalObject&, JSC::JSValue, Vector>&& transfer, Vector>&, SerializationContext = SerializationContext::Default); WEBCORE_EXPORT static RefPtr create(JSC::JSGlobalObject&, JSC::JSValue, SerializationErrorMode = SerializationErrorMode::Throwing, SerializationContext = SerializationContext::Default); WEBCORE_EXPORT static RefPtr create(StringView); static Ref nullValue(); WEBCORE_EXPORT JSC::JSValue deserialize(JSC::JSGlobalObject&, JSC::JSGlobalObject*, SerializationErrorMode = SerializationErrorMode::Throwing); WEBCORE_EXPORT JSC::JSValue deserialize(JSC::JSGlobalObject&, JSC::JSGlobalObject*, const Vector>&, SerializationErrorMode = SerializationErrorMode::Throwing); JSC::JSValue deserialize(JSC::JSGlobalObject&, JSC::JSGlobalObject*, const Vector>&, const Vector& blobURLs, const Vector& blobFilePaths, SerializationErrorMode = SerializationErrorMode::Throwing); static uint32_t wireFormatVersion(); String toString() const; // API implementation helpers. These don't expose special behavior for ArrayBuffers or MessagePorts. WEBCORE_EXPORT static RefPtr create(JSContextRef, JSValueRef, JSValueRef* exception); WEBCORE_EXPORT JSValueRef deserialize(JSContextRef, JSValueRef* exception); // bool hasBlobURLs() const { return !m_blobHandles.isEmpty(); } // Vector blobURLs() const; // const Vector& blobHandles() const { return m_blobHandles; } // void writeBlobsToDiskForIndexedDB(CompletionHandler&&); // IDBValue writeBlobsToDiskForIndexedDBSynchronously(); static Ref createFromWireBytes(Vector&& data) { return adoptRef(*new SerializedScriptValue(WTFMove(data))); } const Vector& wireBytes() const { return m_data; } template void encode(Encoder&) const; template static RefPtr decode(Decoder&); size_t memoryCost() const { return m_memoryCost; } WEBCORE_EXPORT ~SerializedScriptValue(); private: static ExceptionOr> create(JSC::JSGlobalObject&, JSC::JSValue, Vector>&& transfer, Vector>&, SerializationErrorMode, SerializationContext); WEBCORE_EXPORT SerializedScriptValue( Vector&&, std::unique_ptr&& = nullptr #if ENABLE(WEB_RTC) , Vector>&& = {} #endif ); SerializedScriptValue( Vector&&, /*const Vector& blobHandles,*/ std::unique_ptr, std::unique_ptr sharedBuffers /*,Vector>&& backingStores*/ #if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS) , Vector>&& = {} #endif #if ENABLE(WEB_RTC) , Vector>&& = {} #endif #if ENABLE(WEBASSEMBLY) , std::unique_ptr = nullptr, std::unique_ptr = nullptr #endif ); size_t computeMemoryCost() const; Vector m_data; std::unique_ptr m_arrayBufferContentsArray; std::unique_ptr m_sharedBufferContentsArray; // Vector> m_backingStores; #if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS) Vector> m_detachedOffscreenCanvases; #endif #if ENABLE(WEB_RTC) Vector> m_detachedRTCDataChannels; #endif #if ENABLE(WEBASSEMBLY) std::unique_ptr m_wasmModulesArray; std::unique_ptr m_wasmMemoryHandlesArray; #endif // Vector m_blobHandles; size_t m_memoryCost { 0 }; }; template void SerializedScriptValue::encode(Encoder& encoder) const { encoder << m_data; auto hasArray = m_arrayBufferContentsArray && m_arrayBufferContentsArray->size(); encoder << hasArray; if (hasArray) { encoder << static_cast(m_arrayBufferContentsArray->size()); for (const auto& arrayBufferContents : *m_arrayBufferContentsArray) { encoder << static_cast(arrayBufferContents.sizeInBytes()); encoder.encodeFixedLengthData(static_cast(arrayBufferContents.data()), arrayBufferContents.sizeInBytes(), 1); } } #if ENABLE(WEB_RTC) encoder << static_cast(m_detachedRTCDataChannels.size()); for (const auto& channel : m_detachedRTCDataChannels) encoder << *channel; #endif } template RefPtr SerializedScriptValue::decode(Decoder& decoder) { Vector data; if (!decoder.decode(data)) return nullptr; bool hasArray; if (!decoder.decode(hasArray)) return nullptr; std::unique_ptr arrayBufferContentsArray; if (hasArray) { uint64_t arrayLength; if (!decoder.decode(arrayLength)) return nullptr; ASSERT(arrayLength); arrayBufferContentsArray = makeUnique(); while (arrayLength--) { uint64_t bufferSize; if (!decoder.decode(bufferSize)) return nullptr; CheckedSize checkedBufferSize = bufferSize; if (checkedBufferSize.hasOverflowed()) return nullptr; if (!decoder.template bufferIsLargeEnoughToContain(bufferSize)) return nullptr; auto buffer = Gigacage::tryMalloc(Gigacage::Primitive, bufferSize); if (!buffer) return nullptr; if (!decoder.decodeFixedLengthData(static_cast(buffer), bufferSize, 1)) { Gigacage::free(Gigacage::Primitive, buffer); return nullptr; } arrayBufferContentsArray->append({ buffer, checkedBufferSize, ArrayBuffer::primitiveGigacageDestructor() }); } } #if ENABLE(WEB_RTC) uint64_t detachedRTCDataChannelsSize; if (!decoder.decode(detachedRTCDataChannelsSize)) return nullptr; Vector> detachedRTCDataChannels; while (detachedRTCDataChannelsSize--) { auto detachedRTCDataChannel = DetachedRTCDataChannel::decode(decoder); if (!detachedRTCDataChannel) return nullptr; detachedRTCDataChannels.append(WTFMove(detachedRTCDataChannel)); } #endif return adoptRef(*new SerializedScriptValue(WTFMove(data), WTFMove(arrayBufferContentsArray) #if ENABLE(WEB_RTC) , WTFMove(detachedRTCDataChannels) #endif )); } }