1use std::sync::Arc;
6use std::sync::atomic::AtomicBool;
7use std::thread::{self, JoinHandle};
8
9use base::id::{BrowsingContextId, PipelineId, ScriptEventLoopId, WebViewId};
10use constellation_traits::{WorkerGlobalScopeInit, WorkerScriptLoadOrigin};
11use crossbeam_channel::{Receiver, Sender, unbounded};
12use devtools_traits::DevtoolScriptControlMsg;
13use dom_struct::dom_struct;
14use fonts::FontContext;
15use ipc_channel::ipc::IpcReceiver;
16use ipc_channel::router::ROUTER;
17use js::jsapi::{Heap, JSContext, JSObject};
18use js::jsval::UndefinedValue;
19use js::rust::{CustomAutoRooter, CustomAutoRooterGuard, HandleValue};
20use net_traits::image_cache::ImageCache;
21use net_traits::policy_container::PolicyContainer;
22use net_traits::request::{
23 CredentialsMode, Destination, InsecureRequestsPolicy, ParserMetadata, Referrer, RequestBuilder,
24 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, can_gc: CanGc) -> bool {
215 self.handle_mixed_message(event, can_gc)
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: Receiver<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 #[allow(unsafe_code, 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: Receiver<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: IpcReceiver<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
375 thread::Builder::new()
376 .name(format!("WW:{}", worker_url.debug_compact()))
377 .spawn(move || {
378 thread_state::initialize(ThreadState::SCRIPT | ThreadState::IN_WORKER);
379 ScriptEventLoopId::install(event_loop_id);
380
381 let WorkerScriptLoadOrigin {
382 referrer_url,
383 referrer_policy,
384 pipeline_id,
385 } = worker_load_origin;
386
387 let referrer = referrer_url.map(Referrer::ReferrerUrl).unwrap_or(referrer);
388
389 let request = RequestBuilder::new(Some(webview_id), worker_url.clone(), referrer)
390 .destination(Destination::Worker)
391 .mode(RequestMode::SameOrigin)
392 .credentials_mode(CredentialsMode::CredentialsSameOrigin)
393 .parser_metadata(ParserMetadata::NotParserInserted)
394 .use_url_credentials(true)
395 .pipeline_id(Some(pipeline_id))
396 .referrer_policy(referrer_policy)
397 .insecure_requests_policy(insecure_requests_policy)
398 .has_trustworthy_ancestor_origin(current_global_ancestor_trustworthy)
399 .policy_container(policy_container.clone())
400 .origin(origin);
401
402 let event_loop_sender = ScriptEventLoopSender::DedicatedWorker {
403 sender: own_sender.clone(),
404 main_thread_worker: worker.clone(),
405 };
406
407 let runtime = unsafe {
408 Runtime::new_with_parent(Some(parent), Some(event_loop_sender.clone()))
409 };
410 let debugger_global = DebuggerGlobalScope::new(
411 pipeline_id,
412 init.to_devtools_sender.clone(),
413 init.from_devtools_sender
414 .clone()
415 .expect("Guaranteed by Worker::Constructor"),
416 init.mem_profiler_chan.clone(),
417 init.time_profiler_chan.clone(),
418 init.script_to_constellation_chan.clone(),
419 init.script_to_embedder_chan.clone(),
420 init.resource_threads.clone(),
421 init.storage_threads.clone(),
422 #[cfg(feature = "webgpu")]
423 gpu_id_hub.clone(),
424 CanGc::note(),
425 );
426 debugger_global.execute(CanGc::note());
427
428 let context_for_interrupt = runtime.thread_safe_js_context();
429 let _ = context_sender.send(context_for_interrupt);
430
431 let (devtools_mpsc_chan, devtools_mpsc_port) = unbounded();
432 ROUTER.route_ipc_receiver_to_crossbeam_sender(
433 from_devtools_receiver,
434 devtools_mpsc_chan,
435 );
436
437 if worker_url.scheme() == "data" {
445 if is_secure_context {
447 init.origin = ImmutableOrigin::new_opaque_data_url_worker();
448 } else {
449 init.origin = ImmutableOrigin::new_opaque();
450 }
451 }
452
453 let worker_id = init.worker_id;
454 let global = DedicatedWorkerGlobalScope::new(
455 init,
456 webview_id,
457 DOMString::from_string(worker_name),
458 worker_type,
459 worker_url,
460 devtools_mpsc_port,
461 runtime,
462 parent_event_loop_sender,
463 own_sender,
464 receiver,
465 closing,
466 image_cache,
467 browsing_context,
468 #[cfg(feature = "webgpu")]
469 gpu_id_hub,
470 control_receiver,
471 insecure_requests_policy,
472 font_context,
473 );
474 debugger_global.fire_add_debuggee(
475 CanGc::note(),
476 global.upcast(),
477 pipeline_id,
478 Some(worker_id),
479 );
480 let scope = global.upcast::<WorkerGlobalScope>();
481 let global_scope = global.upcast::<GlobalScope>();
482
483 global_scope.set_https_state(current_global_https_state);
484 let request = request.https_state(global_scope.get_https_state());
485
486 let task_source = SendableTaskSource {
487 sender: event_loop_sender.clone(),
488 pipeline_id,
489 name: TaskSourceName::Networking,
490 canceller: Default::default(),
491 };
492 let context = ScriptFetchContext::new(
493 Trusted::new(scope),
494 request.url.clone(),
495 worker.clone(),
496 policy_container,
497 );
498 global_scope.fetch(request, context, task_source);
499
500 let reporter_name = format!("dedicated-worker-reporter-{}", worker_id);
501 scope
502 .upcast::<GlobalScope>()
503 .mem_profiler_chan()
504 .run_with_memory_reporting(
505 || {
506 while !scope.is_closing() {
512 run_worker_event_loop(&*global, Some(&worker), CanGc::note());
513 }
514 },
515 reporter_name,
516 event_loop_sender,
517 CommonScriptMsg::CollectReports,
518 );
519 scope.clear_js_runtime();
520 })
521 .expect("Thread spawning failed")
522 }
523
524 pub(crate) fn webview_id(&self) -> WebViewId {
525 self.webview_id
526 }
527
528 fn replace_worker(
533 &self,
534 new_worker: Option<TrustedWorkerAddress>,
535 ) -> Option<TrustedWorkerAddress> {
536 let old_worker = std::mem::replace(&mut *self.worker.borrow_mut(), new_worker);
537
538 self.upcast::<GlobalScope>()
544 .task_manager()
545 .set_sender(self.event_loop_sender());
546
547 old_worker
548 }
549
550 pub(crate) fn image_cache(&self) -> Arc<dyn ImageCache> {
551 self.image_cache.clone()
552 }
553
554 pub(crate) fn event_loop_sender(&self) -> Option<ScriptEventLoopSender> {
555 Some(ScriptEventLoopSender::DedicatedWorker {
556 sender: self.own_sender.clone(),
557 main_thread_worker: self.worker.borrow().clone()?,
558 })
559 }
560
561 pub(crate) fn new_script_pair(&self) -> (ScriptEventLoopSender, ScriptEventLoopReceiver) {
562 let (sender, receiver) = unbounded();
563 let main_thread_worker = self.worker.borrow().as_ref().unwrap().clone();
564 (
565 ScriptEventLoopSender::DedicatedWorker {
566 sender,
567 main_thread_worker,
568 },
569 ScriptEventLoopReceiver::DedicatedWorker(receiver),
570 )
571 }
572
573 pub(crate) fn fire_queued_messages(&self, can_gc: CanGc) {
574 let queue: Vec<_> = self.queued_worker_tasks.borrow_mut().drain(..).collect();
575 for msg in queue {
576 if self.upcast::<WorkerGlobalScope>().is_closing() {
577 return;
578 }
579 self.dispatch_message_event(msg, can_gc);
580 }
581 }
582
583 fn dispatch_message_event(&self, msg: MessageData, can_gc: CanGc) {
584 let scope = self.upcast::<WorkerGlobalScope>();
585 let target = self.upcast();
586 let _ac = enter_realm(self);
587 rooted!(in(*scope.get_cx()) let mut message = UndefinedValue());
588 if let Ok(ports) =
589 structuredclone::read(scope.upcast(), *msg.data, message.handle_mut(), can_gc)
590 {
591 MessageEvent::dispatch_jsval(
592 target,
593 scope.upcast(),
594 message.handle(),
595 Some(&msg.origin.ascii_serialization()),
596 None,
597 ports,
598 can_gc,
599 );
600 } else {
601 MessageEvent::dispatch_error(target, scope.upcast(), can_gc);
602 }
603 }
604
605 fn handle_script_event(&self, msg: WorkerScriptMsg, can_gc: CanGc) {
606 match msg {
607 WorkerScriptMsg::DOMMessage(message_data) => {
608 if self.upcast::<WorkerGlobalScope>().is_execution_ready() {
609 self.dispatch_message_event(message_data, can_gc);
610 } else {
611 self.queued_worker_tasks.borrow_mut().push(message_data);
612 }
613 },
614 WorkerScriptMsg::Common(msg) => {
615 self.upcast::<WorkerGlobalScope>().process_event(msg);
616 },
617 }
618 }
619
620 fn handle_mixed_message(&self, msg: MixedMessage, can_gc: CanGc) -> bool {
621 if self.upcast::<WorkerGlobalScope>().is_closing() {
622 return false;
623 }
624 match msg {
626 MixedMessage::Devtools(msg) => match msg {
627 DevtoolScriptControlMsg::EvaluateJS(_pipe_id, string, sender) => {
628 devtools::handle_evaluate_js(self.upcast(), string, sender, can_gc)
629 },
630 DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, bool_val) => {
631 devtools::handle_wants_live_notifications(self.upcast(), bool_val)
632 },
633 _ => debug!("got an unusable devtools control message inside the worker!"),
634 },
635 MixedMessage::Worker(DedicatedWorkerScriptMsg::CommonWorker(linked_worker, msg)) => {
636 let _ar = AutoWorkerReset::new(self, linked_worker);
637 self.handle_script_event(msg, can_gc);
638 },
639 MixedMessage::Worker(DedicatedWorkerScriptMsg::WakeUp) => {},
640 MixedMessage::Control(DedicatedWorkerControlMsg::Exit) => {
641 return false;
642 },
643 MixedMessage::Timer => {},
644 }
645 true
646 }
647
648 pub(crate) fn forward_error_to_worker_object(&self, error_info: ErrorInfo) {
650 let worker = self.worker.borrow().as_ref().unwrap().clone();
652 let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
653 let task = Box::new(task!(forward_error_to_worker_object: move || {
654 let worker = worker.root();
655 let global = worker.global();
656
657 let event = ErrorEvent::new(
660 &global,
661 atom!("error"),
662 EventBubbles::DoesNotBubble,
663 EventCancelable::Cancelable,
664 error_info.message.as_str().into(),
665 error_info.filename.as_str().into(),
666 error_info.lineno,
667 error_info.column,
668 HandleValue::null(),
669 CanGc::note(),
670 );
671
672 if event.upcast::<Event>().fire(worker.upcast::<EventTarget>(), CanGc::note()) {
674 global.report_an_error(error_info, HandleValue::null(), CanGc::note());
675 }
676 }));
677 self.parent_event_loop_sender
678 .send(CommonScriptMsg::Task(
679 WorkerEvent,
680 task,
681 Some(pipeline_id),
682 TaskSourceName::DOMManipulation,
683 ))
684 .unwrap();
685 }
686
687 fn post_message_impl(
689 &self,
690 cx: SafeJSContext,
691 message: HandleValue,
692 transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
693 ) -> ErrorResult {
694 let data = structuredclone::write(cx, message, Some(transfer))?;
695 let worker = self.worker.borrow().as_ref().unwrap().clone();
696 let global_scope = self.upcast::<GlobalScope>();
697 let pipeline_id = global_scope.pipeline_id();
698 let task = Box::new(task!(post_worker_message: move || {
699 Worker::handle_message(worker, data, CanGc::note());
700 }));
701 self.parent_event_loop_sender
702 .send(CommonScriptMsg::Task(
703 WorkerEvent,
704 task,
705 Some(pipeline_id),
706 TaskSourceName::DOMManipulation,
707 ))
708 .expect("Sending to parent failed");
709 Ok(())
710 }
711
712 pub(crate) fn browsing_context(&self) -> Option<BrowsingContextId> {
713 self.browsing_context
714 }
715
716 pub(crate) fn report_csp_violations(&self, violations: Vec<Violation>) {
717 let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
718 self.parent_event_loop_sender
719 .send(CommonScriptMsg::ReportCspViolations(
720 pipeline_id,
721 violations,
722 ))
723 .expect("Sending to parent failed");
724 }
725
726 pub(crate) fn forward_simple_error_at_worker(&self, worker: TrustedWorkerAddress) {
727 let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
728 self.parent_event_loop_sender
729 .send(CommonScriptMsg::Task(
730 WorkerEvent,
731 Box::new(SimpleWorkerErrorHandler::new(worker)),
732 Some(pipeline_id),
733 TaskSourceName::DOMManipulation,
734 ))
735 .expect("Sending to parent failed");
736 }
737}
738
739#[expect(unsafe_code)]
740pub(crate) unsafe extern "C" fn interrupt_callback(cx: *mut JSContext) -> bool {
741 let in_realm_proof = AlreadyInRealm::assert_for_cx(unsafe { SafeJSContext::from_ptr(cx) });
742 let global = unsafe { GlobalScope::from_context(cx, InRealm::Already(&in_realm_proof)) };
743 let worker =
744 DomRoot::downcast::<WorkerGlobalScope>(global).expect("global is not a worker scope");
745 assert!(worker.is::<DedicatedWorkerGlobalScope>());
746
747 !worker.is_closing()
749}
750
751impl DedicatedWorkerGlobalScopeMethods<crate::DomTypeHolder> for DedicatedWorkerGlobalScope {
752 fn Name(&self) -> DOMString {
754 self.workerglobalscope.worker_name()
755 }
756
757 fn PostMessage(
759 &self,
760 cx: SafeJSContext,
761 message: HandleValue,
762 transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
763 ) -> ErrorResult {
764 self.post_message_impl(cx, message, transfer)
765 }
766
767 fn PostMessage_(
769 &self,
770 cx: SafeJSContext,
771 message: HandleValue,
772 options: RootedTraceableBox<StructuredSerializeOptions>,
773 ) -> ErrorResult {
774 let mut rooted = CustomAutoRooter::new(
775 options
776 .transfer
777 .iter()
778 .map(|js: &RootedTraceableBox<Heap<*mut JSObject>>| js.get())
779 .collect(),
780 );
781 let guard = CustomAutoRooterGuard::new(*cx, &mut rooted);
782 self.post_message_impl(cx, message, guard)
783 }
784
785 fn Close(&self) {
787 self.upcast::<WorkerGlobalScope>().close();
789 }
790
791 event_handler!(message, GetOnmessage, SetOnmessage);
793
794 event_handler!(messageerror, GetOnmessageerror, SetOnmessageerror);
796}