1use std::sync::Arc;
6use std::sync::atomic::AtomicBool;
7use std::thread::{self, JoinHandle};
8
9use base::generic_channel::{GenericReceiver, RoutedReceiver};
10use base::id::{BrowsingContextId, PipelineId, ScriptEventLoopId, WebViewId};
11use constellation_traits::{WorkerGlobalScopeInit, WorkerScriptLoadOrigin};
12use crossbeam_channel::{Receiver, Sender, unbounded};
13use devtools_traits::DevtoolScriptControlMsg;
14use dom_struct::dom_struct;
15use fonts::FontContext;
16use js::context::JSContext;
17use js::jsapi::{Heap, JSContext as RawJSContext, JSObject};
18use js::jsval::UndefinedValue;
19use js::rust::{CustomAutoRooter, CustomAutoRooterGuard, HandleValue};
20use net_traits::image_cache::ImageCache;
21use net_traits::policy_container::{PolicyContainer, RequestPolicyContainer};
22use net_traits::request::{
23 CredentialsMode, Destination, InsecureRequestsPolicy, Origin, ParserMetadata,
24 PreloadedResources, Referrer, RequestBuilder, RequestClient, RequestMode,
25};
26use servo_url::{ImmutableOrigin, ServoUrl};
27use style::thread_state::{self, ThreadState};
28
29use crate::devtools;
30use crate::dom::abstractworker::{MessageData, SimpleWorkerErrorHandler, WorkerScriptMsg};
31use crate::dom::abstractworkerglobalscope::{WorkerEventLoopMethods, run_worker_event_loop};
32use crate::dom::bindings::cell::DomRefCell;
33use crate::dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding;
34use crate::dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding::DedicatedWorkerGlobalScopeMethods;
35use crate::dom::bindings::codegen::Bindings::MessagePortBinding::StructuredSerializeOptions;
36use crate::dom::bindings::codegen::Bindings::WorkerBinding::WorkerType;
37use crate::dom::bindings::error::{ErrorInfo, ErrorResult};
38use crate::dom::bindings::inheritance::Castable;
39use crate::dom::bindings::refcounted::Trusted;
40use crate::dom::bindings::reflector::DomGlobal;
41use crate::dom::bindings::root::DomRoot;
42use crate::dom::bindings::str::DOMString;
43use crate::dom::bindings::structuredclone;
44use crate::dom::bindings::trace::{CustomTraceable, RootedTraceableBox};
45use crate::dom::csp::Violation;
46use crate::dom::errorevent::ErrorEvent;
47use crate::dom::event::{Event, EventBubbles, EventCancelable};
48use crate::dom::eventtarget::EventTarget;
49use crate::dom::globalscope::GlobalScope;
50use crate::dom::messageevent::MessageEvent;
51use crate::dom::types::DebuggerGlobalScope;
52#[cfg(feature = "webgpu")]
53use crate::dom::webgpu::identityhub::IdentityHub;
54use crate::dom::worker::{TrustedWorkerAddress, Worker};
55use crate::dom::workerglobalscope::{ScriptFetchContext, WorkerGlobalScope};
56use crate::messaging::{CommonScriptMsg, ScriptEventLoopReceiver, ScriptEventLoopSender};
57use crate::realms::{AlreadyInRealm, InRealm, enter_realm};
58use crate::script_runtime::ScriptThreadEventCategory::WorkerEvent;
59use crate::script_runtime::{CanGc, JSContext as SafeJSContext, Runtime, ThreadSafeJSContext};
60use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue};
61use crate::task_source::{SendableTaskSource, TaskSourceName};
62
63pub(crate) struct AutoWorkerReset<'a> {
68 workerscope: &'a DedicatedWorkerGlobalScope,
69 old_worker: Option<TrustedWorkerAddress>,
70}
71
72impl<'a> AutoWorkerReset<'a> {
73 pub(crate) fn new(
74 workerscope: &'a DedicatedWorkerGlobalScope,
75 worker: TrustedWorkerAddress,
76 ) -> AutoWorkerReset<'a> {
77 let old_worker = workerscope.replace_worker(Some(worker));
78 AutoWorkerReset {
79 workerscope,
80 old_worker,
81 }
82 }
83}
84
85impl Drop for AutoWorkerReset<'_> {
86 fn drop(&mut self) {
87 self.workerscope
88 .replace_worker(std::mem::take(&mut self.old_worker));
89 }
90}
91
92pub(crate) enum DedicatedWorkerControlMsg {
94 Exit,
96}
97
98pub(crate) enum DedicatedWorkerScriptMsg {
99 CommonWorker(TrustedWorkerAddress, WorkerScriptMsg),
101 WakeUp,
103}
104
105pub(crate) enum MixedMessage {
106 Worker(DedicatedWorkerScriptMsg),
107 Devtools(DevtoolScriptControlMsg),
108 Control(DedicatedWorkerControlMsg),
109 Timer,
110}
111
112impl QueuedTaskConversion for DedicatedWorkerScriptMsg {
113 fn task_source_name(&self) -> Option<&TaskSourceName> {
114 let common_worker_msg = match self {
115 DedicatedWorkerScriptMsg::CommonWorker(_, common_worker_msg) => common_worker_msg,
116 _ => return None,
117 };
118 let script_msg = match common_worker_msg {
119 WorkerScriptMsg::Common(script_msg) => script_msg,
120 _ => return None,
121 };
122 match script_msg {
123 CommonScriptMsg::Task(_category, _boxed, _pipeline_id, source_name) => {
124 Some(source_name)
125 },
126 _ => None,
127 }
128 }
129
130 fn pipeline_id(&self) -> Option<PipelineId> {
131 None
134 }
135
136 fn into_queued_task(self) -> Option<QueuedTask> {
137 let (worker, common_worker_msg) = match self {
138 DedicatedWorkerScriptMsg::CommonWorker(worker, common_worker_msg) => {
139 (worker, common_worker_msg)
140 },
141 _ => return None,
142 };
143 let script_msg = match common_worker_msg {
144 WorkerScriptMsg::Common(script_msg) => script_msg,
145 _ => return None,
146 };
147 let (category, boxed, pipeline_id, task_source) = match script_msg {
148 CommonScriptMsg::Task(category, boxed, pipeline_id, task_source) => {
149 (category, boxed, pipeline_id, task_source)
150 },
151 _ => return None,
152 };
153 Some((Some(worker), category, boxed, pipeline_id, task_source))
154 }
155
156 fn from_queued_task(queued_task: QueuedTask) -> Self {
157 let (worker, category, boxed, pipeline_id, task_source) = queued_task;
158 let script_msg = CommonScriptMsg::Task(category, boxed, pipeline_id, task_source);
159 DedicatedWorkerScriptMsg::CommonWorker(worker.unwrap(), WorkerScriptMsg::Common(script_msg))
160 }
161
162 fn inactive_msg() -> Self {
163 panic!("Workers should never receive messages marked as inactive");
165 }
166
167 fn wake_up_msg() -> Self {
168 DedicatedWorkerScriptMsg::WakeUp
169 }
170
171 fn is_wake_up(&self) -> bool {
172 matches!(self, DedicatedWorkerScriptMsg::WakeUp)
173 }
174}
175
176unsafe_no_jsmanaged_fields!(TaskQueue<DedicatedWorkerScriptMsg>);
177
178#[dom_struct]
180pub(crate) struct DedicatedWorkerGlobalScope {
181 workerglobalscope: WorkerGlobalScope,
182 #[no_trace]
184 webview_id: WebViewId,
185 #[ignore_malloc_size_of = "Defined in std"]
186 task_queue: TaskQueue<DedicatedWorkerScriptMsg>,
187 own_sender: Sender<DedicatedWorkerScriptMsg>,
188 worker: DomRefCell<Option<TrustedWorkerAddress>>,
189 parent_event_loop_sender: ScriptEventLoopSender,
191 #[ignore_malloc_size_of = "ImageCache"]
192 #[no_trace]
193 image_cache: Arc<dyn ImageCache>,
194 #[no_trace]
195 browsing_context: Option<BrowsingContextId>,
196 #[ignore_malloc_size_of = "Channels are hard"]
199 #[no_trace]
200 control_receiver: Receiver<DedicatedWorkerControlMsg>,
201 #[no_trace]
202 queued_worker_tasks: DomRefCell<Vec<MessageData>>,
203}
204
205impl WorkerEventLoopMethods for DedicatedWorkerGlobalScope {
206 type WorkerMsg = DedicatedWorkerScriptMsg;
207 type ControlMsg = DedicatedWorkerControlMsg;
208 type Event = MixedMessage;
209
210 fn task_queue(&self) -> &TaskQueue<DedicatedWorkerScriptMsg> {
211 &self.task_queue
212 }
213
214 fn handle_event(&self, event: MixedMessage, cx: &mut JSContext) -> bool {
215 self.handle_mixed_message(event, cx)
216 }
217
218 fn handle_worker_post_event(
219 &self,
220 worker: &TrustedWorkerAddress,
221 ) -> Option<AutoWorkerReset<'_>> {
222 let ar = AutoWorkerReset::new(self, worker.clone());
223 Some(ar)
224 }
225
226 fn from_control_msg(msg: DedicatedWorkerControlMsg) -> MixedMessage {
227 MixedMessage::Control(msg)
228 }
229
230 fn from_worker_msg(msg: DedicatedWorkerScriptMsg) -> MixedMessage {
231 MixedMessage::Worker(msg)
232 }
233
234 fn from_devtools_msg(msg: DevtoolScriptControlMsg) -> MixedMessage {
235 MixedMessage::Devtools(msg)
236 }
237
238 fn from_timer_msg() -> MixedMessage {
239 MixedMessage::Timer
240 }
241
242 fn control_receiver(&self) -> &Receiver<DedicatedWorkerControlMsg> {
243 &self.control_receiver
244 }
245}
246
247impl DedicatedWorkerGlobalScope {
248 #[allow(clippy::too_many_arguments)]
249 fn new_inherited(
250 init: WorkerGlobalScopeInit,
251 webview_id: WebViewId,
252 worker_name: DOMString,
253 worker_type: WorkerType,
254 worker_url: ServoUrl,
255 from_devtools_receiver: RoutedReceiver<DevtoolScriptControlMsg>,
256 runtime: Runtime,
257 parent_event_loop_sender: ScriptEventLoopSender,
258 own_sender: Sender<DedicatedWorkerScriptMsg>,
259 receiver: Receiver<DedicatedWorkerScriptMsg>,
260 closing: Arc<AtomicBool>,
261 image_cache: Arc<dyn ImageCache>,
262 browsing_context: Option<BrowsingContextId>,
263 #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
264 control_receiver: Receiver<DedicatedWorkerControlMsg>,
265 insecure_requests_policy: InsecureRequestsPolicy,
266 font_context: Option<Arc<FontContext>>,
267 ) -> DedicatedWorkerGlobalScope {
268 DedicatedWorkerGlobalScope {
269 workerglobalscope: WorkerGlobalScope::new_inherited(
270 init,
271 worker_name,
272 worker_type,
273 worker_url,
274 runtime,
275 from_devtools_receiver,
276 closing,
277 #[cfg(feature = "webgpu")]
278 gpu_id_hub,
279 insecure_requests_policy,
280 font_context,
281 ),
282 webview_id,
283 task_queue: TaskQueue::new(receiver, own_sender.clone()),
284 own_sender,
285 parent_event_loop_sender,
286 worker: DomRefCell::new(None),
287 image_cache,
288 browsing_context,
289 control_receiver,
290 queued_worker_tasks: Default::default(),
291 }
292 }
293
294 #[expect(clippy::too_many_arguments)]
295 pub(crate) fn new(
296 init: WorkerGlobalScopeInit,
297 webview_id: WebViewId,
298 worker_name: DOMString,
299 worker_type: WorkerType,
300 worker_url: ServoUrl,
301 from_devtools_receiver: RoutedReceiver<DevtoolScriptControlMsg>,
302 runtime: Runtime,
303 parent_event_loop_sender: ScriptEventLoopSender,
304 own_sender: Sender<DedicatedWorkerScriptMsg>,
305 receiver: Receiver<DedicatedWorkerScriptMsg>,
306 closing: Arc<AtomicBool>,
307 image_cache: Arc<dyn ImageCache>,
308 browsing_context: Option<BrowsingContextId>,
309 #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
310 control_receiver: Receiver<DedicatedWorkerControlMsg>,
311 insecure_requests_policy: InsecureRequestsPolicy,
312 font_context: Option<Arc<FontContext>>,
313 ) -> DomRoot<DedicatedWorkerGlobalScope> {
314 let scope = Box::new(DedicatedWorkerGlobalScope::new_inherited(
315 init,
316 webview_id,
317 worker_name,
318 worker_type,
319 worker_url,
320 from_devtools_receiver,
321 runtime,
322 parent_event_loop_sender,
323 own_sender,
324 receiver,
325 closing,
326 image_cache,
327 browsing_context,
328 #[cfg(feature = "webgpu")]
329 gpu_id_hub,
330 control_receiver,
331 insecure_requests_policy,
332 font_context,
333 ));
334 DedicatedWorkerGlobalScopeBinding::Wrap::<crate::DomTypeHolder>(
335 GlobalScope::get_cx(),
336 scope,
337 )
338 }
339
340 #[expect(unsafe_code)]
342 #[allow(clippy::too_many_arguments)]
343 pub(crate) fn run_worker_scope(
344 mut init: WorkerGlobalScopeInit,
345 webview_id: WebViewId,
346 worker_url: ServoUrl,
347 from_devtools_receiver: GenericReceiver<DevtoolScriptControlMsg>,
348 worker: TrustedWorkerAddress,
349 parent_event_loop_sender: ScriptEventLoopSender,
350 own_sender: Sender<DedicatedWorkerScriptMsg>,
351 receiver: Receiver<DedicatedWorkerScriptMsg>,
352 worker_load_origin: WorkerScriptLoadOrigin,
353 worker_name: String,
354 worker_type: WorkerType,
355 closing: Arc<AtomicBool>,
356 image_cache: Arc<dyn ImageCache>,
357 browsing_context: Option<BrowsingContextId>,
358 #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
359 control_receiver: Receiver<DedicatedWorkerControlMsg>,
360 context_sender: Sender<ThreadSafeJSContext>,
361 insecure_requests_policy: InsecureRequestsPolicy,
362 policy_container: PolicyContainer,
363 font_context: Option<Arc<FontContext>>,
364 ) -> JoinHandle<()> {
365 let event_loop_id = ScriptEventLoopId::installed()
366 .expect("Should always be in a ScriptThread or in a dedicated worker");
367 let current_global = GlobalScope::current().expect("No current global object");
368 let origin = current_global.origin().immutable().clone();
369 let referrer = current_global.get_referrer();
370 let parent = current_global.runtime_handle();
371 let current_global_https_state = current_global.get_https_state();
372 let current_global_ancestor_trustworthy = current_global.has_trustworthy_ancestor_origin();
373 let is_secure_context = current_global.is_secure_context();
374 let is_nested_browsing_context = current_global.is_nested_browsing_context();
375
376 thread::Builder::new()
377 .name(format!("WW:{}", worker_url.debug_compact()))
378 .spawn(move || {
379 thread_state::initialize(ThreadState::SCRIPT | ThreadState::IN_WORKER);
380 ScriptEventLoopId::install(event_loop_id);
381
382 let WorkerScriptLoadOrigin {
383 referrer_url,
384 referrer_policy,
385 pipeline_id,
386 } = worker_load_origin;
387
388 let referrer = referrer_url.map(Referrer::ReferrerUrl).unwrap_or(referrer);
389
390 let request_client = RequestClient {
391 preloaded_resources: PreloadedResources::default(),
392 policy_container: RequestPolicyContainer::PolicyContainer(
393 policy_container.clone(),
394 ),
395 origin: Origin::Origin(origin.clone()),
396 is_nested_browsing_context,
397 insecure_requests_policy,
398 };
399
400 let request = RequestBuilder::new(Some(webview_id), worker_url.clone(), referrer)
401 .destination(Destination::Worker)
402 .mode(RequestMode::SameOrigin)
403 .credentials_mode(CredentialsMode::CredentialsSameOrigin)
404 .parser_metadata(ParserMetadata::NotParserInserted)
405 .use_url_credentials(true)
406 .pipeline_id(Some(pipeline_id))
407 .referrer_policy(referrer_policy)
408 .insecure_requests_policy(insecure_requests_policy)
409 .has_trustworthy_ancestor_origin(current_global_ancestor_trustworthy)
410 .policy_container(policy_container.clone())
411 .origin(origin)
412 .client(request_client);
413
414 let event_loop_sender = ScriptEventLoopSender::DedicatedWorker {
415 sender: own_sender.clone(),
416 main_thread_worker: worker.clone(),
417 };
418
419 let runtime = unsafe {
420 Runtime::new_with_parent(Some(parent), Some(event_loop_sender.clone()))
421 };
422 let mut cx = unsafe { runtime.cx() };
426 let cx = &mut cx;
427 let debugger_global = DebuggerGlobalScope::new(
428 pipeline_id,
429 init.to_devtools_sender.clone(),
430 init.from_devtools_sender
431 .clone()
432 .expect("Guaranteed by Worker::Constructor"),
433 init.mem_profiler_chan.clone(),
434 init.time_profiler_chan.clone(),
435 init.script_to_constellation_chan.clone(),
436 init.script_to_embedder_chan.clone(),
437 init.resource_threads.clone(),
438 init.storage_threads.clone(),
439 #[cfg(feature = "webgpu")]
440 gpu_id_hub.clone(),
441 cx,
442 );
443 debugger_global.execute(CanGc::from_cx(cx));
444
445 let context_for_interrupt = runtime.thread_safe_js_context();
446 let _ = context_sender.send(context_for_interrupt);
447
448 let devtools_mpsc_port = from_devtools_receiver.route_preserving_errors();
449
450 if worker_url.scheme() == "data" {
458 if is_secure_context {
460 init.origin = ImmutableOrigin::new_opaque_data_url_worker();
461 } else {
462 init.origin = ImmutableOrigin::new_opaque();
463 }
464 }
465
466 let worker_id = init.worker_id;
467 let global = DedicatedWorkerGlobalScope::new(
468 init,
469 webview_id,
470 DOMString::from_string(worker_name),
471 worker_type,
472 worker_url,
473 devtools_mpsc_port,
474 runtime,
475 parent_event_loop_sender,
476 own_sender,
477 receiver,
478 closing,
479 image_cache,
480 browsing_context,
481 #[cfg(feature = "webgpu")]
482 gpu_id_hub,
483 control_receiver,
484 insecure_requests_policy,
485 font_context,
486 );
487 debugger_global.fire_add_debuggee(
488 CanGc::from_cx(cx),
489 global.upcast(),
490 pipeline_id,
491 Some(worker_id),
492 );
493 let scope = global.upcast::<WorkerGlobalScope>();
494 let global_scope = global.upcast::<GlobalScope>();
495
496 global_scope.set_https_state(current_global_https_state);
497 let request = request.https_state(global_scope.get_https_state());
498
499 let task_source = SendableTaskSource {
500 sender: event_loop_sender.clone(),
501 pipeline_id,
502 name: TaskSourceName::Networking,
503 canceller: Default::default(),
504 };
505 let context = ScriptFetchContext::new(
506 Trusted::new(scope),
507 request.url.clone(),
508 worker.clone(),
509 policy_container,
510 );
511 global_scope.fetch(request, context, task_source);
512
513 let reporter_name = format!("dedicated-worker-reporter-{}", worker_id);
514 scope
515 .upcast::<GlobalScope>()
516 .mem_profiler_chan()
517 .run_with_memory_reporting(
518 || {
519 while !scope.is_closing() {
525 run_worker_event_loop(&*global, Some(&worker), cx);
526 }
527 },
528 reporter_name,
529 event_loop_sender,
530 CommonScriptMsg::CollectReports,
531 );
532 scope.clear_js_runtime();
533 })
534 .expect("Thread spawning failed")
535 }
536
537 pub(crate) fn webview_id(&self) -> WebViewId {
538 self.webview_id
539 }
540
541 fn replace_worker(
546 &self,
547 new_worker: Option<TrustedWorkerAddress>,
548 ) -> Option<TrustedWorkerAddress> {
549 let old_worker = std::mem::replace(&mut *self.worker.borrow_mut(), new_worker);
550
551 self.upcast::<GlobalScope>()
557 .task_manager()
558 .set_sender(self.event_loop_sender());
559
560 old_worker
561 }
562
563 pub(crate) fn image_cache(&self) -> Arc<dyn ImageCache> {
564 self.image_cache.clone()
565 }
566
567 pub(crate) fn event_loop_sender(&self) -> Option<ScriptEventLoopSender> {
568 Some(ScriptEventLoopSender::DedicatedWorker {
569 sender: self.own_sender.clone(),
570 main_thread_worker: self.worker.borrow().clone()?,
571 })
572 }
573
574 pub(crate) fn new_script_pair(&self) -> (ScriptEventLoopSender, ScriptEventLoopReceiver) {
575 let (sender, receiver) = unbounded();
576 let main_thread_worker = self.worker.borrow().as_ref().unwrap().clone();
577 (
578 ScriptEventLoopSender::DedicatedWorker {
579 sender,
580 main_thread_worker,
581 },
582 ScriptEventLoopReceiver::DedicatedWorker(receiver),
583 )
584 }
585
586 pub(crate) fn fire_queued_messages(&self, can_gc: CanGc) {
587 let queue: Vec<_> = self.queued_worker_tasks.borrow_mut().drain(..).collect();
588 for msg in queue {
589 if self.upcast::<WorkerGlobalScope>().is_closing() {
590 return;
591 }
592 self.dispatch_message_event(msg, can_gc);
593 }
594 }
595
596 fn dispatch_message_event(&self, msg: MessageData, can_gc: CanGc) {
597 let scope = self.upcast::<WorkerGlobalScope>();
598 let target = self.upcast();
599 let _ac = enter_realm(self);
600 rooted!(in(*scope.get_cx()) let mut message = UndefinedValue());
601 if let Ok(ports) =
602 structuredclone::read(scope.upcast(), *msg.data, message.handle_mut(), can_gc)
603 {
604 MessageEvent::dispatch_jsval(
605 target,
606 scope.upcast(),
607 message.handle(),
608 Some(&msg.origin.ascii_serialization()),
609 None,
610 ports,
611 can_gc,
612 );
613 } else {
614 MessageEvent::dispatch_error(target, scope.upcast(), can_gc);
615 }
616 }
617
618 fn handle_script_event(&self, msg: WorkerScriptMsg, cx: &mut JSContext) {
619 match msg {
620 WorkerScriptMsg::DOMMessage(message_data) => {
621 if self.upcast::<WorkerGlobalScope>().is_execution_ready() {
622 self.dispatch_message_event(message_data, CanGc::from_cx(cx));
623 } else {
624 self.queued_worker_tasks.borrow_mut().push(message_data);
625 }
626 },
627 WorkerScriptMsg::Common(msg) => {
628 self.upcast::<WorkerGlobalScope>().process_event(msg, cx);
629 },
630 }
631 }
632
633 fn handle_mixed_message(&self, msg: MixedMessage, cx: &mut JSContext) -> bool {
634 if self.upcast::<WorkerGlobalScope>().is_closing() {
635 return false;
636 }
637 match msg {
639 MixedMessage::Devtools(msg) => match msg {
640 DevtoolScriptControlMsg::EvaluateJS(_pipe_id, string, sender) => {
641 devtools::handle_evaluate_js(self.upcast(), string, sender, CanGc::from_cx(cx))
642 },
643 DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, bool_val) => {
644 devtools::handle_wants_live_notifications(self.upcast(), bool_val)
645 },
646 _ => debug!("got an unusable devtools control message inside the worker!"),
647 },
648 MixedMessage::Worker(DedicatedWorkerScriptMsg::CommonWorker(linked_worker, msg)) => {
649 let _ar = AutoWorkerReset::new(self, linked_worker);
650 self.handle_script_event(msg, cx);
651 },
652 MixedMessage::Worker(DedicatedWorkerScriptMsg::WakeUp) => {},
653 MixedMessage::Control(DedicatedWorkerControlMsg::Exit) => {
654 return false;
655 },
656 MixedMessage::Timer => {},
657 }
658 true
659 }
660
661 pub(crate) fn forward_error_to_worker_object(&self, error_info: ErrorInfo) {
663 let worker = self.worker.borrow().as_ref().unwrap().clone();
665 let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
666 let task = Box::new(task!(forward_error_to_worker_object: move || {
667 let worker = worker.root();
668 let global = worker.global();
669
670 let event = ErrorEvent::new(
673 &global,
674 atom!("error"),
675 EventBubbles::DoesNotBubble,
676 EventCancelable::Cancelable,
677 error_info.message.as_str().into(),
678 error_info.filename.as_str().into(),
679 error_info.lineno,
680 error_info.column,
681 HandleValue::null(),
682 CanGc::note(),
683 );
684
685 if event.upcast::<Event>().fire(worker.upcast::<EventTarget>(), CanGc::note()) {
687 global.report_an_error(error_info, HandleValue::null(), CanGc::note());
688 }
689 }));
690 self.parent_event_loop_sender
691 .send(CommonScriptMsg::Task(
692 WorkerEvent,
693 task,
694 Some(pipeline_id),
695 TaskSourceName::DOMManipulation,
696 ))
697 .unwrap();
698 }
699
700 fn post_message_impl(
702 &self,
703 cx: &mut JSContext,
704 message: HandleValue,
705 transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
706 ) -> ErrorResult {
707 let data = structuredclone::write(cx.into(), message, Some(transfer))?;
708 let worker = self.worker.borrow().as_ref().unwrap().clone();
709 let global_scope = self.upcast::<GlobalScope>();
710 let pipeline_id = global_scope.pipeline_id();
711 let task = Box::new(task!(post_worker_message: move |cx| {
712 Worker::handle_message(worker, data, cx);
713 }));
714 self.parent_event_loop_sender
715 .send(CommonScriptMsg::Task(
716 WorkerEvent,
717 task,
718 Some(pipeline_id),
719 TaskSourceName::DOMManipulation,
720 ))
721 .expect("Sending to parent failed");
722 Ok(())
723 }
724
725 pub(crate) fn browsing_context(&self) -> Option<BrowsingContextId> {
726 self.browsing_context
727 }
728
729 pub(crate) fn report_csp_violations(&self, violations: Vec<Violation>) {
730 let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
731 self.parent_event_loop_sender
732 .send(CommonScriptMsg::ReportCspViolations(
733 pipeline_id,
734 violations,
735 ))
736 .expect("Sending to parent failed");
737 }
738
739 pub(crate) fn forward_simple_error_at_worker(&self, worker: TrustedWorkerAddress) {
740 let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
741 self.parent_event_loop_sender
742 .send(CommonScriptMsg::Task(
743 WorkerEvent,
744 Box::new(SimpleWorkerErrorHandler::new(worker)),
745 Some(pipeline_id),
746 TaskSourceName::DOMManipulation,
747 ))
748 .expect("Sending to parent failed");
749 }
750}
751
752#[expect(unsafe_code)]
753pub(crate) unsafe extern "C" fn interrupt_callback(cx: *mut RawJSContext) -> bool {
754 let in_realm_proof = AlreadyInRealm::assert_for_cx(unsafe { SafeJSContext::from_ptr(cx) });
755 let global = unsafe { GlobalScope::from_context(cx, InRealm::Already(&in_realm_proof)) };
756
757 let Some(worker) = global.downcast::<WorkerGlobalScope>() else {
759 assert!(global.is::<DebuggerGlobalScope>());
760 return false;
761 };
762
763 assert!(worker.is::<DedicatedWorkerGlobalScope>());
765 !worker.is_closing()
766}
767
768impl DedicatedWorkerGlobalScopeMethods<crate::DomTypeHolder> for DedicatedWorkerGlobalScope {
769 fn Name(&self) -> DOMString {
771 self.workerglobalscope.worker_name()
772 }
773
774 fn PostMessage(
776 &self,
777 cx: &mut JSContext,
778 message: HandleValue,
779 transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
780 ) -> ErrorResult {
781 self.post_message_impl(cx, message, transfer)
782 }
783
784 fn PostMessage_(
786 &self,
787 cx: &mut JSContext,
788 message: HandleValue,
789 options: RootedTraceableBox<StructuredSerializeOptions>,
790 ) -> ErrorResult {
791 let mut rooted = CustomAutoRooter::new(
792 options
793 .transfer
794 .iter()
795 .map(|js: &RootedTraceableBox<Heap<*mut JSObject>>| js.get())
796 .collect(),
797 );
798 #[expect(unsafe_code)]
799 let guard = unsafe { CustomAutoRooterGuard::new(cx.raw_cx(), &mut rooted) };
800 self.post_message_impl(cx, message, guard)
801 }
802
803 fn Close(&self) {
805 self.upcast::<WorkerGlobalScope>().close();
807 }
808
809 event_handler!(message, GetOnmessage, SetOnmessage);
811
812 event_handler!(messageerror, GetOnmessageerror, SetOnmessageerror);
814}