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