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