2023-11-08 11:47:41 -07:00
/*
* Copyright ( c ) 2023 , Andrew Kaster < akaster @ serenityos . org >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2024-10-26 21:02:28 +13:00
# include <LibWeb/Bindings/PrincipalHostDefined.h>
2026-02-11 07:33:58 +01:00
# include <LibWeb/DOM/Document.h>
2026-03-07 21:08:19 +01:00
# include <LibWeb/DOM/Event.h>
# include <LibWeb/DOM/EventTarget.h>
2026-04-04 23:04:46 +02:00
# include <LibWeb/HTML/ErrorEvent.h>
2026-03-07 21:08:19 +01:00
# include <LibWeb/HTML/EventLoop/EventLoop.h>
# include <LibWeb/HTML/EventNames.h>
2024-10-17 08:46:48 -04:00
# include <LibWeb/HTML/MessagePort.h>
2026-03-07 21:08:19 +01:00
# include <LibWeb/HTML/Scripting/Environments.h>
2026-04-04 23:04:46 +02:00
# include <LibWeb/HTML/Scripting/ExceptionReporter.h>
2026-01-04 22:20:18 -08:00
# include <LibWeb/HTML/Window.h>
2026-03-07 21:08:19 +01:00
# include <LibWeb/HTML/Worker.h>
2025-04-24 14:08:39 +12:00
# include <LibWeb/HTML/WorkerAgentParent.h>
2024-01-06 13:13:59 -07:00
# include <LibWeb/Page/Page.h>
2023-11-08 11:47:41 -07:00
# include <LibWeb/Worker/WebWorkerClient.h>
namespace Web : : HTML {
2025-04-24 14:08:39 +12:00
GC_DEFINE_ALLOCATOR ( WorkerAgentParent ) ;
2023-11-19 19:47:52 +01:00
2026-03-07 21:08:19 +01:00
WorkerAgentParent : : WorkerAgentParent ( URL : : URL url , WorkerOptions const & options , GC : : Ptr < MessagePort > outside_port , GC : : Ref < EnvironmentSettingsObject > outside_settings , GC : : Ref < DOM : : EventTarget > worker_event_target , Bindings : : AgentType agent_type )
2023-11-08 11:47:41 -07:00
: m_worker_options ( options )
2025-05-18 14:10:01 -06:00
, m_agent_type ( agent_type )
2023-11-08 11:47:41 -07:00
, m_url ( move ( url ) )
2023-12-20 13:47:01 -07:00
, m_outside_port ( outside_port )
2024-03-05 09:42:10 -07:00
, m_outside_settings ( outside_settings )
2026-03-07 21:08:19 +01:00
, m_worker_event_target ( worker_event_target )
2023-11-08 11:47:41 -07:00
{
2023-12-20 13:47:01 -07:00
}
2025-04-24 14:08:39 +12:00
void WorkerAgentParent : : initialize ( JS : : Realm & realm )
2023-12-20 13:47:01 -07:00
{
Base : : initialize ( realm ) ;
m_message_port = MessagePort : : create ( realm ) ;
m_message_port - > entangle_with ( * m_outside_port ) ;
2025-07-17 09:51:04 -04:00
TransferDataEncoder data_holder ;
2023-12-20 13:47:01 -07:00
MUST ( m_message_port - > transfer_steps ( data_holder ) ) ;
2023-11-22 09:57:22 -07:00
2025-06-07 23:57:17 +02:00
// FIXME: Specification says this supposed to happen in step 11 of onComplete handler defined in https://html.spec.whatwg.org/multipage/workers.html#run-a-worker
// but that would require introducing a new IPC message type to communicate this from WebWorker to WebContent process,
// so let's do it here for now.
m_outside_port - > start ( ) ;
2024-01-06 13:13:59 -07:00
// 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.
2026-03-12 14:17:41 +01:00
auto response = Bindings : : principal_host_defined_page ( realm ) . client ( ) . request_worker_agent ( m_agent_type ) ;
2024-01-06 13:13:59 -07:00
2026-03-12 14:17:41 +01:00
auto transport = MUST ( response . worker_handle . create_transport ( ) ) ;
2024-10-22 15:47:33 -06:00
m_worker_ipc = make_ref_counted < WebWorkerClient > ( move ( transport ) ) ;
2025-09-07 15:32:43 +01:00
setup_worker_ipc_callbacks ( realm ) ;
2024-01-06 13:13:59 -07:00
2026-03-12 14:17:41 +01:00
m_worker_ipc - > async_connect_to_request_server ( move ( response . request_server_handle ) ) ;
m_worker_ipc - > async_connect_to_image_decoder ( move ( response . image_decoder_handle ) ) ;
2026-01-04 22:20:18 -08:00
auto serialized_outside_settings = m_outside_settings - > serialize ( ) ;
2026-02-21 19:11:48 +01:00
m_worker_ipc - > async_start_worker ( m_url , m_worker_options . type , m_worker_options . credentials , m_worker_options . name , move ( data_holder ) , serialized_outside_settings , m_agent_type ) ;
2023-12-20 13:47:01 -07:00
}
2023-11-08 11:47:41 -07:00
2025-09-07 15:32:43 +01:00
void WorkerAgentParent : : setup_worker_ipc_callbacks ( JS : : Realm & realm )
{
// NOTE: As long as WorkerAgentParent is alive, realm and m_worker_ipc will be alive.
2026-02-07 11:13:47 -05:00
m_worker_ipc - > on_request_cookie = [ realm = GC : : RawRef { realm } ] ( URL : : URL const & url , HTTP : : Cookie : : Source source ) {
2025-09-07 15:32:43 +01:00
auto & client = Bindings : : principal_host_defined_page ( realm ) . client ( ) ;
return client . page_did_request_cookie ( url , source ) ;
} ;
2026-04-10 21:18:00 +02:00
m_worker_ipc - > on_post_broadcast_channel_message = [ realm = GC : : RawRef { realm } ] ( Web : : HTML : : BroadcastChannelMessage message ) {
auto & client = Bindings : : principal_host_defined_page ( realm ) . client ( ) ;
client . page_did_post_broadcast_channel_message ( message ) ;
} ;
2026-03-12 14:17:41 +01:00
m_worker_ipc - > on_request_worker_agent = [ realm = GC : : RawRef { realm } ] ( Web : : Bindings : : AgentType worker_type ) - > Messages : : WebWorkerClient : : RequestWorkerAgentResponse {
2026-01-06 13:33:34 -08:00
auto & client = Bindings : : principal_host_defined_page ( realm ) . client ( ) ;
2026-03-12 14:17:41 +01:00
auto response = client . request_worker_agent ( worker_type ) ;
return { move ( response . worker_handle ) , move ( response . request_server_handle ) , move ( response . image_decoder_handle ) } ;
2026-01-06 13:33:34 -08:00
} ;
2026-04-04 23:04:46 +02:00
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 > ( * 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 < WindowOrWorkerGlobalScopeMixin > ( outside_settings . global_object ( ) ) . report_an_exception ( error , WindowOrWorkerGlobalScopeMixin : : OmitError : : Yes ) ;
} ) ) ;
} ;
2026-03-07 21:08:19 +01:00
m_worker_ipc - > on_worker_script_load_failure = [ self = GC : : Weak { * this } ] ( ) {
if ( ! self )
return ;
auto & outside_settings = * self - > m_outside_settings ;
auto & event_target = * self - > m_worker_event_target ;
// See: https://html.spec.whatwg.org/multipage/workers.html#worker-processing-model, onComplete handler for fetching script.
// 1. Queue a global task on the DOM manipulation task source given worker's relevant global object to fire an event named error at worker.
queue_global_task ( Task : : Source : : DOMManipulation , outside_settings . global_object ( ) , GC : : create_function ( outside_settings . heap ( ) , [ & event_target , & outside_settings ] ( ) {
event_target . dispatch_event ( DOM : : Event : : create ( outside_settings . realm ( ) , EventNames : : error ) ) ;
} ) ) ;
} ;
2025-09-07 15:32:43 +01:00
}
2025-04-24 14:08:39 +12:00
void WorkerAgentParent : : visit_edges ( Cell : : Visitor & visitor )
2023-12-20 13:47:01 -07:00
{
Base : : visit_edges ( visitor ) ;
visitor . visit ( m_message_port ) ;
visitor . visit ( m_outside_port ) ;
2024-03-05 09:42:10 -07:00
visitor . visit ( m_outside_settings ) ;
2026-03-07 21:08:19 +01:00
visitor . visit ( m_worker_event_target ) ;
2023-11-08 11:47:41 -07:00
}
}