diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index aaf6a6871f..47bb50b671 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -1185,7 +1185,6 @@ set(SOURCES WebXR/XRSessionEvent.cpp WebXR/XRSystem.cpp WebXR/XRWebGLLayer.cpp - Worker/WebWorkerClient.cpp XHR/EventNames.cpp XHR/FormData.cpp XHR/FormDataIterator.cpp diff --git a/Libraries/LibWeb/Forward.h b/Libraries/LibWeb/Forward.h index 992d0c15d6..fd82ed1eda 100644 --- a/Libraries/LibWeb/Forward.h +++ b/Libraries/LibWeb/Forward.h @@ -850,7 +850,6 @@ class UserActivation; class ValidityState; class VideoTrack; class VideoTrackList; -class WebWorkerClient; class Window; class WindowEnvironmentSettingsObject; class WindowProxy; diff --git a/Libraries/LibWeb/HTML/BroadcastChannel.cpp b/Libraries/LibWeb/HTML/BroadcastChannel.cpp index c92b0c556d..826222f21c 100644 --- a/Libraries/LibWeb/HTML/BroadcastChannel.cpp +++ b/Libraries/LibWeb/HTML/BroadcastChannel.cpp @@ -24,7 +24,6 @@ #include #include #include -#include namespace Web::HTML { @@ -153,15 +152,8 @@ WebIDL::ExceptionOr BroadcastChannel::post_message(JS::Value message) // Steps 6-9. deliver_message_locally(message_to_send); - // NB: Other WebContent processes receive this via the browser-process IPC fanout. - // Child worker processes are not part of that routing path, so forward to them directly here. Bindings::principal_host_defined_page(realm()).client().page_did_post_broadcast_channel_message(message_to_send); - WebWorkerClient::for_each_client([&](WebWorkerClient& client) { - client.async_broadcast_channel_message(message_to_send); - return IterationDecision::Continue; - }); - return {}; } diff --git a/Libraries/LibWeb/Worker/WebWorkerClient.cpp b/Libraries/LibWeb/Worker/WebWorkerClient.cpp deleted file mode 100644 index 49f142e7f3..0000000000 --- a/Libraries/LibWeb/Worker/WebWorkerClient.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2023, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -namespace Web::HTML { - -HashTable WebWorkerClient::s_all_clients; - -void WebWorkerClient::die() -{ - if (on_worker_died) - on_worker_died(); -} - -void WebWorkerClient::did_close_worker() -{ - if (on_worker_close) - on_worker_close(); -} - -void WebWorkerClient::did_finish_loading_worker_script(bool worker_is_secure_context) -{ - if (on_worker_script_load_success) - on_worker_script_load_success(worker_is_secure_context); -} - -void WebWorkerClient::did_fail_loading_worker_script() -{ - if (on_worker_script_load_failure) - on_worker_script_load_failure(); -} - -void WebWorkerClient::did_report_worker_exception(String message, String filename, u32 lineno, u32 colno) -{ - if (on_worker_exception) - on_worker_exception(move(message), move(filename), lineno, colno); -} - -Messages::WebWorkerClient::DidRequestCookieResponse WebWorkerClient::did_request_cookie(URL::URL url, HTTP::Cookie::Source source) -{ - if (on_request_cookie) - return on_request_cookie(url, source); - return HTTP::Cookie::VersionedCookie {}; -} - -void WebWorkerClient::did_request_file(ByteString path, i32 request_id) -{ - if (on_request_file) - on_request_file(move(path), request_id); -} - -void WebWorkerClient::did_post_broadcast_channel_message(Web::HTML::BroadcastChannelMessage message) -{ - if (on_post_broadcast_channel_message) - on_post_broadcast_channel_message(move(message)); -} - -Messages::WebWorkerClient::StartWorkerAgentResponse WebWorkerClient::start_worker_agent(Web::HTML::WorkerAgentStartRequest request) -{ - if (on_start_worker_agent) - return on_start_worker_agent(move(request)); - return { 0 }; -} - -void WebWorkerClient::close_worker_agent(Web::HTML::WorkerAgentId agent_id, Web::HTML::WorkerAgentOwnerToken owner_token) -{ - if (on_close_worker_agent) - on_close_worker_agent(agent_id, owner_token); -} - -WebWorkerClient::WebWorkerClient(NonnullOwnPtr transport) - : IPC::ConnectionToServer(*this, move(transport)) -{ - s_all_clients.set(this); -} - -WebWorkerClient::~WebWorkerClient() -{ - s_all_clients.remove(this); -} - -} diff --git a/Libraries/LibWebView/CMakeLists.txt b/Libraries/LibWebView/CMakeLists.txt index 10b08d23d2..535639c955 100644 --- a/Libraries/LibWebView/CMakeLists.txt +++ b/Libraries/LibWebView/CMakeLists.txt @@ -28,6 +28,7 @@ set(SOURCES Utilities.cpp ViewImplementation.cpp WebContentClient.cpp + WebWorkerClient.cpp WorkerProcessManager.cpp WebUI.cpp WebUI/BookmarksUI.cpp diff --git a/Libraries/LibWebView/Forward.h b/Libraries/LibWebView/Forward.h index 50da5a6d84..86587663a3 100644 --- a/Libraries/LibWebView/Forward.h +++ b/Libraries/LibWebView/Forward.h @@ -25,6 +25,7 @@ class ProcessManager; class Settings; class ViewImplementation; class WebContentClient; +class WebWorkerClient; class WebUI; struct Attribute; diff --git a/Libraries/LibWebView/HelperProcess.cpp b/Libraries/LibWebView/HelperProcess.cpp index e66c099926..92922bc2b9 100644 --- a/Libraries/LibWebView/HelperProcess.cpp +++ b/Libraries/LibWebView/HelperProcess.cpp @@ -56,7 +56,7 @@ static ErrorOr> launch_server_process( if constexpr (requires { client->set_pid(pid_t {}); }) client->set_pid(process.pid()); - if constexpr (requires { client->transport().set_peer_pid(0); } && !IsSame) { + if constexpr (requires { client->transport().set_peer_pid(0); } && !IsSame) { auto response = client->template send_sync(Core::System::getpid()); client->transport().set_peer_pid(response->peer_pid()); } @@ -185,7 +185,7 @@ ErrorOr> launch_compositor_process() return launch_server_process("Compositor"sv, move(arguments)); } -ErrorOr> launch_web_worker_process(Web::Bindings::AgentType type) +ErrorOr> launch_web_worker_process(Web::Bindings::AgentType type, Web::HTML::WorkerAgentId agent_id) { auto const& web_content_options = WebView::Application::web_content_options(); @@ -218,7 +218,7 @@ ErrorOr> launch_web_worker_process(Web arguments.append(server.value()); } - return launch_server_process("WebWorker"sv, move(arguments)); + return launch_server_process("WebWorker"sv, move(arguments), agent_id); } ErrorOr> launch_request_server_process() diff --git a/Libraries/LibWebView/HelperProcess.h b/Libraries/LibWebView/HelperProcess.h index 2b349683d4..2ef4971a76 100644 --- a/Libraries/LibWebView/HelperProcess.h +++ b/Libraries/LibWebView/HelperProcess.h @@ -12,10 +12,10 @@ #include #include #include -#include #include #include #include +#include namespace WebView { @@ -25,7 +25,7 @@ WEBVIEW_API ErrorOr> launch_spare_web_c WEBVIEW_API ErrorOr> launch_image_decoder_process(); WEBVIEW_API ErrorOr> launch_compositor_process(); -WEBVIEW_API ErrorOr> launch_web_worker_process(Web::Bindings::AgentType); +WEBVIEW_API ErrorOr> launch_web_worker_process(Web::Bindings::AgentType, Web::HTML::WorkerAgentId); WEBVIEW_API ErrorOr> launch_request_server_process(); WEBVIEW_API ErrorOr connect_new_request_server_client(); diff --git a/Libraries/LibWebView/WebWorkerClient.cpp b/Libraries/LibWebView/WebWorkerClient.cpp new file mode 100644 index 0000000000..6a9978c1bd --- /dev/null +++ b/Libraries/LibWebView/WebWorkerClient.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include + +namespace WebView { + +void WebWorkerClient::die() +{ + WorkerProcessManager::the().worker_did_die(m_agent_id); + + // Otherwise nested workers we own would outlive us, in violation of the HTML spec. + WorkerProcessManager::the().remove_web_worker_owner(*this); +} + +void WebWorkerClient::did_close_worker() +{ + WorkerProcessManager::the().worker_did_close(m_agent_id); +} + +void WebWorkerClient::did_finish_loading_worker_script(bool worker_is_secure_context) +{ + WorkerProcessManager::the().worker_did_finish_loading_script(m_agent_id, worker_is_secure_context); +} + +void WebWorkerClient::did_fail_loading_worker_script() +{ + WorkerProcessManager::the().worker_did_fail_loading_script(m_agent_id); +} + +void WebWorkerClient::did_report_worker_exception(String message, String filename, u32 lineno, u32 colno) +{ + WorkerProcessManager::the().worker_did_report_exception(m_agent_id, move(message), move(filename), lineno, colno); +} + +Messages::WebWorkerClient::DidRequestCookieResponse WebWorkerClient::did_request_cookie(URL::URL url, HTTP::Cookie::Source source) +{ + HTTP::Cookie::VersionedCookie cookie; + cookie.cookie = Application::cookie_jar().get_cookie(url, source); + return cookie; +} + +void WebWorkerClient::did_request_file(ByteString path, i32 request_id) +{ + WorkerProcessManager::the().worker_did_request_file(m_agent_id, move(path), request_id); +} + +void WebWorkerClient::did_post_broadcast_channel_message(Web::HTML::BroadcastChannelMessage message) +{ + WorkerProcessManager::the().worker_did_post_broadcast_channel_message(m_agent_id, move(message)); +} + +Messages::WebWorkerClient::StartWorkerAgentResponse WebWorkerClient::start_worker_agent(Web::HTML::WorkerAgentStartRequest request) +{ + return WorkerProcessManager::the().start_worker_agent(*this, move(request)); +} + +void WebWorkerClient::close_worker_agent(Web::HTML::WorkerAgentId agent_id, Web::HTML::WorkerAgentOwnerToken owner_token) +{ + WorkerProcessManager::the().close_worker_agent(*this, agent_id, owner_token); +} + +WebWorkerClient::WebWorkerClient(NonnullOwnPtr transport, Web::HTML::WorkerAgentId agent_id) + : IPC::ConnectionToServer(*this, move(transport)) + , m_agent_id(agent_id) +{ +} + +WebWorkerClient::~WebWorkerClient() = default; + +} diff --git a/Libraries/LibWeb/Worker/WebWorkerClient.h b/Libraries/LibWebView/WebWorkerClient.h similarity index 57% rename from Libraries/LibWeb/Worker/WebWorkerClient.h rename to Libraries/LibWebView/WebWorkerClient.h index 1b100df0f1..b30f127b97 100644 --- a/Libraries/LibWeb/Worker/WebWorkerClient.h +++ b/Libraries/LibWebView/WebWorkerClient.h @@ -7,30 +7,25 @@ #pragma once #include -#include -#include #include #include #include #include -#include #include #include #include #include +#include -namespace Web::HTML { +namespace WebView { -class WEB_API WebWorkerClient final +class WEBVIEW_API WebWorkerClient final : public IPC::ConnectionToServer , public WebWorkerClientEndpoint { C_OBJECT_ABSTRACT(WebWorkerClient); public: - template - static void for_each_client(Callback callback); - - explicit WebWorkerClient(NonnullOwnPtr); + explicit WebWorkerClient(NonnullOwnPtr, Web::HTML::WorkerAgentId agent_id); ~WebWorkerClient(); pid_t pid() const { return m_pid; } @@ -46,31 +41,11 @@ public: virtual Messages::WebWorkerClient::StartWorkerAgentResponse start_worker_agent(Web::HTML::WorkerAgentStartRequest request) override; virtual void close_worker_agent(Web::HTML::WorkerAgentId, Web::HTML::WorkerAgentOwnerToken) override; - Function on_worker_close; - Function on_worker_died; - Function on_worker_script_load_success; - Function on_worker_script_load_failure; - Function on_worker_exception; - Function on_request_cookie; - Function on_request_file; - Function on_post_broadcast_channel_message; - Function on_start_worker_agent; - Function on_close_worker_agent; - private: virtual void die() override; pid_t m_pid { -1 }; - static HashTable s_all_clients; + Web::HTML::WorkerAgentId m_agent_id { 0 }; }; -template -void WebWorkerClient::for_each_client(Callback callback) -{ - for (auto* client : s_all_clients) { - if (callback(*client) == IterationDecision::Break) - return; - } -} - } diff --git a/Libraries/LibWebView/WorkerProcessManager.cpp b/Libraries/LibWebView/WorkerProcessManager.cpp index a3b12d105b..d0d9daba79 100644 --- a/Libraries/LibWebView/WorkerProcessManager.cpp +++ b/Libraries/LibWebView/WorkerProcessManager.cpp @@ -7,11 +7,9 @@ #include #include #include -#include -#include -#include #include #include +#include #include namespace WebView { @@ -34,7 +32,7 @@ Web::HTML::WorkerAgentId WorkerProcessManager::start_worker_agent(WebContentClie return start_worker_agent(move(abstract_owner), move(request)); } -Web::HTML::WorkerAgentId WorkerProcessManager::start_worker_agent(Web::HTML::WebWorkerClient& owner, Web::HTML::WorkerAgentStartRequest request) +Web::HTML::WorkerAgentId WorkerProcessManager::start_worker_agent(WebWorkerClient& owner, Web::HTML::WorkerAgentStartRequest request) { auto abstract_owner = Owner { .client = WebWorkerOwner { @@ -113,40 +111,7 @@ Web::HTML::WorkerAgentId WorkerProcessManager::start_worker_agent(Owner owner, W // AD-HOC: For DedicatedWorker there is no shared worker manager step; we always launch a fresh // worker process here. auto agent_id = ++m_next_agent_id; - auto client = MUST(launch_web_worker_process(request.agent_type)); - - client->on_worker_close = [this, agent_id] { - worker_did_close(agent_id); - }; - client->on_worker_script_load_success = [this, agent_id](bool worker_is_secure_context) { - worker_did_finish_loading_script(agent_id, worker_is_secure_context); - }; - client->on_worker_script_load_failure = [this, agent_id] { - worker_did_fail_loading_script(agent_id); - }; - client->on_worker_exception = [this, agent_id](String message, String filename, u32 lineno, u32 colno) { - worker_did_report_exception(agent_id, move(message), move(filename), lineno, colno); - }; - client->on_worker_died = [this, agent_id] { - worker_did_die(agent_id); - }; - client->on_request_cookie = [](URL::URL const& url, HTTP::Cookie::Source source) { - HTTP::Cookie::VersionedCookie cookie; - cookie.cookie = Application::cookie_jar().get_cookie(url, source); - return cookie; - }; - client->on_request_file = [this, agent_id](ByteString path, i32 request_id) { - worker_did_request_file(agent_id, move(path), request_id); - }; - client->on_post_broadcast_channel_message = [this, agent_id](Web::HTML::BroadcastChannelMessage message) { - worker_did_post_broadcast_channel_message(agent_id, move(message)); - }; - client->on_start_worker_agent = [this, client = client.ptr()](Web::HTML::WorkerAgentStartRequest request) { - return start_worker_agent(*client, move(request)); - }; - client->on_close_worker_agent = [this, client = client.ptr()](Web::HTML::WorkerAgentId agent_id, Web::HTML::WorkerAgentOwnerToken owner_token) { - close_worker_agent(*client, agent_id, owner_token); - }; + auto client = MUST(launch_web_worker_process(request.agent_type, agent_id)); auto request_server_handle = MUST(connect_new_request_server_client()); auto image_decoder_handle = MUST(connect_new_image_decoder_client()); @@ -196,7 +161,7 @@ void WorkerProcessManager::close_worker_agent(WebContentClient& client, Web::HTM remove_owner(agent_id, identity); } -void WorkerProcessManager::close_worker_agent(Web::HTML::WebWorkerClient& client, Web::HTML::WorkerAgentId agent_id, Web::HTML::WorkerAgentOwnerToken owner_token) +void WorkerProcessManager::close_worker_agent(WebWorkerClient& client, Web::HTML::WorkerAgentId agent_id, Web::HTML::WorkerAgentOwnerToken owner_token) { Owner identity { .client = WebWorkerOwner { .client = client }, @@ -222,6 +187,23 @@ void WorkerProcessManager::remove_web_content_owner(WebContentClient& client) remove_agent(agent_id); } +void WorkerProcessManager::remove_web_worker_owner(WebWorkerClient& client) +{ + Vector agents_to_close; + for (auto& entry : m_agents) { + auto& agent = entry.value; + agent.owners.remove_all_matching([&](Owner const& owner) { + auto const* web_worker_owner = owner.client.get_pointer(); + return web_worker_owner && web_worker_owner->client.ptr() == &client; + }); + if (agent.owners.is_empty()) + agents_to_close.append(agent.id); + } + + for (auto agent_id : agents_to_close) + remove_agent(agent_id); +} + void WorkerProcessManager::broadcast_channel_message_from_web_content(Web::HTML::BroadcastChannelMessage const& message) { for (auto& entry : m_agents) { diff --git a/Libraries/LibWebView/WorkerProcessManager.h b/Libraries/LibWebView/WorkerProcessManager.h index 8115b46abd..1da7b46735 100644 --- a/Libraries/LibWebView/WorkerProcessManager.h +++ b/Libraries/LibWebView/WorkerProcessManager.h @@ -16,12 +16,6 @@ #include #include -namespace Web::HTML { - -class WebWorkerClient; - -} - namespace WebView { class WorkerProcessManager { @@ -37,15 +31,18 @@ public: }; Web::HTML::WorkerAgentId start_worker_agent(WebContentClient&, u64 page_id, Web::HTML::WorkerAgentStartRequest); - Web::HTML::WorkerAgentId start_worker_agent(Web::HTML::WebWorkerClient&, Web::HTML::WorkerAgentStartRequest); + Web::HTML::WorkerAgentId start_worker_agent(WebWorkerClient&, Web::HTML::WorkerAgentStartRequest); void close_worker_agent(WebContentClient&, Web::HTML::WorkerAgentId, Web::HTML::WorkerAgentOwnerToken); - void close_worker_agent(Web::HTML::WebWorkerClient&, Web::HTML::WorkerAgentId, Web::HTML::WorkerAgentOwnerToken); + void close_worker_agent(WebWorkerClient&, Web::HTML::WorkerAgentId, Web::HTML::WorkerAgentOwnerToken); void remove_web_content_owner(WebContentClient&); + void remove_web_worker_owner(WebWorkerClient&); void broadcast_channel_message_from_web_content(Web::HTML::BroadcastChannelMessage const&); private: + friend class WebWorkerClient; + WorkerProcessManager() = default; struct WebContentOwner { @@ -54,7 +51,7 @@ private: }; struct WebWorkerOwner { - NonnullRefPtr client; + NonnullRefPtr client; }; struct Owner { @@ -82,7 +79,7 @@ private: struct WorkerAgent { Web::HTML::WorkerAgentId id { 0 }; - NonnullRefPtr client; + NonnullRefPtr client; Web::Bindings::AgentType agent_type { Web::Bindings::AgentType::DedicatedWorker }; Web::Bindings::WorkerType worker_type { Web::Bindings::WorkerType::Classic }; Web::Bindings::RequestCredentials credentials { Web::Bindings::RequestCredentials::SameOrigin };