StructuredSerialize.cpp 4.9 KB

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