Serenity Operating System
at master 159 lines 5.0 kB view raw
1/* 2 * Copyright (c) 2022, Daniel Ehrenberg <dan@littledan.dev> 3 * Copyright (c) 2022, Andrew Kaster <akaster@serenityos.org> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <AK/HashTable.h> 9#include <AK/Vector.h> 10#include <LibJS/Forward.h> 11#include <LibWeb/HTML/StructuredSerialize.h> 12#include <LibWeb/WebIDL/ExceptionOr.h> 13 14namespace Web::HTML { 15 16// Binary format: 17// A list of adjacent shallow values, which may contain references to other 18// values (noted by their position in the list, one value following another). 19// This list represents the "memory" in the StructuredSerialize algorithm. 20// The first item in the list is the root, i.e., the value of everything. 21// The format is generally u32-aligned (hence this leaking out into the type) 22// Each value has a length based on its type, as defined below. 23// 24// (Should more redundancy be added, e.g., for lengths/positions of values?) 25 26enum ValueTag { 27 // Unused, for ease of catching bugs 28 Empty, 29 30 // Following two u32s are the double value 31 NumberPrimitive, 32 33 // TODO: Define many more types 34 35 // This tag or higher are understood to be errors 36 ValueTagMax, 37}; 38 39// Serializing and deserializing are each two passes: 40// 1. Fill up the memory with all the values, but without translating references 41// 2. Translate all the references into the appropriate form 42 43class Serializer { 44public: 45 Serializer(JS::VM& vm) 46 : m_vm(vm) 47 { 48 } 49 50 void serialize(JS::Value value) 51 { 52 if (value.is_number()) { 53 m_serialized.append(ValueTag::NumberPrimitive); 54 double number = value.as_double(); 55 m_serialized.append(bit_cast<u32*>(&number), 2); 56 } else { 57 // TODO: Define many more types 58 m_error = "Unsupported type"sv; 59 } 60 } 61 62 WebIDL::ExceptionOr<Vector<u32>> result() 63 { 64 if (m_error.is_null()) 65 return m_serialized; 66 return throw_completion(WebIDL::DataCloneError::create(*m_vm.current_realm(), m_error)); 67 } 68 69private: 70 AK::StringView m_error; 71 SerializationMemory m_memory; // JS value -> index 72 SerializationRecord m_serialized; 73 JS::VM& m_vm; 74}; 75 76class Deserializer { 77public: 78 Deserializer(JS::VM& vm, JS::Realm& target_realm, SerializationRecord const& v) 79 : m_vm(vm) 80 , m_vector(v) 81 , m_memory(target_realm.heap()) 82 { 83 } 84 85 void deserialize() 86 { 87 // First pass: fill up the memory with new values 88 u32 position = 0; 89 while (position < m_vector.size()) { 90 switch (m_vector[position++]) { 91 case ValueTag::NumberPrimitive: { 92 u32 bits[2]; 93 bits[0] = m_vector[position++]; 94 bits[1] = m_vector[position++]; 95 double value = *bit_cast<double*>(&bits); 96 m_memory.append(JS::Value(value)); 97 break; 98 } 99 default: 100 m_error = "Unsupported type"sv; 101 return; 102 } 103 } 104 105 // Second pass: Update the objects to point to other objects in memory 106 } 107 108 WebIDL::ExceptionOr<JS::Value> result() 109 { 110 if (m_error.is_null()) 111 return m_memory[0]; 112 return throw_completion(WebIDL::DataCloneError::create(*m_vm.current_realm(), m_error)); 113 } 114 115private: 116 JS::VM& m_vm; 117 SerializationRecord const& m_vector; 118 JS::MarkedVector<JS::Value> m_memory; // Index -> JS value 119 StringView m_error; 120}; 121 122// https://html.spec.whatwg.org/multipage/structured-data.html#structuredserialize 123WebIDL::ExceptionOr<SerializationRecord> structured_serialize(JS::VM& vm, JS::Value value) 124{ 125 // 1. Return ? StructuredSerializeInternal(value, false). 126 return structured_serialize_internal(vm, value, false, {}); 127} 128 129// https://html.spec.whatwg.org/multipage/structured-data.html#structuredserializeforstorage 130WebIDL::ExceptionOr<SerializationRecord> structured_serialize_for_storage(JS::VM& vm, JS::Value value) 131{ 132 // 1. Return ? StructuredSerializeInternal(value, true). 133 return structured_serialize_internal(vm, value, true, {}); 134} 135 136// https://html.spec.whatwg.org/multipage/structured-data.html#structuredserializeinternal 137WebIDL::ExceptionOr<SerializationRecord> structured_serialize_internal(JS::VM& vm, JS::Value value, bool for_storage, Optional<SerializationMemory> memory) 138{ 139 // FIXME: Do the spec steps 140 (void)for_storage; 141 (void)memory; 142 143 Serializer serializer(vm); 144 serializer.serialize(value); 145 return serializer.result(); // TODO: Avoid several copies of vector 146} 147 148// https://html.spec.whatwg.org/multipage/structured-data.html#structureddeserialize 149WebIDL::ExceptionOr<JS::Value> structured_deserialize(JS::VM& vm, SerializationRecord const& serialized, JS::Realm& target_realm, Optional<SerializationMemory> memory) 150{ 151 // FIXME: Do the spec steps 152 (void)memory; 153 154 Deserializer deserializer(vm, target_realm, serialized); 155 deserializer.deserialize(); 156 return deserializer.result(); 157} 158 159}