2021-09-19 22:12:31 +02:00
/*
2024-10-04 13:19:50 +02:00
* Copyright ( c ) 2021 , Andreas Kling < andreas @ ladybird . org >
2023-12-19 15:28:56 -07:00
* Copyright ( c ) 2023 , Andrew Kaster < akaster @ serenityos . org >
2021-09-19 22:12:31 +02:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2024-04-17 16:46:24 -06:00
# include <AK/ByteReader.h>
2023-12-19 15:28:56 -07:00
# include <AK/MemoryStream.h>
2023-12-18 17:24:31 -07:00
# include <LibCore/Socket.h>
# include <LibCore/System.h>
2023-12-19 15:28:56 -07:00
# include <LibIPC/Decoder.h>
# include <LibIPC/Encoder.h>
2023-12-18 17:24:31 -07:00
# include <LibIPC/File.h>
2024-10-22 15:47:33 -06:00
# include <LibIPC/Transport.h>
2023-12-18 17:24:31 -07:00
# include <LibWeb/Bindings/ExceptionOrUtils.h>
2022-09-25 16:38:21 -06:00
# include <LibWeb/Bindings/Intrinsics.h>
2023-12-18 17:24:31 -07:00
# include <LibWeb/Bindings/MessagePortPrototype.h>
2021-09-19 22:12:31 +02:00
# include <LibWeb/DOM/EventDispatcher.h>
# include <LibWeb/HTML/EventNames.h>
# include <LibWeb/HTML/MessageEvent.h>
# include <LibWeb/HTML/MessagePort.h>
2023-12-18 17:24:31 -07:00
# include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
2024-10-17 08:46:48 -04:00
# include <LibWeb/HTML/StructuredSerializeOptions.h>
2023-12-20 13:47:01 -07:00
# include <LibWeb/HTML/WorkerGlobalScope.h>
2021-09-19 22:12:31 +02:00
namespace Web : : HTML {
2023-12-18 17:24:31 -07:00
constexpr u8 IPC_FILE_TAG = 0xA5 ;
2024-11-15 04:01:23 +13:00
GC_DEFINE_ALLOCATOR ( MessagePort ) ;
2023-11-19 19:47:52 +01:00
2024-11-15 04:01:23 +13:00
static HashTable < GC : : RawPtr < MessagePort > > & all_message_ports ( )
2024-10-17 07:59:04 -04:00
{
2024-11-15 04:01:23 +13:00
static HashTable < GC : : RawPtr < MessagePort > > ports ;
2024-10-17 07:59:04 -04:00
return ports ;
}
2024-11-15 04:01:23 +13:00
GC : : Ref < MessagePort > MessagePort : : create ( JS : : Realm & realm )
2021-09-19 22:12:31 +02:00
{
2024-11-14 05:50:17 +13:00
return realm . create < MessagePort > ( realm ) ;
2022-08-28 13:42:07 +02:00
}
2022-09-25 16:38:21 -06:00
MessagePort : : MessagePort ( JS : : Realm & realm )
: DOM : : EventTarget ( realm )
2022-08-28 13:42:07 +02:00
{
2024-10-17 07:59:04 -04:00
all_message_ports ( ) . set ( this ) ;
2021-09-19 22:12:31 +02:00
}
2025-01-01 01:20:37 +13:00
MessagePort : : ~ MessagePort ( ) = default ;
2021-09-19 22:12:31 +02:00
2024-10-17 07:59:04 -04:00
void MessagePort : : for_each_message_port ( Function < void ( MessagePort & ) > callback )
{
for ( auto port : all_message_ports ( ) )
callback ( * port ) ;
}
2023-08-07 08:41:28 +02:00
void MessagePort : : initialize ( JS : : Realm & realm )
2023-01-10 06:28:20 -05:00
{
2023-08-07 08:41:28 +02:00
Base : : initialize ( realm ) ;
2024-03-16 13:13:08 +01:00
WEB_SET_PROTOTYPE_FOR_INTERFACE ( MessagePort ) ;
2023-01-10 06:28:20 -05:00
}
2025-01-01 01:20:37 +13:00
void MessagePort : : finalize ( )
{
Base : : finalize ( ) ;
all_message_ports ( ) . remove ( this ) ;
disentangle ( ) ;
}
2022-08-28 13:42:07 +02:00
void MessagePort : : visit_edges ( Cell : : Visitor & visitor )
{
Base : : visit_edges ( visitor ) ;
2023-11-19 16:18:00 +13:00
visitor . visit ( m_remote_port ) ;
2024-10-16 19:51:05 -04:00
visitor . visit ( m_worker_event_target ) ;
2022-08-28 13:42:07 +02:00
}
2024-10-22 15:47:33 -06:00
bool MessagePort : : is_entangled ( ) const
{
return m_transport . has_value ( ) ;
}
2024-11-15 04:01:23 +13:00
void MessagePort : : set_worker_event_target ( GC : : Ref < DOM : : EventTarget > target )
2023-12-20 13:47:01 -07:00
{
m_worker_event_target = target ;
}
2023-12-07 15:52:08 -07:00
// https://html.spec.whatwg.org/multipage/web-messaging.html#message-ports:transfer-steps
2023-12-18 17:24:31 -07:00
WebIDL : : ExceptionOr < void > MessagePort : : transfer_steps ( HTML : : TransferDataHolder & data_holder )
2023-12-07 15:52:08 -07:00
{
// 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.
2024-10-22 15:47:33 -06:00
if constexpr ( IsSame < IPC : : Transport , IPC : : TransportSocket > ) {
auto fd = MUST ( m_transport - > release_underlying_transport_for_transfer ( ) ) ;
m_transport = { } ;
data_holder . fds . append ( IPC : : File : : adopt_fd ( fd ) ) ;
data_holder . data . append ( IPC_FILE_TAG ) ;
} else {
VERIFY ( false & & " Don't know how to transfer IPC::Transport type " ) ;
}
2023-12-07 15:52:08 -07:00
}
// 4. Otherwise, set dataHolder.[[RemotePort]] to null.
else {
2023-12-18 17:24:31 -07:00
data_holder . data . append ( 0 ) ;
2023-12-07 15:52:08 -07:00
}
return { } ;
}
2023-12-18 17:24:31 -07:00
WebIDL : : ExceptionOr < void > MessagePort : : transfer_receiving_steps ( HTML : : TransferDataHolder & data_holder )
2023-12-07 15:52:08 -07:00
{
// 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.
2023-12-18 17:24:31 -07:00
// 3. If dataHolder.[[RemotePort]] is not null, then entangle dataHolder.[[RemotePort]] and value.
2023-12-07 15:52:08 -07:00
// (This will disentangle dataHolder.[[RemotePort]] from the original port that was transferred.)
2023-12-18 17:24:31 -07:00
auto fd_tag = data_holder . data . take_first ( ) ;
if ( fd_tag = = IPC_FILE_TAG ) {
2024-10-22 15:47:33 -06:00
if constexpr ( IsSame < IPC : : Transport , IPC : : TransportSocket > ) {
auto fd = data_holder . fds . take_first ( ) ;
m_transport = IPC : : Transport ( MUST ( Core : : LocalSocket : : adopt_fd ( fd . take_fd ( ) ) ) ) ;
2024-11-15 04:01:23 +13:00
m_transport - > set_up_read_hook ( [ strong_this = GC : : make_root ( this ) ] ( ) {
2024-10-22 15:47:33 -06:00
strong_this - > read_from_transport ( ) ;
} ) ;
} else {
VERIFY ( false & & " Don't know how to receive IPC::Transport type " ) ;
}
2023-12-18 17:24:31 -07:00
} else if ( fd_tag ! = 0 ) {
dbgln ( " Unexpected byte {:x} in MessagePort transfer data " , fd_tag ) ;
VERIFY_NOT_REACHED ( ) ;
}
2023-12-07 15:52:08 -07:00
return { } ;
}
2021-09-19 22:12:31 +02:00
void MessagePort : : disentangle ( )
{
2023-12-19 15:28:56 -07:00
if ( m_remote_port )
m_remote_port - > m_remote_port = nullptr ;
2021-09-19 22:12:31 +02:00
m_remote_port = nullptr ;
2023-12-18 17:24:31 -07:00
2024-10-22 15:47:33 -06:00
m_transport = { } ;
2024-10-17 07:57:20 -04:00
m_worker_event_target = nullptr ;
2021-09-19 22:12:31 +02:00
}
// https://html.spec.whatwg.org/multipage/web-messaging.html#entangle
2022-02-17 13:31:09 +01:00
void MessagePort : : entangle_with ( MessagePort & remote_port )
2021-09-19 22:12:31 +02:00
{
2022-08-28 13:42:07 +02:00
if ( m_remote_port . ptr ( ) = = & remote_port )
2021-09-19 22:12:31 +02:00
return ;
// 1. If one of the ports is already entangled, then disentangle it and the port that it was entangled with.
if ( is_entangled ( ) )
disentangle ( ) ;
if ( remote_port . is_entangled ( ) )
remote_port . disentangle ( ) ;
// 2. Associate the two ports to be entangled, so that they form the two parts of a new channel.
// (There is no MessageChannel object that represents this channel.)
2022-08-28 13:42:07 +02:00
remote_port . m_remote_port = this ;
2021-09-19 22:12:31 +02:00
m_remote_port = & remote_port ;
2023-12-18 17:24:31 -07:00
2024-10-22 15:47:33 -06:00
// FIXME: Abstract such that we can entangle different transport types
2023-12-19 15:28:56 -07:00
auto create_paired_sockets = [ ] ( ) - > Array < NonnullOwnPtr < Core : : LocalSocket > , 2 > {
int fds [ 2 ] = { } ;
MUST ( Core : : System : : socketpair ( AF_LOCAL , SOCK_STREAM , 0 , fds ) ) ;
2024-04-05 00:07:32 +02:00
auto socket0 = MUST ( Core : : LocalSocket : : adopt_fd ( fds [ 0 ] ) ) ;
2023-12-19 15:28:56 -07:00
MUST ( socket0 - > set_blocking ( false ) ) ;
MUST ( socket0 - > set_close_on_exec ( true ) ) ;
2024-04-05 00:07:32 +02:00
auto socket1 = MUST ( Core : : LocalSocket : : adopt_fd ( fds [ 1 ] ) ) ;
2023-12-19 15:28:56 -07:00
MUST ( socket1 - > set_blocking ( false ) ) ;
MUST ( socket1 - > set_close_on_exec ( true ) ) ;
return Array { move ( socket0 ) , move ( socket1 ) } ;
} ;
auto sockets = create_paired_sockets ( ) ;
2024-10-22 15:47:33 -06:00
m_transport = IPC : : Transport ( move ( sockets [ 0 ] ) ) ;
m_remote_port - > m_transport = IPC : : Transport ( move ( sockets [ 1 ] ) ) ;
2023-12-19 15:28:56 -07:00
2024-11-15 04:01:23 +13:00
m_transport - > set_up_read_hook ( [ strong_this = GC : : make_root ( this ) ] ( ) {
2024-10-22 15:47:33 -06:00
strong_this - > read_from_transport ( ) ;
} ) ;
2023-12-19 15:28:56 -07:00
2024-11-15 04:01:23 +13:00
m_remote_port - > m_transport - > set_up_read_hook ( [ remote_port = GC : : make_root ( m_remote_port ) ] ( ) {
2024-10-22 15:47:33 -06:00
remote_port - > read_from_transport ( ) ;
} ) ;
2021-09-19 22:12:31 +02:00
}
2023-12-18 17:24:31 -07:00
// https://html.spec.whatwg.org/multipage/web-messaging.html#dom-messageport-postmessage-options
2024-11-15 04:01:23 +13:00
WebIDL : : ExceptionOr < void > MessagePort : : post_message ( JS : : Value message , Vector < GC : : Root < JS : : Object > > const & transfer )
2021-09-19 22:12:31 +02:00
{
// 1. Let targetPort be the port with which this MessagePort is entangled, if any; otherwise let it be null.
2024-11-15 04:01:23 +13:00
GC : : Ptr < MessagePort > target_port = m_remote_port ;
2021-09-19 22:12:31 +02:00
2023-12-18 17:24:31 -07:00
// 2. Let options be «[ "transfer" → transfer ]».
auto options = StructuredSerializeOptions { transfer } ;
// 3. Run the message port post message steps providing this, targetPort, message and options.
return message_port_post_message_steps ( target_port , message , options ) ;
}
// https://html.spec.whatwg.org/multipage/web-messaging.html#dom-messageport-postmessage
WebIDL : : ExceptionOr < void > MessagePort : : post_message ( JS : : Value message , StructuredSerializeOptions const & options )
{
// 1. Let targetPort be the port with which this MessagePort is entangled, if any; otherwise let it be null.
2024-11-15 04:01:23 +13:00
GC : : Ptr < MessagePort > target_port = m_remote_port ;
2021-09-19 22:12:31 +02:00
2023-12-18 17:24:31 -07:00
// 2. Run the message port post message steps providing targetPort, message and options.
return message_port_post_message_steps ( target_port , message , options ) ;
}
2021-09-19 22:12:31 +02:00
2023-12-18 17:24:31 -07:00
// https://html.spec.whatwg.org/multipage/web-messaging.html#message-port-post-message-steps
2024-11-15 04:01:23 +13:00
WebIDL : : ExceptionOr < void > MessagePort : : message_port_post_message_steps ( GC : : Ptr < MessagePort > target_port , JS : : Value message , StructuredSerializeOptions const & options )
2023-12-18 17:24:31 -07:00
{
auto & realm = this - > realm ( ) ;
auto & vm = this - > vm ( ) ;
2021-09-19 22:12:31 +02:00
2023-12-18 17:24:31 -07:00
// 1. Let transfer be options["transfer"].
auto const & transfer = options . transfer ;
2021-09-19 22:12:31 +02:00
2023-12-18 17:24:31 -07:00
// 2. If transfer contains this MessagePort, then throw a "DataCloneError" DOMException.
for ( auto const & handle : transfer ) {
if ( handle = = this )
2024-10-12 20:56:21 +02:00
return WebIDL : : DataCloneError : : create ( realm , " Cannot transfer a MessagePort to itself " _string ) ;
2023-12-18 17:24:31 -07:00
}
2021-09-19 22:12:31 +02:00
// 3. Let doomed be false.
bool doomed = false ;
2023-12-18 17:24:31 -07:00
// 4. If targetPort is not null and transfer contains targetPort, then set doomed to true and optionally report to a developer console that the target port was posted to itself, causing the communication channel to be lost.
if ( target_port ) {
for ( auto const & handle : transfer ) {
if ( handle = = target_port . ptr ( ) ) {
doomed = true ;
dbgln ( " FIXME: Report to a developer console that the target port was posted to itself, causing the communication channel to be lost " ) ;
}
}
}
2021-09-19 22:12:31 +02:00
2023-12-18 17:24:31 -07:00
// 5. Let serializeWithTransferResult be StructuredSerializeWithTransfer(message, transfer). Rethrow any exceptions.
auto serialize_with_transfer_result = TRY ( structured_serialize_with_transfer ( vm , message , transfer ) ) ;
2021-09-19 22:12:31 +02:00
// 6. If targetPort is null, or if doomed is true, then return.
2023-12-19 15:28:56 -07:00
// IMPLEMENTATION DEFINED: Actually check the socket here, not the target port.
// If there's no target message port in the same realm, we still want to send the message over IPC
2024-10-22 15:47:33 -06:00
if ( ! m_transport . has_value ( ) | | doomed ) {
2023-12-18 17:24:31 -07:00
return { } ;
2023-12-19 15:28:56 -07:00
}
2021-09-19 22:12:31 +02:00
2023-12-19 15:28:56 -07:00
// 7. Add a task that runs the following steps to the port message queue of targetPort:
post_port_message ( move ( serialize_with_transfer_result ) ) ;
return { } ;
}
2023-12-18 17:24:31 -07:00
2024-10-22 15:47:33 -06:00
ErrorOr < void > MessagePort : : send_message_on_transport ( SerializedTransferRecord const & serialize_with_transfer_result )
2023-12-19 15:28:56 -07:00
{
IPC : : MessageBuffer buffer ;
IPC : : Encoder encoder ( buffer ) ;
MUST ( encoder . encode ( serialize_with_transfer_result ) ) ;
2024-10-22 15:47:33 -06:00
TRY ( buffer . transfer_message ( * m_transport ) ) ;
2023-12-19 15:28:56 -07:00
return { } ;
}
void MessagePort : : post_port_message ( SerializedTransferRecord serialize_with_transfer_result )
{
2024-11-08 17:02:31 -07:00
if ( ! m_transport . has_value ( ) | | ! m_transport - > is_open ( ) )
return ;
if ( auto result = send_message_on_transport ( serialize_with_transfer_result ) ; result . is_error ( ) ) {
dbgln ( " Failed to post message: {} " , result . error ( ) ) ;
disentangle ( ) ;
}
2023-12-19 15:28:56 -07:00
}
2024-04-17 16:46:24 -06:00
ErrorOr < MessagePort : : ParseDecision > MessagePort : : parse_message ( )
2023-12-19 15:28:56 -07:00
{
2024-04-17 16:46:24 -06:00
static constexpr size_t HEADER_SIZE = sizeof ( u32 ) ;
auto num_bytes_ready = m_buffered_data . size ( ) ;
2023-12-19 15:28:56 -07:00
switch ( m_socket_state ) {
case SocketState : : Header : {
2024-04-17 16:46:24 -06:00
if ( num_bytes_ready < HEADER_SIZE )
return ParseDecision : : NotEnoughData ;
m_socket_incoming_message_size = ByteReader : : load32 ( m_buffered_data . data ( ) ) ;
// NOTE: We don't decrement the number of ready bytes because we want to remove the entire
// message + header from the buffer in one go on success
2023-12-19 15:28:56 -07:00
m_socket_state = SocketState : : Data ;
[[fallthrough]] ;
2024-04-17 16:46:24 -06:00
}
2023-12-19 15:28:56 -07:00
case SocketState : : Data : {
2024-07-30 15:04:32 +01:00
if ( num_bytes_ready < HEADER_SIZE + m_socket_incoming_message_size )
2024-04-17 16:46:24 -06:00
return ParseDecision : : NotEnoughData ;
2023-12-19 15:28:56 -07:00
2024-04-17 16:46:24 -06:00
auto payload = m_buffered_data . span ( ) . slice ( HEADER_SIZE , m_socket_incoming_message_size ) ;
2023-12-19 15:28:56 -07:00
2024-04-17 16:46:24 -06:00
FixedMemoryStream stream { payload , FixedMemoryStream : : Mode : : ReadOnly } ;
IPC : : Decoder decoder { stream , m_unprocessed_fds } ;
2023-12-19 15:28:56 -07:00
2024-04-17 16:46:24 -06:00
auto serialized_transfer_record = TRY ( decoder . decode < SerializedTransferRecord > ( ) ) ;
2023-12-19 15:28:56 -07:00
2024-01-05 14:50:01 -07:00
// Make sure to advance our state machine before dispatching the MessageEvent,
// as dispatching events can run arbitrary JS (and cause us to receive another message!)
2023-12-19 15:28:56 -07:00
m_socket_state = SocketState : : Header ;
2024-01-05 14:50:01 -07:00
2024-04-17 16:46:24 -06:00
m_buffered_data . remove ( 0 , HEADER_SIZE + m_socket_incoming_message_size ) ;
2024-11-08 17:02:31 -07:00
// Note: this is step 7 of message_port_post_message_steps:
// 7. Add a task that runs the following steps to the port message queue of targetPort:
2024-11-15 04:01:23 +13:00
queue_global_task ( Task : : Source : : PostedMessage , relevant_global_object ( * this ) , GC : : create_function ( heap ( ) , [ this , serialized_transfer_record = move ( serialized_transfer_record ) ] ( ) mutable {
2024-11-08 17:02:31 -07:00
this - > post_message_task_steps ( serialized_transfer_record ) ;
} ) ) ;
2024-04-17 16:46:24 -06:00
2023-12-19 15:28:56 -07:00
break ;
}
case SocketState : : Error :
2024-04-17 16:46:24 -06:00
return Error : : from_errno ( ENOMSG ) ;
}
return ParseDecision : : ParseNextMessage ;
}
2024-10-22 15:47:33 -06:00
void MessagePort : : read_from_transport ( )
2024-04-17 16:46:24 -06:00
{
2024-10-22 15:47:33 -06:00
auto & & [ bytes , fds ] = m_transport - > read_as_much_as_possible_without_blocking ( [ this ] {
2024-11-15 04:01:23 +13:00
queue_global_task ( Task : : Source : : PostedMessage , relevant_global_object ( * this ) , GC : : create_function ( heap ( ) , [ this ] {
2024-10-22 15:47:33 -06:00
this - > close ( ) ;
} ) ) ;
} ) ;
2024-04-17 16:46:24 -06:00
m_buffered_data . append ( bytes . data ( ) , bytes . size ( ) ) ;
for ( auto fd : fds )
m_unprocessed_fds . enqueue ( IPC : : File : : adopt_fd ( fd ) ) ;
while ( true ) {
auto parse_decision_or_error = parse_message ( ) ;
if ( parse_decision_or_error . is_error ( ) ) {
dbgln ( " MessagePort::read_from_socket(): Failed to parse message: {} " , parse_decision_or_error . error ( ) ) ;
return ;
}
if ( parse_decision_or_error . value ( ) = = ParseDecision : : NotEnoughData )
break ;
2023-12-19 15:28:56 -07:00
}
}
void MessagePort : : post_message_task_steps ( SerializedTransferRecord & serialize_with_transfer_result )
{
// 1. Let finalTargetPort be the MessagePort in whose port message queue the task now finds itself.
// NOTE: This can be different from targetPort, if targetPort itself was transferred and thus all its tasks moved along with it.
auto * final_target_port = this ;
2023-12-20 13:47:01 -07:00
// IMPLEMENTATION DEFINED:
// https://html.spec.whatwg.org/multipage/workers.html#dedicated-workers-and-the-worker-interface
// Worker objects act as if they had an implicit MessagePort associated with them.
// All messages received by that port must immediately be retargeted at the Worker object.
// We therefore set a special event target for those implicit ports on the Worker and the WorkerGlobalScope objects
EventTarget * message_event_target = final_target_port ;
if ( m_worker_event_target ! = nullptr ) {
message_event_target = m_worker_event_target ;
}
2023-12-19 15:28:56 -07:00
// 2. Let targetRealm be finalTargetPort's relevant realm.
auto & target_realm = relevant_realm ( * final_target_port ) ;
auto & target_vm = target_realm . vm ( ) ;
// 3. Let deserializeRecord be StructuredDeserializeWithTransfer(serializeWithTransferResult, targetRealm).
2024-10-24 20:39:18 +13:00
TemporaryExecutionContext context { relevant_realm ( * final_target_port ) } ;
2023-12-19 15:28:56 -07:00
auto deserialize_record_or_error = structured_deserialize_with_transfer ( target_vm , serialize_with_transfer_result ) ;
if ( deserialize_record_or_error . is_error ( ) ) {
// If this throws an exception, catch it, fire an event named messageerror at finalTargetPort, using MessageEvent, and then return.
auto exception = deserialize_record_or_error . release_error ( ) ;
2021-10-01 18:39:03 +03:00
MessageEventInit event_init { } ;
2023-12-20 13:47:01 -07:00
message_event_target - > dispatch_event ( MessageEvent : : create ( target_realm , HTML : : EventNames : : messageerror , event_init ) ) ;
2023-12-19 15:28:56 -07:00
return ;
}
auto deserialize_record = deserialize_record_or_error . release_value ( ) ;
2023-12-18 17:24:31 -07:00
2023-12-19 15:28:56 -07:00
// 4. Let messageClone be deserializeRecord.[[Deserialized]].
auto message_clone = deserialize_record . deserialized ;
// 5. Let newPorts be a new frozen array consisting of all MessagePort objects in deserializeRecord.[[TransferredValues]], if any, maintaining their relative order.
// FIXME: Use a FrozenArray
2024-11-15 04:01:23 +13:00
Vector < GC : : Root < MessagePort > > new_ports ;
2023-12-19 15:28:56 -07:00
for ( auto const & object : deserialize_record . transferred_values ) {
if ( is < HTML : : MessagePort > ( * object ) ) {
2024-05-15 20:58:02 +01:00
new_ports . append ( verify_cast < MessagePort > ( * object ) ) ;
2023-12-19 15:28:56 -07:00
}
}
// 6. Fire an event named message at finalTargetPort, using MessageEvent, with the data attribute initialized to messageClone and the ports attribute initialized to newPorts.
MessageEventInit event_init { } ;
event_init . data = message_clone ;
event_init . ports = move ( new_ports ) ;
2024-11-15 17:15:34 +00:00
auto event = MessageEvent : : create ( target_realm , HTML : : EventNames : : message , event_init ) ;
event - > set_is_trusted ( true ) ;
message_event_target - > dispatch_event ( event ) ;
2021-09-19 22:12:31 +02:00
}
2023-12-18 17:24:31 -07:00
// https://html.spec.whatwg.org/multipage/web-messaging.html#dom-messageport-start
2021-09-19 22:12:31 +02:00
void MessagePort : : start ( )
{
2024-03-12 10:53:21 +01:00
if ( ! is_entangled ( ) )
return ;
2024-10-22 15:47:33 -06:00
VERIFY ( m_transport . has_value ( ) ) ;
2023-12-18 17:24:31 -07:00
// TODO: The start() method steps are to enable this's port message queue, if it is not already enabled.
2021-09-19 22:12:31 +02:00
}
// https://html.spec.whatwg.org/multipage/web-messaging.html#dom-messageport-close
void MessagePort : : close ( )
{
// 1. Set this MessagePort object's [[Detached]] internal slot value to true.
2023-12-07 15:52:08 -07:00
set_detached ( true ) ;
2021-09-19 22:12:31 +02:00
// 2. If this MessagePort object is entangled, disentangle it.
if ( is_entangled ( ) )
disentangle ( ) ;
}
2024-12-15 01:17:08 +13:00
// https://html.spec.whatwg.org/multipage/web-messaging.html#handler-messageeventtarget-onmessageerror
void MessagePort : : set_onmessageerror ( GC : : Ptr < WebIDL : : CallbackType > value )
{
set_event_handler_attribute ( EventNames : : messageerror , value ) ;
}
// https://html.spec.whatwg.org/multipage/web-messaging.html#handler-messageeventtarget-onmessageerror
GC : : Ptr < WebIDL : : CallbackType > MessagePort : : onmessageerror ( )
{
return event_handler_attribute ( EventNames : : messageerror ) ;
}
// https://html.spec.whatwg.org/multipage/web-messaging.html#handler-messageeventtarget-onmessage
void MessagePort : : set_onmessage ( GC : : Ptr < WebIDL : : CallbackType > value )
{
set_event_handler_attribute ( EventNames : : message , value ) ;
}
// https://html.spec.whatwg.org/multipage/web-messaging.html#handler-messageeventtarget-onmessage
GC : : Ptr < WebIDL : : CallbackType > MessagePort : : onmessage ( )
{
return event_handler_attribute ( EventNames : : message ) ;
}
2021-09-19 22:12:31 +02:00
}