From ba1b26cdc2f5012e8c9ac705854f621a83eeda4c Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Thu, 17 Oct 2024 07:59:04 -0400 Subject: [PATCH] LibWeb: Disentangle associated MessagePorts when a document is destroyed --- Userland/Libraries/LibWeb/DOM/Document.cpp | 14 ++++++++++++-- Userland/Libraries/LibWeb/HTML/MessagePort.cpp | 14 ++++++++++++++ Userland/Libraries/LibWeb/HTML/MessagePort.h | 5 ++++- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp index f7c82f97ab4..5d4d0bb761e 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.cpp +++ b/Userland/Libraries/LibWeb/DOM/Document.cpp @@ -96,6 +96,7 @@ #include #include #include +#include #include #include #include @@ -3316,8 +3317,17 @@ void Document::destroy() // 3. Set document's salvageable state to false. m_salvageable = false; - // FIXME: 4. Let ports be the list of MessagePorts whose relevant global object's associated Document is document. - // FIXME: 5. For each port in ports, disentangle port. + // 4. Let ports be the list of MessagePorts whose relevant global object's associated Document is document. + // 5. For each port in ports, disentangle port. + HTML::MessagePort::for_each_message_port([&](HTML::MessagePort& port) { + auto& global = HTML::relevant_global_object(port); + if (!is(global)) + return; + + auto& window = static_cast(global); + if (&window.associated_document() == this) + port.disentangle(); + }); // 6. Run any unloading document cleanup steps for document that are defined by this specification and other applicable specifications. run_unloading_cleanup_steps(); diff --git a/Userland/Libraries/LibWeb/HTML/MessagePort.cpp b/Userland/Libraries/LibWeb/HTML/MessagePort.cpp index c4cc105b08a..283bb036e2c 100644 --- a/Userland/Libraries/LibWeb/HTML/MessagePort.cpp +++ b/Userland/Libraries/LibWeb/HTML/MessagePort.cpp @@ -29,6 +29,12 @@ constexpr u8 IPC_FILE_TAG = 0xA5; JS_DEFINE_ALLOCATOR(MessagePort); +static HashTable>& all_message_ports() +{ + static HashTable> ports; + return ports; +} + JS::NonnullGCPtr MessagePort::create(JS::Realm& realm) { return realm.heap().allocate(realm, realm); @@ -37,13 +43,21 @@ JS::NonnullGCPtr MessagePort::create(JS::Realm& realm) MessagePort::MessagePort(JS::Realm& realm) : DOM::EventTarget(realm) { + all_message_ports().set(this); } MessagePort::~MessagePort() { + all_message_ports().remove(this); disentangle(); } +void MessagePort::for_each_message_port(Function callback) +{ + for (auto port : all_message_ports()) + callback(*port); +} + void MessagePort::initialize(JS::Realm& realm) { Base::initialize(realm); diff --git a/Userland/Libraries/LibWeb/HTML/MessagePort.h b/Userland/Libraries/LibWeb/HTML/MessagePort.h index ebc5b0efa22..40c81b55695 100644 --- a/Userland/Libraries/LibWeb/HTML/MessagePort.h +++ b/Userland/Libraries/LibWeb/HTML/MessagePort.h @@ -30,11 +30,15 @@ class MessagePort final : public DOM::EventTarget public: [[nodiscard]] static JS::NonnullGCPtr create(JS::Realm&); + static void for_each_message_port(Function); + virtual ~MessagePort() override; // https://html.spec.whatwg.org/multipage/web-messaging.html#entangle void entangle_with(MessagePort&); + void disentangle(); + // https://html.spec.whatwg.org/multipage/web-messaging.html#dom-messageport-postmessage WebIDL::ExceptionOr post_message(JS::Value message, Vector> const& transfer); @@ -66,7 +70,6 @@ private: virtual void visit_edges(Cell::Visitor&) override; bool is_entangled() const { return static_cast(m_socket); } - void disentangle(); WebIDL::ExceptionOr message_port_post_message_steps(JS::GCPtr target_port, JS::Value message, StructuredSerializeOptions const& options); void post_message_task_steps(SerializedTransferRecord&);