diff --git a/Libraries/LibWeb/HTML/SharedWorkerGlobalScope.h b/Libraries/LibWeb/HTML/SharedWorkerGlobalScope.h index a02fb32d9d4..a1516773590 100644 --- a/Libraries/LibWeb/HTML/SharedWorkerGlobalScope.h +++ b/Libraries/LibWeb/HTML/SharedWorkerGlobalScope.h @@ -25,6 +25,15 @@ class SharedWorkerGlobalScope public: virtual ~SharedWorkerGlobalScope() override; + void set_constructor_origin(URL::Origin origin) { m_constructor_origin = move(origin); } + URL::Origin const& constructor_origin() const { return m_constructor_origin; } + + void set_constructor_url(URL::URL url) { m_constructor_url = move(url); } + URL::URL const& constructor_url() const { return m_constructor_url; } + + Fetch::Infrastructure::Request::CredentialsMode credentials() const { return m_credentials; } + void set_credentials(Fetch::Infrastructure::Request::CredentialsMode credentials) { m_credentials = credentials; } + void close(); #define __ENUMERATE(attribute_name, event_name) \ @@ -38,6 +47,10 @@ private: virtual void initialize_web_interfaces_impl() override; virtual void finalize() override; + + URL::Origin m_constructor_origin; + URL::URL m_constructor_url; + Fetch::Infrastructure::Request::CredentialsMode m_credentials; }; HashTable>& all_shared_worker_global_scopes(); diff --git a/Libraries/LibWeb/HTML/Worker.cpp b/Libraries/LibWeb/HTML/Worker.cpp index b81cbbdfbd7..2ae3ef58dd4 100644 --- a/Libraries/LibWeb/HTML/Worker.cpp +++ b/Libraries/LibWeb/HTML/Worker.cpp @@ -93,7 +93,7 @@ WebIDL::ExceptionOr> Worker::create(String const& script_url, Wo void run_a_worker(Variant, GC::Ref> worker, URL::URL& url, EnvironmentSettingsObject& outside_settings, GC::Ptr port, WorkerOptions const& options) { // 1. Let is shared be true if worker is a SharedWorker object, and false otherwise. - // FIXME: SharedWorker support + Bindings::AgentType agent_type = worker.has>() ? Bindings::AgentType::SharedWorker : Bindings::AgentType::DedicatedWorker; // 2. Let owner be the relevant owner to add given outside settings. // FIXME: Support WorkerGlobalScope options @@ -111,7 +111,7 @@ void run_a_worker(Variant, GC::Ref> worker, URL::U // and is shared. Run the rest of these steps in that agent. // Note: This spawns a new process to act as the 'agent' for the worker. - auto agent = outside_settings.realm().create(url, options, port, outside_settings); + auto agent = outside_settings.realm().create(url, options, port, outside_settings, agent_type); worker.visit([&](auto worker) { worker->set_agent(agent); }); } diff --git a/Libraries/LibWeb/HTML/WorkerAgentParent.cpp b/Libraries/LibWeb/HTML/WorkerAgentParent.cpp index 3e0b9515b2b..3f8266f189c 100644 --- a/Libraries/LibWeb/HTML/WorkerAgentParent.cpp +++ b/Libraries/LibWeb/HTML/WorkerAgentParent.cpp @@ -14,8 +14,9 @@ namespace Web::HTML { GC_DEFINE_ALLOCATOR(WorkerAgentParent); -WorkerAgentParent::WorkerAgentParent(URL::URL url, WorkerOptions const& options, GC::Ptr outside_port, GC::Ref outside_settings) +WorkerAgentParent::WorkerAgentParent(URL::URL url, WorkerOptions const& options, GC::Ptr outside_port, GC::Ref outside_settings, Bindings::AgentType agent_type) : m_worker_options(options) + , m_agent_type(agent_type) , m_url(move(url)) , m_outside_port(outside_port) , m_outside_settings(outside_settings) @@ -34,7 +35,7 @@ void WorkerAgentParent::initialize(JS::Realm& realm) // NOTE: This blocking IPC call may launch another process. // If spinning the event loop for this can cause other javascript to execute, we're in trouble. - auto worker_socket_file = Bindings::principal_host_defined_page(realm).client().request_worker_agent(Bindings::AgentType::DedicatedWorker); + auto worker_socket_file = Bindings::principal_host_defined_page(realm).client().request_worker_agent(m_agent_type); auto worker_socket = MUST(Core::LocalSocket::adopt_fd(worker_socket_file.take_fd())); MUST(worker_socket->set_blocking(true)); @@ -44,7 +45,7 @@ void WorkerAgentParent::initialize(JS::Realm& realm) m_worker_ipc = make_ref_counted(move(transport)); - m_worker_ipc->async_start_dedicated_worker(m_url, m_worker_options.type, m_worker_options.credentials, m_worker_options.name, move(data_holder), m_outside_settings->serialize()); + m_worker_ipc->async_start_worker(m_url, m_worker_options.type, m_worker_options.credentials, m_worker_options.name, move(data_holder), m_outside_settings->serialize(), m_agent_type); } void WorkerAgentParent::visit_edges(Cell::Visitor& visitor) diff --git a/Libraries/LibWeb/HTML/WorkerAgentParent.h b/Libraries/LibWeb/HTML/WorkerAgentParent.h index 85967576a62..693bc7e12a4 100644 --- a/Libraries/LibWeb/HTML/WorkerAgentParent.h +++ b/Libraries/LibWeb/HTML/WorkerAgentParent.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -25,12 +26,13 @@ class WorkerAgentParent : public JS::Cell { GC_DECLARE_ALLOCATOR(WorkerAgentParent); protected: - WorkerAgentParent(URL::URL url, WorkerOptions const& options, GC::Ptr outside_port, GC::Ref outside_settings); + WorkerAgentParent(URL::URL url, WorkerOptions const& options, GC::Ptr outside_port, GC::Ref outside_settings, Bindings::AgentType); virtual void initialize(JS::Realm&) override; virtual void visit_edges(Cell::Visitor&) override; private: WorkerOptions m_worker_options; + Bindings::AgentType m_agent_type { Bindings::AgentType::DedicatedWorker }; URL::URL m_url; GC::Ptr m_message_port; diff --git a/Libraries/LibWeb/Worker/WebWorkerServer.ipc b/Libraries/LibWeb/Worker/WebWorkerServer.ipc index 240e469ab69..6a0ebe98e88 100644 --- a/Libraries/LibWeb/Worker/WebWorkerServer.ipc +++ b/Libraries/LibWeb/Worker/WebWorkerServer.ipc @@ -1,12 +1,19 @@ #include #include +#include +#include #include #include -#include endpoint WebWorkerServer { - start_dedicated_worker(URL::URL url, Web::Bindings::WorkerType type, Web::Bindings::RequestCredentials credentials, String name, Web::HTML::TransferDataHolder message_port, Web::HTML::SerializedEnvironmentSettingsObject outside_settings) =| + start_worker(URL::URL url, + Web::Bindings::WorkerType type, + Web::Bindings::RequestCredentials credentials, + String name, + Web::HTML::TransferDataHolder message_port, + Web::HTML::SerializedEnvironmentSettingsObject outside_settings, + Web::Bindings::AgentType agent_type) =| close_worker() =| diff --git a/Services/WebWorker/CMakeLists.txt b/Services/WebWorker/CMakeLists.txt index 89f2c58ae07..c8473be708f 100644 --- a/Services/WebWorker/CMakeLists.txt +++ b/Services/WebWorker/CMakeLists.txt @@ -1,7 +1,7 @@ set(WEBWORKER_SOURCES ConnectionFromClient.cpp - DedicatedWorkerHost.cpp PageHost.cpp + WorkerHost.cpp ) # FIXME: Add Android service diff --git a/Services/WebWorker/ConnectionFromClient.cpp b/Services/WebWorker/ConnectionFromClient.cpp index dd6b363c36b..c560db81b53 100644 --- a/Services/WebWorker/ConnectionFromClient.cpp +++ b/Services/WebWorker/ConnectionFromClient.cpp @@ -6,8 +6,8 @@ #include #include -#include #include +#include namespace WebWorker { @@ -63,10 +63,16 @@ Web::Page const& ConnectionFromClient::page() const return m_page_host->page(); } -void ConnectionFromClient::start_dedicated_worker(URL::URL url, Web::Bindings::WorkerType type, Web::Bindings::RequestCredentials, String name, Web::HTML::TransferDataHolder implicit_port, Web::HTML::SerializedEnvironmentSettingsObject outside_settings) +void ConnectionFromClient::start_worker(URL::URL url, Web::Bindings::WorkerType type, Web::Bindings::RequestCredentials credentials, String name, Web::HTML::TransferDataHolder implicit_port, Web::HTML::SerializedEnvironmentSettingsObject outside_settings, Web::Bindings::AgentType agent_type) { - m_worker_host = make_ref_counted(move(url), type, move(name)); - m_worker_host->run(page(), move(implicit_port), outside_settings); + m_worker_host = make_ref_counted(move(url), type, move(name)); + + bool const is_shared = agent_type == Web::Bindings::AgentType::SharedWorker; + VERIFY(is_shared || agent_type == Web::Bindings::AgentType::DedicatedWorker); + + // FIXME: Add an assertion that the agent_type passed here is the same that was passed at process creation to initialize_main_thread_vm() + + m_worker_host->run(page(), move(implicit_port), outside_settings, credentials, is_shared); } void ConnectionFromClient::handle_file_return(i32 error, Optional file, i32 request_id) diff --git a/Services/WebWorker/ConnectionFromClient.h b/Services/WebWorker/ConnectionFromClient.h index 65b8b8470f1..e86dd89b2c5 100644 --- a/Services/WebWorker/ConnectionFromClient.h +++ b/Services/WebWorker/ConnectionFromClient.h @@ -41,7 +41,7 @@ private: Web::Page& page(); Web::Page const& page() const; - virtual void start_dedicated_worker(URL::URL url, Web::Bindings::WorkerType type, Web::Bindings::RequestCredentials credentials, String name, Web::HTML::TransferDataHolder, Web::HTML::SerializedEnvironmentSettingsObject) override; + virtual void start_worker(URL::URL url, Web::Bindings::WorkerType type, Web::Bindings::RequestCredentials credentials, String name, Web::HTML::TransferDataHolder, Web::HTML::SerializedEnvironmentSettingsObject, Web::Bindings::AgentType) override; virtual void handle_file_return(i32 error, Optional file, i32 request_id) override; GC::Root m_page_host; @@ -51,7 +51,7 @@ private: HashMap m_requested_files {}; int last_id { 0 }; - RefPtr m_worker_host; + RefPtr m_worker_host; }; } diff --git a/Services/WebWorker/Forward.h b/Services/WebWorker/Forward.h index e3480520807..5992e2605f5 100644 --- a/Services/WebWorker/Forward.h +++ b/Services/WebWorker/Forward.h @@ -9,7 +9,7 @@ namespace WebWorker { class ConnectionFromClient; -class DedicatedWorkerHost; class PageHost; +class WorkerHost; } diff --git a/Services/WebWorker/DedicatedWorkerHost.cpp b/Services/WebWorker/WorkerHost.cpp similarity index 83% rename from Services/WebWorker/DedicatedWorkerHost.cpp rename to Services/WebWorker/WorkerHost.cpp index 423b11353cf..8031ca5e568 100644 --- a/Services/WebWorker/DedicatedWorkerHost.cpp +++ b/Services/WebWorker/WorkerHost.cpp @@ -6,49 +6,49 @@ #include #include +#include #include #include #include +#include #include #include #include #include +#include #include +#include #include #include #include #include -#include +#include namespace WebWorker { -DedicatedWorkerHost::DedicatedWorkerHost(URL::URL url, Web::Bindings::WorkerType type, String name) +WorkerHost::WorkerHost(URL::URL url, Web::Bindings::WorkerType type, String name) : m_url(move(url)) , m_type(type) , m_name(move(name)) { } -DedicatedWorkerHost::~DedicatedWorkerHost() = default; +WorkerHost::~WorkerHost() = default; // https://html.spec.whatwg.org/multipage/workers.html#run-a-worker -// FIXME: Extract out into a helper for both shared and dedicated workers -void DedicatedWorkerHost::run(GC::Ref page, Web::HTML::TransferDataHolder message_port_data, Web::HTML::SerializedEnvironmentSettingsObject const& outside_settings_snapshot) +void WorkerHost::run(GC::Ref page, Web::HTML::TransferDataHolder message_port_data, Web::HTML::SerializedEnvironmentSettingsObject const& outside_settings_snapshot, Web::Bindings::RequestCredentials credentials, bool is_shared) { - bool const is_shared = false; - // 3. Let unsafeWorkerCreationTime be the unsafe shared current time. auto unsafe_worker_creation_time = Web::HighResolutionTime::unsafe_shared_current_time(); // 7. Let realm execution context be the result of creating a new JavaScript realm given agent and the following customizations: auto realm_execution_context = Web::Bindings::create_a_new_javascript_realm( Web::Bindings::main_thread_vm(), - [page](JS::Realm& realm) -> JS::Object* { + [page, is_shared](JS::Realm& realm) -> JS::Object* { // 7a. For the global object, if is shared is true, create a new SharedWorkerGlobalScope object. // 7b. Otherwise, create a new DedicatedWorkerGlobalScope object. - // FIXME: Proper support for both SharedWorkerGlobalScope and DedicatedWorkerGlobalScope if (is_shared) - TODO(); + return Web::Bindings::main_thread_vm().heap().allocate(realm, page); return Web::Bindings::main_thread_vm().heap().allocate(realm, page); }, nullptr); @@ -67,10 +67,7 @@ void DedicatedWorkerHost::run(GC::Ref page, Web::HTML::TransferDataHo console_object.console().set_client(*m_console); // 10. Set worker global scope's name to the value of options's name member. - if (is_shared) - TODO(); - else - static_cast(*worker_global_scope).set_name(m_name); + worker_global_scope->set_name(m_name); // 11. Append owner to worker global scope's owner set. // FIXME: support for 'owner' set on WorkerGlobalScope @@ -80,11 +77,18 @@ void DedicatedWorkerHost::run(GC::Ref page, Web::HTML::TransferDataHo // 12. If is shared is true, then: if (is_shared) { - // FIXME: Shared worker support + auto& shared_global_scope = static_cast(*worker_global_scope); // 1. Set worker global scope's constructor origin to outside settings's origin. + shared_global_scope.set_constructor_origin(outside_settings->origin()); + // 2. Set worker global scope's constructor url to url. + shared_global_scope.set_constructor_url(m_url); + // 3. Set worker global scope's type to the value of options's type member. + shared_global_scope.set_type(m_type); + // 4. Set worker global scope's credentials to the value of options's credentials member. + shared_global_scope.set_credentials(Web::Fetch::from_bindings_enum(credentials)); } // 13. Let destination be "sharedworker" if is shared is true, and "worker" otherwise. @@ -92,7 +96,7 @@ void DedicatedWorkerHost::run(GC::Ref page, Web::HTML::TransferDataHo : Web::Fetch::Infrastructure::Request::Destination::Worker; // In both cases, let performFetch be the following perform the fetch hook given request, isTopLevel and processCustomFetchResponse: - auto perform_fetch_function = [inside_settings, worker_global_scope](GC::Ref request, Web::HTML::TopLevelModule is_top_level, Web::Fetch::Infrastructure::FetchAlgorithms::ProcessResponseConsumeBodyFunction process_custom_fetch_response) -> Web::WebIDL::ExceptionOr { + auto perform_fetch_function = [inside_settings, worker_global_scope, is_shared](GC::Ref request, Web::HTML::TopLevelModule is_top_level, Web::Fetch::Infrastructure::FetchAlgorithms::ProcessResponseConsumeBodyFunction process_custom_fetch_response) -> Web::WebIDL::ExceptionOr { auto& realm = inside_settings->realm(); auto& vm = realm.vm(); @@ -112,7 +116,7 @@ void DedicatedWorkerHost::run(GC::Ref page, Web::HTML::TransferDataHo auto process_custom_fetch_response_function = GC::create_function(vm.heap(), move(process_custom_fetch_response)); // 3. Fetch request with processResponseConsumeBody set to the following steps given response response and null, failure, or a byte sequence bodyBytes: - fetch_algorithms_input.process_response_consume_body = [worker_global_scope, process_custom_fetch_response_function, inside_settings](auto response, auto body_bytes) { + fetch_algorithms_input.process_response_consume_body = [worker_global_scope, process_custom_fetch_response_function, inside_settings, is_shared](auto response, auto body_bytes) { auto& vm = inside_settings->vm(); // 1. Set worker global scope's url to response's url. @@ -127,6 +131,7 @@ void DedicatedWorkerHost::run(GC::Ref page, Web::HTML::TransferDataHo response = Web::Fetch::Infrastructure::Response::network_error(vm, "Blocked by Content Security Policy"_string); } + // FIXME: Use worker global scope's policy container's embedder policy // FIXME: 4. If worker global scope's embedder policy's value is compatible with cross-origin isolation and is shared is true, // then set agent's agent cluster's cross-origin isolation mode to "logical" or "concrete". // The one chosen is implementation-defined. @@ -150,7 +155,7 @@ void DedicatedWorkerHost::run(GC::Ref page, Web::HTML::TransferDataHo }; auto perform_fetch = Web::HTML::create_perform_the_fetch_hook(inside_settings->heap(), move(perform_fetch_function)); - auto on_complete_function = [inside_settings, worker_global_scope, message_port_data = move(message_port_data), url = m_url](GC::Ptr script) mutable { + auto on_complete_function = [inside_settings, worker_global_scope, message_port_data = move(message_port_data), url = m_url, is_shared](GC::Ptr script) mutable { auto& realm = inside_settings->realm(); // 1. If script is null or if script's error to rethrow is non-null, then: if (!script || !script->error_to_rethrow().is_null()) { @@ -206,10 +211,25 @@ void DedicatedWorkerHost::run(GC::Ref page, Web::HTML::TransferDataHo inside_port->start(); } - // FIXME: 13. If is shared is true, then queue a global task on DOM manipulation task source given worker + // 13. If is shared is true, then queue a global task on DOM manipulation task source given worker // global scope to fire an event named connect at worker global scope, using MessageEvent, // with the data attribute initialized to the empty string, the ports attribute initialized // to a new frozen array containing inside port, and the source attribute initialized to inside port. + if (is_shared) { + Web::HTML::queue_global_task(Web::HTML::Task::Source::DOMManipulation, *worker_global_scope, GC::create_function(realm.heap(), [worker_global_scope, inside_port] { + auto& realm = worker_global_scope->realm(); + auto& vm = realm.vm(); + Web::HTML::TemporaryExecutionContext const context(realm); + + Web::HTML::MessageEventInit event_init {}; + event_init.data = GC::Ref { vm.empty_string() }; + event_init.ports = { inside_port }; + event_init.source = inside_port; + + auto message_event = Web::HTML::MessageEvent::create(realm, Web::HTML::EventNames::connect, event_init); + worker_global_scope->dispatch_event(message_event); + })); + } // FIXME: 14. Enable the client message queue of the ServiceWorkerContainer object whose associated service // worker client is worker global scope's relevant settings object. diff --git a/Services/WebWorker/DedicatedWorkerHost.h b/Services/WebWorker/WorkerHost.h similarity index 77% rename from Services/WebWorker/DedicatedWorkerHost.h rename to Services/WebWorker/WorkerHost.h index 891e1c6ef79..ee256727c1d 100644 --- a/Services/WebWorker/DedicatedWorkerHost.h +++ b/Services/WebWorker/WorkerHost.h @@ -16,12 +16,12 @@ namespace WebWorker { -class DedicatedWorkerHost : public RefCounted { +class WorkerHost : public RefCounted { public: - explicit DedicatedWorkerHost(URL::URL url, Web::Bindings::WorkerType type, String name); - ~DedicatedWorkerHost(); + explicit WorkerHost(URL::URL url, Web::Bindings::WorkerType type, String name); + ~WorkerHost(); - void run(GC::Ref, Web::HTML::TransferDataHolder message_port_data, Web::HTML::SerializedEnvironmentSettingsObject const&); + void run(GC::Ref, Web::HTML::TransferDataHolder message_port_data, Web::HTML::SerializedEnvironmentSettingsObject const&, Web::Bindings::RequestCredentials, bool is_shared); private: GC::Root m_console;