/src/serenity/Userland/Libraries/LibWeb/HTML/Worker.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2022, Ben Abraham <ben.d.abraham@gmail.com> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #include <AK/Debug.h> |
8 | | #include <LibJS/Runtime/Realm.h> |
9 | | #include <LibWeb/Bindings/WorkerPrototype.h> |
10 | | #include <LibWeb/HTML/MessagePort.h> |
11 | | #include <LibWeb/HTML/Scripting/Environments.h> |
12 | | #include <LibWeb/HTML/Scripting/WindowEnvironmentSettingsObject.h> |
13 | | #include <LibWeb/HTML/Worker.h> |
14 | | |
15 | | namespace Web::HTML { |
16 | | |
17 | | JS_DEFINE_ALLOCATOR(Worker); |
18 | | |
19 | | // https://html.spec.whatwg.org/multipage/workers.html#dedicated-workers-and-the-worker-interface |
20 | | Worker::Worker(String const& script_url, WorkerOptions const& options, DOM::Document& document) |
21 | 0 | : DOM::EventTarget(document.realm()) |
22 | 0 | , m_script_url(script_url) |
23 | 0 | , m_options(options) |
24 | 0 | , m_document(&document) |
25 | 0 | { |
26 | 0 | } |
27 | | |
28 | | void Worker::initialize(JS::Realm& realm) |
29 | 0 | { |
30 | 0 | Base::initialize(realm); |
31 | 0 | WEB_SET_PROTOTYPE_FOR_INTERFACE(Worker); |
32 | 0 | } |
33 | | |
34 | | void Worker::visit_edges(Cell::Visitor& visitor) |
35 | 0 | { |
36 | 0 | Base::visit_edges(visitor); |
37 | 0 | visitor.visit(m_document); |
38 | 0 | visitor.visit(m_outside_port); |
39 | 0 | visitor.visit(m_agent); |
40 | 0 | } |
41 | | |
42 | | // https://html.spec.whatwg.org/multipage/workers.html#dom-worker |
43 | | WebIDL::ExceptionOr<JS::NonnullGCPtr<Worker>> Worker::create(String const& script_url, WorkerOptions const& options, DOM::Document& document) |
44 | 0 | { |
45 | 0 | dbgln_if(WEB_WORKER_DEBUG, "WebWorker: Creating worker with script_url = {}", script_url); |
46 | | |
47 | | // Returns a new Worker object. scriptURL will be fetched and executed in the background, |
48 | | // creating a new global environment for which worker represents the communication channel. |
49 | | // options can be used to define the name of that global environment via the name option, |
50 | | // primarily for debugging purposes. It can also ensure this new global environment supports |
51 | | // JavaScript modules (specify type: "module"), and if that is specified, can also be used |
52 | | // to specify how scriptURL is fetched through the credentials option. |
53 | | |
54 | | // FIXME: 1. The user agent may throw a "SecurityError" DOMException if the request violates |
55 | | // a policy decision (e.g. if the user agent is configured to not allow the page to start dedicated workers). |
56 | | // Technically not a fixme if our policy is not to throw errors :^) |
57 | | |
58 | | // 2. Let outside settings be the current settings object. |
59 | 0 | auto& outside_settings = current_settings_object(); |
60 | | |
61 | | // 3. Parse the scriptURL argument relative to outside settings. |
62 | 0 | auto url = document.parse_url(script_url); |
63 | | |
64 | | // 4. If this fails, throw a "SyntaxError" DOMException. |
65 | 0 | if (!url.is_valid()) { |
66 | 0 | dbgln_if(WEB_WORKER_DEBUG, "WebWorker: Invalid URL loaded '{}'.", script_url); |
67 | 0 | return WebIDL::SyntaxError::create(document.realm(), "url is not valid"_string); |
68 | 0 | } |
69 | | |
70 | | // 5. Let worker URL be the resulting URL record. |
71 | | |
72 | | // 6. Let worker be a new Worker object. |
73 | 0 | auto worker = document.heap().allocate<Worker>(document.realm(), script_url, options, document); |
74 | | |
75 | | // 7. Let outside port be a new MessagePort in outside settings's Realm. |
76 | 0 | auto outside_port = MessagePort::create(outside_settings.realm()); |
77 | | |
78 | | // 8. Associate the outside port with worker |
79 | 0 | worker->m_outside_port = outside_port; |
80 | 0 | worker->m_outside_port->set_worker_event_target(worker); |
81 | | |
82 | | // 9. Run this step in parallel: |
83 | | // 1. Run a worker given worker, worker URL, outside settings, outside port, and options. |
84 | 0 | worker->run_a_worker(url, outside_settings, *outside_port, options); |
85 | | |
86 | | // 10. Return worker |
87 | 0 | return worker; |
88 | 0 | } |
89 | | |
90 | | // https://html.spec.whatwg.org/multipage/workers.html#run-a-worker |
91 | | void Worker::run_a_worker(URL::URL& url, EnvironmentSettingsObject& outside_settings, JS::GCPtr<MessagePort> port, WorkerOptions const& options) |
92 | 0 | { |
93 | | // 1. Let is shared be true if worker is a SharedWorker object, and false otherwise. |
94 | | // FIXME: SharedWorker support |
95 | | |
96 | | // 2. Let owner be the relevant owner to add given outside settings. |
97 | | // FIXME: Support WorkerGlobalScope options |
98 | 0 | if (!is<HTML::WindowEnvironmentSettingsObject>(outside_settings)) |
99 | 0 | TODO(); |
100 | | |
101 | | // 3. Let parent worker global scope be null. |
102 | | // 4. If owner is a WorkerGlobalScope object (i.e., we are creating a nested dedicated worker), |
103 | | // then set parent worker global scope to owner. |
104 | | // FIXME: Support for nested workers. |
105 | | |
106 | | // 5. Let unsafeWorkerCreationTime be the unsafe shared current time. |
107 | | |
108 | | // 6. Let agent be the result of obtaining a dedicated/shared worker agent given outside settings |
109 | | // and is shared. Run the rest of these steps in that agent. |
110 | | |
111 | | // Note: This spawns a new process to act as the 'agent' for the worker. |
112 | 0 | m_agent = heap().allocate<WorkerAgent>(outside_settings.realm(), url, options, port, outside_settings); |
113 | 0 | } |
114 | | |
115 | | // https://html.spec.whatwg.org/multipage/workers.html#dom-worker-terminate |
116 | | WebIDL::ExceptionOr<void> Worker::terminate() |
117 | 0 | { |
118 | 0 | dbgln_if(WEB_WORKER_DEBUG, "WebWorker: Terminate"); |
119 | |
|
120 | 0 | return {}; |
121 | 0 | } |
122 | | |
123 | | // https://html.spec.whatwg.org/multipage/workers.html#dom-worker-postmessage |
124 | | WebIDL::ExceptionOr<void> Worker::post_message(JS::Value message, StructuredSerializeOptions const& options) |
125 | 0 | { |
126 | 0 | dbgln_if(WEB_WORKER_DEBUG, "WebWorker: Post Message: {}", message.to_string_without_side_effects()); |
127 | | |
128 | | // The postMessage(message, transfer) and postMessage(message, options) methods on Worker objects act as if, |
129 | | // when invoked, they immediately invoked the respective postMessage(message, transfer) and |
130 | | // postMessage(message, options) on the port, with the same arguments, and returned the same return value. |
131 | |
|
132 | 0 | return m_outside_port->post_message(message, options); |
133 | 0 | } |
134 | | |
135 | | // https://html.spec.whatwg.org/multipage/workers.html#dom-worker-postmessage |
136 | | WebIDL::ExceptionOr<void> Worker::post_message(JS::Value message, Vector<JS::Handle<JS::Object>> const& transfer) |
137 | 0 | { |
138 | | // The postMessage(message, transfer) and postMessage(message, options) methods on Worker objects act as if, |
139 | | // when invoked, they immediately invoked the respective postMessage(message, transfer) and |
140 | | // postMessage(message, options) on the port, with the same arguments, and returned the same return value. |
141 | |
|
142 | 0 | return m_outside_port->post_message(message, transfer); |
143 | 0 | } |
144 | | |
145 | | #undef __ENUMERATE |
146 | | #define __ENUMERATE(attribute_name, event_name) \ |
147 | | void Worker::set_##attribute_name(WebIDL::CallbackType* value) \ |
148 | 0 | { \ |
149 | 0 | set_event_handler_attribute(event_name, move(value)); \ |
150 | 0 | } \ Unexecuted instantiation: Web::HTML::Worker::set_onmessage(Web::WebIDL::CallbackType*) Unexecuted instantiation: Web::HTML::Worker::set_onmessageerror(Web::WebIDL::CallbackType*) |
151 | | WebIDL::CallbackType* Worker::attribute_name() \ |
152 | 0 | { \ |
153 | 0 | return event_handler_attribute(event_name); \ |
154 | 0 | } Unexecuted instantiation: Web::HTML::Worker::onmessage() Unexecuted instantiation: Web::HTML::Worker::onmessageerror() |
155 | | ENUMERATE_WORKER_EVENT_HANDLERS(__ENUMERATE) |
156 | | #undef __ENUMERATE |
157 | | |
158 | | } // namespace Web::HTML |