diff --git a/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp b/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp
index c8621bf3a81..2d8a23b3fe8 100644
--- a/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp
+++ b/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -42,6 +43,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -1248,17 +1250,16 @@ void WindowOrWorkerGlobalScopeMixin::report_an_exception(JS::Value exception, Om
// 1. Set errorInfo[error] to null.
error_info.error = JS::js_null();
- // FIXME: 2. If global implements DedicatedWorkerGlobalScope, queue a global task on the DOM manipulation
- // task source with the global's associated Worker's relevant global object to run these steps:
- if (false) {
- // FIXME: 1. Let workerObject be the Worker object associated with global.
-
- // FIXME: 2. Set notHandled to the result of firing an event named error at workerObject, using ErrorEvent,
- // with the cancelable attribute initialized to true, and additional attributes initialized
- // according to errorInfo.
-
- // FIXME: 3. If notHandled is true, then report exception for workerObject's relevant global object with
- // omitError set to true.
+ // 2. If global implements DedicatedWorkerGlobalScope, queue a global task on the DOM manipulation
+ // task source with the global's associated Worker's relevant global object to run these steps:
+ if (auto* dedicated_worker_global_scope = as_if(target)) {
+ if (auto* page = dedicated_worker_global_scope->page()) {
+ page->client().page_did_report_worker_exception(
+ error_info.message,
+ error_info.filename,
+ error_info.lineno,
+ error_info.colno);
+ }
}
// 3. Otherwise, the user agent may report exception to a developer console.
else {
diff --git a/Libraries/LibWeb/HTML/WorkerAgentParent.cpp b/Libraries/LibWeb/HTML/WorkerAgentParent.cpp
index 4d4361dd22c..ab551f1f0f2 100644
--- a/Libraries/LibWeb/HTML/WorkerAgentParent.cpp
+++ b/Libraries/LibWeb/HTML/WorkerAgentParent.cpp
@@ -8,10 +8,12 @@
#include
#include
#include
+#include
#include
#include
#include
#include
+#include
#include
#include
#include
@@ -75,6 +77,36 @@ void WorkerAgentParent::setup_worker_ipc_callbacks(JS::Realm& realm)
auto response = client.request_worker_agent(worker_type);
return { move(response.worker_handle), move(response.request_server_handle), move(response.image_decoder_handle) };
};
+ m_worker_ipc->on_worker_exception = [self = GC::Weak { *this }](String message, String filename, u32 lineno, u32 colno) {
+ if (!self)
+ return;
+ // https://html.spec.whatwg.org/multipage/webappapis.html#report-an-exception
+ // 7.2: If global implements DedicatedWorkerGlobalScope, queue a global task on the DOM manipulation task source with the global's associated Worker's relevant global object to run these steps:
+ auto& outside_settings = *self->m_outside_settings;
+ auto worker_event_target = GC::Ref { *self->m_worker_event_target };
+ queue_global_task(Task::Source::DOMManipulation, outside_settings.global_object(), GC::create_function(outside_settings.heap(), [&outside_settings, worker_event_target, message = move(message), filename = move(filename), lineno, colno]() {
+ // 1. Let workerObject be the Worker object associated with global.
+ auto& worker_object = as(*worker_event_target);
+
+ auto& realm = outside_settings.realm();
+
+ // 2. Set notHandled to the result of firing an event named error at workerObject, using ErrorEvent, with the
+ // cancelable attribute initialized to true, and additional attributes initialized according to errorInfo.
+ ErrorEventInit event_init {};
+ event_init.cancelable = true;
+ event_init.message = message;
+ event_init.filename = filename;
+ event_init.lineno = lineno;
+ event_init.colno = colno;
+ event_init.error = JS::js_null();
+ auto error = ErrorEvent::create(realm, EventNames::error, event_init);
+ bool not_handled = worker_object.dispatch_event(error);
+
+ // 3. If notHandled is true, then report exception for workerObject's relevant global object with omitError set to true.
+ if (not_handled)
+ as(outside_settings.global_object()).report_an_exception(error, WindowOrWorkerGlobalScopeMixin::OmitError::Yes);
+ }));
+ };
m_worker_ipc->on_worker_script_load_failure = [self = GC::Weak { *this }]() {
if (!self)
return;
diff --git a/Libraries/LibWeb/Page/Page.h b/Libraries/LibWeb/Page/Page.h
index 0b138244359..3437deebf72 100644
--- a/Libraries/LibWeb/Page/Page.h
+++ b/Libraries/LibWeb/Page/Page.h
@@ -469,6 +469,7 @@ public:
virtual void page_did_receive_network_response_headers([[maybe_unused]] u64 request_id, [[maybe_unused]] u32 status_code, [[maybe_unused]] Optional reason_phrase, [[maybe_unused]] Vector const& response_headers) { }
virtual void page_did_receive_network_response_body([[maybe_unused]] u64 request_id, [[maybe_unused]] ReadonlyBytes data) { }
virtual void page_did_finish_network_request([[maybe_unused]] u64 request_id, [[maybe_unused]] u64 body_size, [[maybe_unused]] Requests::RequestTimingInfo const& timing_info, [[maybe_unused]] Optional const& network_error) { }
+ virtual void page_did_report_worker_exception([[maybe_unused]] String const& message, [[maybe_unused]] String const& filename, [[maybe_unused]] u32 lineno, [[maybe_unused]] u32 colno) { }
struct WorkerAgentResponse {
IPC::TransportHandle worker_handle;
diff --git a/Libraries/LibWeb/Worker/WebWorkerClient.cpp b/Libraries/LibWeb/Worker/WebWorkerClient.cpp
index 098df651643..eb71d8de56e 100644
--- a/Libraries/LibWeb/Worker/WebWorkerClient.cpp
+++ b/Libraries/LibWeb/Worker/WebWorkerClient.cpp
@@ -25,6 +25,12 @@ void WebWorkerClient::did_fail_loading_worker_script()
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)
diff --git a/Libraries/LibWeb/Worker/WebWorkerClient.h b/Libraries/LibWeb/Worker/WebWorkerClient.h
index 7c8b488c999..6ceaf393e54 100644
--- a/Libraries/LibWeb/Worker/WebWorkerClient.h
+++ b/Libraries/LibWeb/Worker/WebWorkerClient.h
@@ -25,11 +25,13 @@ public:
virtual void did_close_worker() override;
virtual void did_fail_loading_worker_script() override;
+ virtual void did_report_worker_exception(String message, String filename, u32 lineno, u32 colno) override;
virtual Messages::WebWorkerClient::DidRequestCookieResponse did_request_cookie(URL::URL, HTTP::Cookie::Source) override;
virtual Messages::WebWorkerClient::RequestWorkerAgentResponse request_worker_agent(Web::Bindings::AgentType worker_type) override;
Function on_worker_close;
Function on_worker_script_load_failure;
+ Function on_worker_exception;
Function on_request_cookie;
Function on_request_worker_agent;
diff --git a/Libraries/LibWeb/Worker/WebWorkerClient.ipc b/Libraries/LibWeb/Worker/WebWorkerClient.ipc
index a4c087338da..6f3d5c22b52 100644
--- a/Libraries/LibWeb/Worker/WebWorkerClient.ipc
+++ b/Libraries/LibWeb/Worker/WebWorkerClient.ipc
@@ -6,6 +6,7 @@
endpoint WebWorkerClient {
did_close_worker() =|
did_fail_loading_worker_script() =|
+ did_report_worker_exception(String message, String filename, u32 lineno, u32 colno) =|
did_request_cookie(URL::URL url, HTTP::Cookie::Source source) => (HTTP::Cookie::VersionedCookie cookie)
request_worker_agent(Web::Bindings::AgentType worker_type) => (IPC::TransportHandle handle, IPC::TransportHandle request_server_handle, IPC::TransportHandle image_decoder_handle)
}
diff --git a/Services/WebWorker/PageHost.cpp b/Services/WebWorker/PageHost.cpp
index d41492b5b4d..6a9c5cd4b19 100644
--- a/Services/WebWorker/PageHost.cpp
+++ b/Services/WebWorker/PageHost.cpp
@@ -92,6 +92,11 @@ HTTP::Cookie::VersionedCookie PageHost::page_did_request_cookie(URL::URL const&
return m_client.did_request_cookie(url, source);
}
+void PageHost::page_did_report_worker_exception(String const& message, String const& filename, u32 lineno, u32 colno)
+{
+ m_client.async_did_report_worker_exception(message, filename, lineno, colno);
+}
+
void PageHost::request_file(Web::FileRequest request)
{
m_client.request_file(move(request));
diff --git a/Services/WebWorker/PageHost.h b/Services/WebWorker/PageHost.h
index ac6c8f0c50a..3fcaa1b7c2f 100644
--- a/Services/WebWorker/PageHost.h
+++ b/Services/WebWorker/PageHost.h
@@ -37,6 +37,7 @@ public:
virtual Web::CSS::PreferredMotion preferred_motion() const override;
virtual size_t screen_count() const override { return 1; }
virtual HTTP::Cookie::VersionedCookie page_did_request_cookie(URL::URL const&, HTTP::Cookie::Source) override;
+ virtual void page_did_report_worker_exception(String const& message, String const& filename, u32 lineno, u32 colno) override;
virtual void request_file(Web::FileRequest) override;
virtual WorkerAgentResponse request_worker_agent(Web::Bindings::AgentType) override;
virtual Web::DisplayListPlayerType display_list_player_type() const override { VERIFY_NOT_REACHED(); }
diff --git a/Tests/LibWeb/TestConfig.ini b/Tests/LibWeb/TestConfig.ini
index e16a383f5aa..dbf71833d04 100644
--- a/Tests/LibWeb/TestConfig.ini
+++ b/Tests/LibWeb/TestConfig.ini
@@ -5,6 +5,7 @@ Text/input/cookie-working.html
; Performs cross-origin Worker fetch
Text/input/wpt-import/html/infrastructure/safe-passing-of-structured-data/structuredclone_0.html
Text/input/wpt-import/workers/constructors/Worker/same-origin.html
+Text/input/wpt-import/workers/Worker_ErrorEvent_type.htm
Text/input/Worker/XHttpRequest-responseXML-unavailable-in-worker.html
; fetching a file only works from an HTTP server.
diff --git a/Tests/LibWeb/Text/expected/wpt-import/workers/Worker_ErrorEvent_type.txt b/Tests/LibWeb/Text/expected/wpt-import/workers/Worker_ErrorEvent_type.txt
new file mode 100644
index 00000000000..a01041f5b14
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/workers/Worker_ErrorEvent_type.txt
@@ -0,0 +1,6 @@
+Harness status: OK
+
+Found 1 tests
+
+1 Pass
+Pass AbstractWorker ErrorEvent.type
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/input/wpt-import/workers/Worker_ErrorEvent_type.htm b/Tests/LibWeb/Text/input/wpt-import/workers/Worker_ErrorEvent_type.htm
new file mode 100644
index 00000000000..d65aadfc7d0
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/workers/Worker_ErrorEvent_type.htm
@@ -0,0 +1,19 @@
+
+ AbstractWorker ErrorEvent.type
+
+
+
+
diff --git a/Tests/LibWeb/Text/input/wpt-import/workers/support/ErrorEvent.js b/Tests/LibWeb/Text/input/wpt-import/workers/support/ErrorEvent.js
new file mode 100644
index 00000000000..22ea6d4fb51
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/workers/support/ErrorEvent.js
@@ -0,0 +1,10 @@
+onmessage = function(evt)
+{
+ throw(new Error(evt.data));
+}
+
+onerror = function(message, location, line, col)
+{
+ postMessage( {"message": message, "filename": location, "lineno": line, "colno": col} );
+ return false; // "not handled" so the error propagates up to the Worker object
+}