1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 11:08:11 +00:00

LibWeb: Add ability to {,de}serialize platform objects

This adds the ability to serialize and deserialize serializable platform
object in structured_serialize() and structured_deserialize().
This commit is contained in:
Kenneth Myhra 2024-02-23 18:32:27 +01:00 committed by Andrew Kaster
parent 394c38729f
commit 27445f3132

View file

@ -31,7 +31,9 @@
#include <LibJS/Runtime/VM.h>
#include <LibWeb/Bindings/ExceptionOrUtils.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Bindings/Serializable.h>
#include <LibWeb/Bindings/Transferable.h>
#include <LibWeb/FileAPI/Blob.h>
#include <LibWeb/HTML/MessagePort.h>
#include <LibWeb/HTML/StructuredSerialize.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
@ -105,6 +107,8 @@ enum ValueTag {
ObjectReference,
SerializableObject,
// TODO: Define many more types
// This tag or higher are understood to be errors
@ -310,6 +314,14 @@ public:
}
// FIXME: 19. Otherwise, if value is a platform object that is a serializable object:
else if (value.is_object() && is<Bindings::Serializable>(value.as_object())) {
auto& serializable = dynamic_cast<Bindings::Serializable&>(value.as_object());
m_serialized.append(ValueTag::SerializableObject);
// 1. Perform the serialization steps for value's primary interface, given value, serialized, and forStorage.
TRY(serializable.serialization_steps(m_serialized, m_for_storage));
}
// 20. Otherwise, if value is a platform object, then throw a "DataCloneError" DOMException.
else if (value.is_object() && is<Bindings::PlatformObject>(value.as_object())) {
@ -812,7 +824,20 @@ public:
}
// 22. Otherwise:
default:
return WebIDL::DataCloneError::create(*m_vm.current_realm(), "Unsupported type"_fly_string);
VERIFY(tag == ValueTag::SerializableObject);
auto& realm = *m_vm.current_realm();
// 1. Let interfaceName be serialized.[[Type]].
auto interface_name = TRY(deserialize_string(m_vm, m_serialized, m_position));
// 2. If the interface identified by interfaceName is not exposed in targetRealm, then throw a "DataCloneError" DOMException.
if (!is_interface_exposed_on_target_realm(interface_name, realm))
return WebIDL::DataCloneError::create(realm, "Unsupported type"_fly_string);
// 3. Set value to a new instance of the interface identified by interfaceName, created in targetRealm.
value = TRY(create_serialized_type(interface_name, realm));
// 4. Set deep to true.
deep = true;
}
// 23. Set memory[serialized] to value.
@ -874,8 +899,9 @@ public:
// 4. Otherwise:
else {
// FIXME: 1. Perform the appropriate deserialization steps for the interface identified by serialized.[[Type]], given serialized, value, and targetRealm.
VERIFY_NOT_REACHED();
// 1. Perform the appropriate deserialization steps for the interface identified by serialized.[[Type]], given serialized, value, and targetRealm.
auto& serializable = dynamic_cast<Bindings::Serializable&>(value.as_object());
TRY(serializable.deserialization_steps(m_serialized, m_position));
}
}
@ -896,6 +922,22 @@ private:
m_position += 2;
return value;
}
static WebIDL::ExceptionOr<JS::NonnullGCPtr<Bindings::PlatformObject>> create_serialized_type(StringView interface_name, JS::Realm& realm)
{
if (interface_name == "Blob"sv)
return FileAPI::Blob::create(realm);
VERIFY_NOT_REACHED();
}
// FIXME: Consolidate this function with the similar is_interface_exposed_on_target_realm() used when transferring objects.
// Also, the name parameter would be better off being the interface name (as a string) so that we don't need a switch statement.
static bool is_interface_exposed_on_target_realm(StringView interface_name, JS::Realm& realm)
{
auto const& intrinsics = Bindings::host_defined_intrinsics(realm);
return intrinsics.is_exposed(interface_name);
}
};
WebIDL::ExceptionOr<ByteBuffer> deserialize_bytes(JS::VM& vm, ReadonlySpan<u32> vector, size_t& position)