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 (event_category, task, 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(QueuedTask {
154 worker: Some(worker),
155 event_category,
156 task,
157 pipeline_id,
158 task_source,
159 })
160 }
161
162 fn from_queued_task(queued_task: QueuedTask) -> Self {
163 let script_msg = CommonScriptMsg::Task(
164 queued_task.event_category,
165 queued_task.task,
166 queued_task.pipeline_id,
167 queued_task.task_source,
168 );
169 DedicatedWorkerScriptMsg::CommonWorker(
170 queued_task.worker.unwrap(),
171 WorkerScriptMsg::Common(script_msg),
172 )
173 }
174
175 fn inactive_msg() -> Self {
176 panic!("Workers should never receive messages marked as inactive");
178 }
179
180 fn wake_up_msg() -> Self {
181 DedicatedWorkerScriptMsg::WakeUp
182 }
183
184 fn is_wake_up(&self) -> bool {
185 matches!(self, DedicatedWorkerScriptMsg::WakeUp)
186 }
187}
188
189unsafe_no_jsmanaged_fields!(TaskQueue<DedicatedWorkerScriptMsg>);
190
191#[dom_struct]
193pub(crate) struct DedicatedWorkerGlobalScope {
194 workerglobalscope: WorkerGlobalScope,
195 #[no_trace]
197 webview_id: WebViewId,
198 #[ignore_malloc_size_of = "Defined in std"]
199 task_queue: TaskQueue<DedicatedWorkerScriptMsg>,
200 own_sender: Sender<DedicatedWorkerScriptMsg>,
201 worker: DomRefCell<Option<TrustedWorkerAddress>>,
202 parent_event_loop_sender: ScriptEventLoopSender,
204 #[ignore_malloc_size_of = "ImageCache"]
205 #[no_trace]
206 image_cache: Arc<dyn ImageCache>,
207 #[no_trace]
208 browsing_context: Option<BrowsingContextId>,
209 #[no_trace]
212 control_receiver: Receiver<DedicatedWorkerControlMsg>,
213 #[no_trace]
214 queued_worker_tasks: DomRefCell<Vec<MessageData>>,
215}
216
217impl WorkerEventLoopMethods for DedicatedWorkerGlobalScope {
218 type WorkerMsg = DedicatedWorkerScriptMsg;
219 type ControlMsg = DedicatedWorkerControlMsg;
220 type Event = MixedMessage;
221
222 fn task_queue(&self) -> &TaskQueue<DedicatedWorkerScriptMsg> {
223 &self.task_queue
224 }
225
226 fn handle_event(&self, event: MixedMessage, cx: &mut JSContext) -> bool {
227 self.handle_mixed_message(event, cx)
228 }
229
230 fn handle_worker_post_event(
231 &self,
232 worker: &TrustedWorkerAddress,
233 ) -> Option<AutoWorkerReset<'_>> {
234 let ar = AutoWorkerReset::new(self, worker.clone());
235 Some(ar)
236 }
237
238 fn from_control_msg(msg: DedicatedWorkerControlMsg) -> MixedMessage {
239 MixedMessage::Control(msg)
240 }
241
242 fn from_worker_msg(msg: DedicatedWorkerScriptMsg) -> MixedMessage {
243 MixedMessage::Worker(msg)
244 }
245
246 fn from_devtools_msg(msg: DevtoolScriptControlMsg) -> MixedMessage {
247 MixedMessage::Devtools(msg)
248 }
249
250 fn from_timer_msg() -> MixedMessage {
251 MixedMessage::Timer
252 }
253
254 fn control_receiver(&self) -> &Receiver<DedicatedWorkerControlMsg> {
255 &self.control_receiver
256 }
257}
258
259impl DedicatedWorkerGlobalScope {
260 #[allow(clippy::too_many_arguments)]
261 fn new_inherited(
262 init: WorkerGlobalScopeInit,
263 webview_id: WebViewId,
264 worker_name: DOMString,
265 worker_type: WorkerType,
266 worker_url: ServoUrl,
267 from_devtools_receiver: RoutedReceiver<DevtoolScriptControlMsg>,
268 runtime: Runtime,
269 parent_event_loop_sender: ScriptEventLoopSender,
270 own_sender: Sender<DedicatedWorkerScriptMsg>,
271 receiver: Receiver<DedicatedWorkerScriptMsg>,
272 closing: Arc<AtomicBool>,
273 image_cache: Arc<dyn ImageCache>,
274 browsing_context: Option<BrowsingContextId>,
275 #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
276 control_receiver: Receiver<DedicatedWorkerControlMsg>,
277 insecure_requests_policy: InsecureRequestsPolicy,
278 font_context: Option<Arc<FontContext>>,
279 ) -> DedicatedWorkerGlobalScope {
280 DedicatedWorkerGlobalScope {
281 workerglobalscope: WorkerGlobalScope::new_inherited(
282 init,
283 worker_name,
284 worker_type,
285 worker_url,
286 runtime,
287 from_devtools_receiver,
288 closing,
289 #[cfg(feature = "webgpu")]
290 gpu_id_hub,
291 insecure_requests_policy,
292 font_context,
293 ),
294 webview_id,
295 task_queue: TaskQueue::new(receiver, own_sender.clone()),
296 own_sender,
297 parent_event_loop_sender,
298 worker: DomRefCell::new(None),
299 image_cache,
300 browsing_context,
301 control_receiver,
302 queued_worker_tasks: Default::default(),
303 }
304 }
305
306 #[expect(clippy::too_many_arguments)]
307 pub(crate) fn new(
308 init: WorkerGlobalScopeInit,
309 webview_id: WebViewId,
310 worker_name: DOMString,
311 worker_type: WorkerType,
312 worker_url: ServoUrl,
313 from_devtools_receiver: RoutedReceiver<DevtoolScriptControlMsg>,
314 runtime: Runtime,
315 parent_event_loop_sender: ScriptEventLoopSender,
316 own_sender: Sender<DedicatedWorkerScriptMsg>,
317 receiver: Receiver<DedicatedWorkerScriptMsg>,
318 closing: Arc<AtomicBool>,
319 image_cache: Arc<dyn ImageCache>,
320 browsing_context: Option<BrowsingContextId>,
321 #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
322 control_receiver: Receiver<DedicatedWorkerControlMsg>,
323 insecure_requests_policy: InsecureRequestsPolicy,
324 font_context: Option<Arc<FontContext>>,
325 cx: &mut js::context::JSContext,
326 ) -> DomRoot<DedicatedWorkerGlobalScope> {
327 let scope = Box::new(DedicatedWorkerGlobalScope::new_inherited(
328 init,
329 webview_id,
330 worker_name,
331 worker_type,
332 worker_url,
333 from_devtools_receiver,
334 runtime,
335 parent_event_loop_sender,
336 own_sender,
337 receiver,
338 closing,
339 image_cache,
340 browsing_context,
341 #[cfg(feature = "webgpu")]
342 gpu_id_hub,
343 control_receiver,
344 insecure_requests_policy,
345 font_context,
346 ));
347 DedicatedWorkerGlobalScopeBinding::Wrap::<crate::DomTypeHolder>(cx, scope)
348 }
349
350 #[expect(unsafe_code)]
352 #[allow(clippy::too_many_arguments)]
353 pub(crate) fn run_worker_scope(
354 mut init: WorkerGlobalScopeInit,
355 webview_id: WebViewId,
356 worker_url: ServoUrl,
357 from_devtools_receiver: GenericReceiver<DevtoolScriptControlMsg>,
358 worker: TrustedWorkerAddress,
359 parent_event_loop_sender: ScriptEventLoopSender,
360 own_sender: Sender<DedicatedWorkerScriptMsg>,
361 receiver: Receiver<DedicatedWorkerScriptMsg>,
362 worker_load_origin: WorkerScriptLoadOrigin,
363 worker_name: String,
364 worker_type: WorkerType,
365 closing: Arc<AtomicBool>,
366 image_cache: Arc<dyn ImageCache>,
367 browsing_context: Option<BrowsingContextId>,
368 #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
369 control_receiver: Receiver<DedicatedWorkerControlMsg>,
370 context_sender: Sender<ThreadSafeJSContext>,
371 insecure_requests_policy: InsecureRequestsPolicy,
372 policy_container: PolicyContainer,
373 font_context: Option<Arc<FontContext>>,
374 ) -> JoinHandle<()> {
375 let event_loop_id = ScriptEventLoopId::installed()
376 .expect("Should always be in a ScriptThread or in a dedicated worker");
377 let current_global = GlobalScope::current().expect("No current global object");
378 let origin = current_global.origin().immutable().clone();
379 let referrer = current_global.get_referrer();
380 let parent = current_global.runtime_handle();
381 let current_global_https_state = current_global.get_https_state();
382 let current_global_ancestor_trustworthy = current_global.has_trustworthy_ancestor_origin();
383 let is_secure_context = current_global.is_secure_context();
384 let is_nested_browsing_context = current_global.is_nested_browsing_context();
385
386 thread::Builder::new()
387 .name(format!("WW:{}", worker_url.debug_compact()))
388 .spawn(move || {
389 thread_state::initialize(ThreadState::SCRIPT | ThreadState::IN_WORKER);
390 ScriptEventLoopId::install(event_loop_id);
391
392 let WorkerScriptLoadOrigin {
393 referrer_url,
394 referrer_policy,
395 pipeline_id,
396 } = worker_load_origin;
397
398 let referrer = referrer_url.map(Referrer::ReferrerUrl).unwrap_or(referrer);
399
400 let request_client = RequestClient {
401 preloaded_resources: PreloadedResources::default(),
402 policy_container: RequestPolicyContainer::PolicyContainer(
403 policy_container.clone(),
404 ),
405 origin: Origin::Origin(origin.clone()),
406 is_nested_browsing_context,
407 insecure_requests_policy,
408 };
409
410 let request = RequestBuilder::new(Some(webview_id), worker_url.clone(), referrer)
411 .destination(Destination::Worker)
412 .mode(RequestMode::SameOrigin)
413 .credentials_mode(CredentialsMode::CredentialsSameOrigin)
414 .parser_metadata(ParserMetadata::NotParserInserted)
415 .use_url_credentials(true)
416 .pipeline_id(Some(pipeline_id))
417 .referrer_policy(referrer_policy)
418 .insecure_requests_policy(insecure_requests_policy)
419 .has_trustworthy_ancestor_origin(current_global_ancestor_trustworthy)
420 .policy_container(policy_container.clone())
421 .origin(origin)
422 .client(request_client);
423
424 let event_loop_sender = ScriptEventLoopSender::DedicatedWorker {
425 sender: own_sender.clone(),
426 main_thread_worker: worker.clone(),
427 };
428
429 let runtime = unsafe {
430 Runtime::new_with_parent(Some(parent), Some(event_loop_sender.clone()))
431 };
432 let mut cx = unsafe { runtime.cx() };
436 let cx = &mut cx;
437 let debugger_global = DebuggerGlobalScope::new(
438 pipeline_id,
439 init.to_devtools_sender.clone(),
440 init.from_devtools_sender
441 .clone()
442 .expect("Guaranteed by Worker::Constructor"),
443 init.mem_profiler_chan.clone(),
444 init.time_profiler_chan.clone(),
445 init.script_to_constellation_chan.clone(),
446 init.script_to_embedder_chan.clone(),
447 init.resource_threads.clone(),
448 init.storage_threads.clone(),
449 #[cfg(feature = "webgpu")]
450 gpu_id_hub.clone(),
451 cx,
452 );
453 debugger_global.execute(cx);
454
455 let context_for_interrupt = runtime.thread_safe_js_context();
456 let _ = context_sender.send(context_for_interrupt);
457
458 let devtools_mpsc_port = from_devtools_receiver.route_preserving_errors();
459
460 if worker_url.scheme() == "data" {
468 if is_secure_context {
470 init.origin = ImmutableOrigin::new_opaque_data_url_worker();
471 } else {
472 init.origin = ImmutableOrigin::new_opaque();
473 }
474 }
475
476 let worker_id = init.worker_id;
477 let global = DedicatedWorkerGlobalScope::new(
478 init,
479 webview_id,
480 DOMString::from_string(worker_name),
481 worker_type,
482 worker_url,
483 devtools_mpsc_port,
484 runtime,
485 parent_event_loop_sender,
486 own_sender,
487 receiver,
488 closing,
489 image_cache,
490 browsing_context,
491 #[cfg(feature = "webgpu")]
492 gpu_id_hub,
493 control_receiver,
494 insecure_requests_policy,
495 font_context,
496 cx,
497 );
498 debugger_global.fire_add_debuggee(
499 CanGc::from_cx(cx),
500 global.upcast(),
501 pipeline_id,
502 Some(worker_id),
503 );
504 let scope = global.upcast::<WorkerGlobalScope>();
505 let global_scope = global.upcast::<GlobalScope>();
506
507 global_scope.set_https_state(current_global_https_state);
508 let request = request.https_state(global_scope.get_https_state());
509
510 let task_source = SendableTaskSource {
511 sender: event_loop_sender.clone(),
512 pipeline_id,
513 name: TaskSourceName::Networking,
514 canceller: Default::default(),
515 };
516 let context = ScriptFetchContext::new(
517 Trusted::new(scope),
518 request.url.clone(),
519 worker.clone(),
520 policy_container,
521 );
522 global_scope.fetch(request, context, task_source);
523
524 let reporter_name = format!("dedicated-worker-reporter-{}", worker_id);
525 scope
526 .upcast::<GlobalScope>()
527 .mem_profiler_chan()
528 .run_with_memory_reporting(
529 || {
530 while !scope.is_closing() {
536 run_worker_event_loop(&*global, Some(&worker), cx);
537 }
538 },
539 reporter_name,
540 event_loop_sender,
541 CommonScriptMsg::CollectReports,
542 );
543 scope.clear_js_runtime();
544 })
545 .expect("Thread spawning failed")
546 }
547
548 pub(crate) fn webview_id(&self) -> WebViewId {
549 self.webview_id
550 }
551
552 fn replace_worker(
557 &self,
558 new_worker: Option<TrustedWorkerAddress>,
559 ) -> Option<TrustedWorkerAddress> {
560 let old_worker = std::mem::replace(&mut *self.worker.borrow_mut(), new_worker);
561
562 self.upcast::<GlobalScope>()
568 .task_manager()
569 .set_sender(self.event_loop_sender());
570
571 old_worker
572 }
573
574 pub(crate) fn image_cache(&self) -> Arc<dyn ImageCache> {
575 self.image_cache.clone()
576 }
577
578 pub(crate) fn event_loop_sender(&self) -> Option<ScriptEventLoopSender> {
579 Some(ScriptEventLoopSender::DedicatedWorker {
580 sender: self.own_sender.clone(),
581 main_thread_worker: self.worker.borrow().clone()?,
582 })
583 }
584
585 pub(crate) fn new_script_pair(&self) -> (ScriptEventLoopSender, ScriptEventLoopReceiver) {
586 let (sender, receiver) = unbounded();
587 let main_thread_worker = self.worker.borrow().as_ref().unwrap().clone();
588 (
589 ScriptEventLoopSender::DedicatedWorker {
590 sender,
591 main_thread_worker,
592 },
593 ScriptEventLoopReceiver::DedicatedWorker(receiver),
594 )
595 }
596
597 pub(crate) fn fire_queued_messages(&self, can_gc: CanGc) {
598 let queue: Vec<_> = self.queued_worker_tasks.borrow_mut().drain(..).collect();
599 for msg in queue {
600 if self.upcast::<WorkerGlobalScope>().is_closing() {
601 return;
602 }
603 self.dispatch_message_event(msg, can_gc);
604 }
605 }
606
607 fn dispatch_message_event(&self, msg: MessageData, can_gc: CanGc) {
608 let scope = self.upcast::<WorkerGlobalScope>();
609 let target = self.upcast();
610 let _ac = enter_realm(self);
611 rooted!(in(*scope.get_cx()) let mut message = UndefinedValue());
612 if let Ok(ports) =
613 structuredclone::read(scope.upcast(), *msg.data, message.handle_mut(), can_gc)
614 {
615 MessageEvent::dispatch_jsval(
616 target,
617 scope.upcast(),
618 message.handle(),
619 Some(&msg.origin.ascii_serialization()),
620 None,
621 ports,
622 can_gc,
623 );
624 } else {
625 MessageEvent::dispatch_error(target, scope.upcast(), can_gc);
626 }
627 }
628
629 fn handle_script_event(&self, msg: WorkerScriptMsg, cx: &mut JSContext) {
630 match msg {
631 WorkerScriptMsg::DOMMessage(message_data) => {
632 if self.upcast::<WorkerGlobalScope>().is_execution_ready() {
633 self.dispatch_message_event(message_data, CanGc::from_cx(cx));
634 } else {
635 self.queued_worker_tasks.borrow_mut().push(message_data);
636 }
637 },
638 WorkerScriptMsg::Common(msg) => {
639 self.upcast::<WorkerGlobalScope>().process_event(msg, cx);
640 },
641 }
642 }
643
644 fn handle_mixed_message(&self, msg: MixedMessage, cx: &mut JSContext) -> bool {
645 if self.upcast::<WorkerGlobalScope>().is_closing() {
646 return false;
647 }
648 match msg {
650 MixedMessage::Devtools(msg) => match msg {
651 DevtoolScriptControlMsg::EvaluateJS(_pipe_id, string, sender) => {
652 devtools::handle_evaluate_js(self.upcast(), string, sender, cx)
653 },
654 DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, bool_val) => {
655 devtools::handle_wants_live_notifications(self.upcast(), bool_val)
656 },
657 _ => debug!("got an unusable devtools control message inside the worker!"),
658 },
659 MixedMessage::Worker(DedicatedWorkerScriptMsg::CommonWorker(linked_worker, msg)) => {
660 let _ar = AutoWorkerReset::new(self, linked_worker);
661 self.handle_script_event(msg, cx);
662 },
663 MixedMessage::Worker(DedicatedWorkerScriptMsg::WakeUp) => {},
664 MixedMessage::Control(DedicatedWorkerControlMsg::Exit) => {
665 return false;
666 },
667 MixedMessage::Timer => {},
668 }
669 true
670 }
671
672 pub(crate) fn forward_error_to_worker_object(&self, error_info: ErrorInfo) {
674 let worker = self.worker.borrow().as_ref().unwrap().clone();
676 let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
677 let task = Box::new(task!(forward_error_to_worker_object: move || {
678 let worker = worker.root();
679 let global = worker.global();
680
681 let event = ErrorEvent::new(
684 &global,
685 atom!("error"),
686 EventBubbles::DoesNotBubble,
687 EventCancelable::Cancelable,
688 error_info.message.as_str().into(),
689 error_info.filename.as_str().into(),
690 error_info.lineno,
691 error_info.column,
692 HandleValue::null(),
693 CanGc::note(),
694 );
695
696 if event.upcast::<Event>().fire(worker.upcast::<EventTarget>(), CanGc::note()) {
698 global.report_an_error(error_info, HandleValue::null(), CanGc::note());
699 }
700 }));
701 self.parent_event_loop_sender
702 .send(CommonScriptMsg::Task(
703 WorkerEvent,
704 task,
705 Some(pipeline_id),
706 TaskSourceName::DOMManipulation,
707 ))
708 .unwrap();
709 }
710
711 fn post_message_impl(
713 &self,
714 cx: &mut JSContext,
715 message: HandleValue,
716 transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
717 ) -> ErrorResult {
718 let data = structuredclone::write(cx.into(), message, Some(transfer))?;
719 let worker = self.worker.borrow().as_ref().unwrap().clone();
720 let global_scope = self.upcast::<GlobalScope>();
721 let pipeline_id = global_scope.pipeline_id();
722 let task = Box::new(task!(post_worker_message: move |cx| {
723 Worker::handle_message(worker, data, cx);
724 }));
725 self.parent_event_loop_sender
726 .send(CommonScriptMsg::Task(
727 WorkerEvent,
728 task,
729 Some(pipeline_id),
730 TaskSourceName::DOMManipulation,
731 ))
732 .expect("Sending to parent failed");
733 Ok(())
734 }
735
736 pub(crate) fn browsing_context(&self) -> Option<BrowsingContextId> {
737 self.browsing_context
738 }
739
740 pub(crate) fn report_csp_violations(&self, violations: Vec<Violation>) {
741 let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
742 self.parent_event_loop_sender
743 .send(CommonScriptMsg::ReportCspViolations(
744 pipeline_id,
745 violations,
746 ))
747 .expect("Sending to parent failed");
748 }
749
750 pub(crate) fn forward_simple_error_at_worker(&self, worker: TrustedWorkerAddress) {
751 let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
752 self.parent_event_loop_sender
753 .send(CommonScriptMsg::Task(
754 WorkerEvent,
755 Box::new(SimpleWorkerErrorHandler::new(worker)),
756 Some(pipeline_id),
757 TaskSourceName::DOMManipulation,
758 ))
759 .expect("Sending to parent failed");
760 }
761}
762
763#[expect(unsafe_code)]
764pub(crate) unsafe extern "C" fn interrupt_callback(cx: *mut RawJSContext) -> bool {
765 let in_realm_proof = AlreadyInRealm::assert_for_cx(unsafe { SafeJSContext::from_ptr(cx) });
766 let global = unsafe { GlobalScope::from_context(cx, InRealm::Already(&in_realm_proof)) };
767
768 let Some(worker) = global.downcast::<WorkerGlobalScope>() else {
770 assert!(global.is::<DebuggerGlobalScope>());
771 return false;
772 };
773
774 assert!(worker.is::<DedicatedWorkerGlobalScope>());
776 !worker.is_closing()
777}
778
779impl DedicatedWorkerGlobalScopeMethods<crate::DomTypeHolder> for DedicatedWorkerGlobalScope {
780 fn Name(&self) -> DOMString {
782 self.workerglobalscope.worker_name()
783 }
784
785 fn PostMessage(
787 &self,
788 cx: &mut JSContext,
789 message: HandleValue,
790 transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
791 ) -> ErrorResult {
792 self.post_message_impl(cx, message, transfer)
793 }
794
795 fn PostMessage_(
797 &self,
798 cx: &mut JSContext,
799 message: HandleValue,
800 options: RootedTraceableBox<StructuredSerializeOptions>,
801 ) -> ErrorResult {
802 let mut rooted = CustomAutoRooter::new(
803 options
804 .transfer
805 .iter()
806 .map(|js: &RootedTraceableBox<Heap<*mut JSObject>>| js.get())
807 .collect(),
808 );
809 #[expect(unsafe_code)]
810 let guard = unsafe { CustomAutoRooterGuard::new(cx.raw_cx(), &mut rooted) };
811 self.post_message_impl(cx, message, guard)
812 }
813
814 fn Close(&self) {
816 self.upcast::<WorkerGlobalScope>().close();
818 }
819
820 event_handler!(message, GetOnmessage, SetOnmessage);
822
823 event_handler!(messageerror, GetOnmessageerror, SetOnmessageerror);
825}