diff --git a/Userland/Libraries/LibWeb/Bindings/Transferable.h b/Userland/Libraries/LibWeb/Bindings/Transferable.h new file mode 100644 index 0000000000..4873e9cb49 --- /dev/null +++ b/Userland/Libraries/LibWeb/Bindings/Transferable.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include + +namespace Web::Bindings { + +// https://html.spec.whatwg.org/multipage/structured-data.html#transferable-objects +class Transferable { +public: + virtual ~Transferable() = default; + + // NOTE: It is an error to call Base::transfer_steps in your impl + virtual WebIDL::ExceptionOr transfer_steps(HTML::TransferDataHolder&) = 0; + + // NOTE: It is an error to call Base::transfer_receiving_steps in your impl + virtual WebIDL::ExceptionOr transfer_receiving_steps(HTML::TransferDataHolder const&) = 0; + + virtual HTML::TransferType primary_interface() const = 0; + + bool is_detached() const { return m_detached; } + void set_detached(bool b) { m_detached = b; } + +private: + // https://html.spec.whatwg.org/multipage/structured-data.html#detached + bool m_detached = false; +}; + +} diff --git a/Userland/Libraries/LibWeb/HTML/MessagePort.cpp b/Userland/Libraries/LibWeb/HTML/MessagePort.cpp index 222a9dcf15..ed9d6f4b11 100644 --- a/Userland/Libraries/LibWeb/HTML/MessagePort.cpp +++ b/Userland/Libraries/LibWeb/HTML/MessagePort.cpp @@ -40,6 +40,47 @@ void MessagePort::visit_edges(Cell::Visitor& visitor) visitor.visit(m_remote_port); } +// https://html.spec.whatwg.org/multipage/web-messaging.html#message-ports:transfer-steps +WebIDL::ExceptionOr MessagePort::transfer_steps(HTML::TransferDataHolder&) +{ + // 1. Set value's has been shipped flag to true. + m_has_been_shipped = true; + + // FIXME: 2. Set dataHolder.[[PortMessageQueue]] to value's port message queue. + // FIXME: Support delivery of messages that haven't been delivered yet on the other side + + // 3. If value is entangled with another port remotePort, then: + if (is_entangled()) { + // 1. Set remotePort's has been shipped flag to true. + m_remote_port->m_has_been_shipped = true; + + // 2. Set dataHolder.[[RemotePort]] to remotePort. + // FIXME: Append an IPC::File to the dataHolder + } + + // 4. Otherwise, set dataHolder.[[RemotePort]] to null. + else { + // FIXME: Note in the dataHolder that there are no fds + } + + return {}; +} + +WebIDL::ExceptionOr MessagePort::transfer_receiving_steps(HTML::TransferDataHolder const&) +{ + // 1. Set value's has been shipped flag to true. + m_has_been_shipped = true; + + // FIXME 2. Move all the tasks that are to fire message events in dataHolder.[[PortMessageQueue]] to the port message queue of value, + // if any, leaving value's port message queue in its initial disabled state, and, if value's relevant global object is a Window, + // associating the moved tasks with value's relevant global object's associated Document. + + // FIXME: 3. If dataHolder.[[RemotePort]] is not null, then entangle dataHolder.[[RemotePort]] and value. + // (This will disentangle dataHolder.[[RemotePort]] from the original port that was transferred.) + + return {}; +} + void MessagePort::disentangle() { m_remote_port->m_remote_port = nullptr; @@ -112,7 +153,7 @@ void MessagePort::start() void MessagePort::close() { // 1. Set this MessagePort object's [[Detached]] internal slot value to true. - m_detached = true; + set_detached(true); // 2. If this MessagePort object is entangled, disentangle it. if (is_entangled()) diff --git a/Userland/Libraries/LibWeb/HTML/MessagePort.h b/Userland/Libraries/LibWeb/HTML/MessagePort.h index b079ea08f2..6126e1b6c9 100644 --- a/Userland/Libraries/LibWeb/HTML/MessagePort.h +++ b/Userland/Libraries/LibWeb/HTML/MessagePort.h @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -23,7 +24,8 @@ struct StructuredSerializeOptions { }; // https://html.spec.whatwg.org/multipage/web-messaging.html#message-ports -class MessagePort final : public DOM::EventTarget { +class MessagePort final : public DOM::EventTarget + , public Bindings::Transferable { WEB_PLATFORM_OBJECT(MessagePort, DOM::EventTarget); JS_DECLARE_ALLOCATOR(MessagePort); @@ -49,6 +51,11 @@ public: ENUMERATE_MESSAGE_PORT_EVENT_HANDLERS(__ENUMERATE) #undef __ENUMERATE + // ^Transferable + virtual WebIDL::ExceptionOr transfer_steps(HTML::TransferDataHolder&) override; + virtual WebIDL::ExceptionOr transfer_receiving_steps(HTML::TransferDataHolder const&) override; + virtual HTML::TransferType primary_interface() const override { return HTML::TransferType::MessagePort; } + private: explicit MessagePort(JS::Realm&); @@ -63,9 +70,6 @@ private: // https://html.spec.whatwg.org/multipage/web-messaging.html#has-been-shipped bool m_has_been_shipped { false }; - - // This is TransferableObject.[[Detached]] - bool m_detached { false }; }; } diff --git a/Userland/Libraries/LibWeb/HTML/StructuredSerialize.h b/Userland/Libraries/LibWeb/HTML/StructuredSerialize.h index 7830cd9577..b18d4c88bb 100644 --- a/Userland/Libraries/LibWeb/HTML/StructuredSerialize.h +++ b/Userland/Libraries/LibWeb/HTML/StructuredSerialize.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -24,6 +25,25 @@ using SerializationRecord = Vector; using SerializationMemory = HashMap, u32>; using DeserializationMemory = JS::MarkedVector; +struct TransferDataHolder { + Vector data; + Vector fds; +}; + +struct SerializedTransferRecord { + SerializationRecord serialized; + Vector transfer_data_holders; +}; + +struct DeserializedTransferRecord { + JS::Value deserialized; + JS::MarkedVector transferred_values; +}; + +enum class TransferType : u8 { + MessagePort, +}; + WebIDL::ExceptionOr structured_serialize(JS::VM& vm, JS::Value); WebIDL::ExceptionOr structured_serialize_for_storage(JS::VM& vm, JS::Value); WebIDL::ExceptionOr structured_serialize_internal(JS::VM& vm, JS::Value, bool for_storage, SerializationMemory&);