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, RequestPolicyContainer};
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::{ModuleFetchClient, 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: RequestPolicyContainer::PolicyContainer(
420 policy_container.clone(),
421 ),
422 origin: Origin::Origin(origin.clone()),
423 is_nested_browsing_context,
424 insecure_requests_policy,
425 };
426
427 let event_loop_sender = ScriptEventLoopSender::DedicatedWorker {
428 sender: own_sender.clone(),
429 main_thread_worker: worker.clone(),
430 };
431
432 let runtime = unsafe {
433 Runtime::new_with_parent(Some(parent), Some(event_loop_sender.clone()))
434 };
435 let mut cx = unsafe { runtime.cx() };
439 let cx = &mut cx;
440 let debugger_global = DebuggerGlobalScope::new(
441 pipeline_id,
442 init.to_devtools_sender.clone(),
443 init.from_devtools_sender
444 .clone()
445 .expect("Guaranteed by Worker::Constructor"),
446 init.mem_profiler_chan.clone(),
447 init.time_profiler_chan.clone(),
448 init.script_to_constellation_chan.clone(),
449 init.script_to_embedder_chan.clone(),
450 init.resource_threads.clone(),
451 init.storage_threads.clone(),
452 #[cfg(feature = "webgpu")]
453 gpu_id_hub.clone(),
454 cx,
455 );
456 debugger_global.execute(cx);
457
458 let context_for_interrupt = runtime.thread_safe_js_context();
459 let _ = context_sender.send(context_for_interrupt);
460
461 let devtools_mpsc_port = from_devtools_receiver.route_preserving_errors();
462
463 if worker_url.scheme() == "data" {
471 if is_secure_context {
473 init.origin = ImmutableOrigin::new_opaque_data_url_worker();
474 } else {
475 init.origin = ImmutableOrigin::new_opaque();
476 }
477 }
478
479 let worker_id = init.worker_id;
480 let devtools_enabled = init.to_devtools_sender.is_some();
481 let global = DedicatedWorkerGlobalScope::new(
482 init,
483 webview_id,
484 worker_name.into(),
485 worker_type,
486 worker_url.url(),
487 devtools_mpsc_port,
488 runtime,
489 parent_event_loop_sender,
490 own_sender,
491 receiver,
492 closing,
493 image_cache,
494 browsing_context,
495 #[cfg(feature = "webgpu")]
496 gpu_id_hub,
497 control_receiver,
498 insecure_requests_policy,
499 font_context,
500 &debugger_global,
501 cx,
502 );
503 if devtools_enabled {
504 debugger_global.fire_add_debuggee(
505 cx,
506 global.upcast(),
507 pipeline_id,
508 Some(worker_id),
509 );
510 }
511 let scope = global.upcast::<WorkerGlobalScope>();
512 let global_scope = global.upcast::<GlobalScope>();
513
514 let fetch_client = ModuleFetchClient {
515 insecure_requests_policy,
516 has_trustworthy_ancestor_origin: current_global_ancestor_trustworthy,
517 policy_container,
518 client: request_client,
519 pipeline_id,
520 origin,
521 };
522
523 {
525 let _ar = AutoWorkerReset::new(&global, worker.clone());
526 match worker_type {
527 WorkerType::Classic => {
528 fetch_a_classic_worker_script(
529 scope,
530 worker_url,
531 fetch_client,
532 Destination::Worker,
533 Some(webview_id),
534 referrer,
535 );
536 },
537 WorkerType::Module => {
538 let worker_scope = DomRoot::from_ref(scope);
539 fetch_a_module_worker_script_graph(
540 cx,
541 global_scope,
542 worker_url.url(),
543 fetch_client,
544 Destination::Worker,
545 referrer,
546 credentials,
547 move |cx, module_tree| {
548 worker_scope.on_complete(cx, module_tree.map(Script::Module));
549 },
550 );
551 },
552 }
553
554 let reporter_name = format!("dedicated-worker-reporter-{}", worker_id);
555 scope
556 .upcast::<GlobalScope>()
557 .mem_profiler_chan()
558 .run_with_memory_reporting(
559 || {
560 while !scope.is_closing() {
566 run_worker_event_loop(&*global, Some(&worker), cx);
567 }
568 },
569 reporter_name,
570 event_loop_sender,
571 CommonScriptMsg::CollectReports,
572 );
573 }
574
575 scope.clear_js_runtime();
576 })
577 .expect("Thread spawning failed")
578 }
579
580 pub(crate) fn webview_id(&self) -> WebViewId {
581 self.webview_id
582 }
583
584 fn replace_worker(
589 &self,
590 new_worker: Option<TrustedWorkerAddress>,
591 ) -> Option<TrustedWorkerAddress> {
592 let old_worker = std::mem::replace(&mut *self.worker.borrow_mut(), new_worker);
593
594 self.upcast::<GlobalScope>()
600 .task_manager()
601 .set_sender(self.event_loop_sender());
602
603 old_worker
604 }
605
606 pub(crate) fn image_cache(&self) -> Arc<dyn ImageCache> {
607 self.image_cache.clone()
608 }
609
610 pub(crate) fn event_loop_sender(&self) -> Option<ScriptEventLoopSender> {
611 Some(ScriptEventLoopSender::DedicatedWorker {
612 sender: self.own_sender.clone(),
613 main_thread_worker: self.worker.borrow().clone()?,
614 })
615 }
616
617 pub(crate) fn new_script_pair(&self) -> (ScriptEventLoopSender, ScriptEventLoopReceiver) {
618 let (sender, receiver) = unbounded();
619 let main_thread_worker = self.worker.borrow().as_ref().unwrap().clone();
620 (
621 ScriptEventLoopSender::DedicatedWorker {
622 sender,
623 main_thread_worker,
624 },
625 ScriptEventLoopReceiver::DedicatedWorker(receiver),
626 )
627 }
628
629 pub(crate) fn fire_queued_messages(&self, cx: &mut JSContext) {
630 let queue: Vec<_> = self.queued_worker_tasks.borrow_mut().drain(..).collect();
631 for msg in queue {
632 if self.upcast::<WorkerGlobalScope>().is_closing() {
633 return;
634 }
635 self.dispatch_message_event(cx, msg);
636 }
637 }
638
639 fn dispatch_message_event(&self, cx: &mut JSContext, msg: MessageData) {
640 let scope = self.upcast::<WorkerGlobalScope>();
641 let target = self.upcast();
642 let mut realm = enter_auto_realm(cx, self);
643 let cx = &mut realm;
644 rooted!(&in(cx) let mut message = UndefinedValue());
645 if let Ok(ports) =
646 structuredclone::read(cx, scope.upcast(), *msg.data, message.handle_mut())
647 {
648 MessageEvent::dispatch_jsval(
649 cx,
650 target,
651 scope.upcast(),
652 message.handle(),
653 Some(&msg.origin.ascii_serialization()),
654 None,
655 ports,
656 );
657 } else {
658 MessageEvent::dispatch_error(cx, target, scope.upcast());
659 }
660 }
661
662 fn handle_script_event(&self, msg: WorkerScriptMsg, cx: &mut JSContext) {
663 match msg {
664 WorkerScriptMsg::DOMMessage(message_data) => {
665 if self.upcast::<WorkerGlobalScope>().is_execution_ready() {
666 self.dispatch_message_event(cx, message_data);
667 } else {
668 self.queued_worker_tasks.borrow_mut().push(message_data);
669 }
670 },
671 WorkerScriptMsg::Common(msg) => {
672 self.upcast::<WorkerGlobalScope>().process_event(msg, cx);
673 },
674 }
675 }
676
677 fn handle_mixed_message(&self, msg: MixedMessage, cx: &mut JSContext) -> bool {
678 if self.upcast::<WorkerGlobalScope>().is_closing() {
679 return false;
680 }
681 match msg {
683 MixedMessage::Devtools(msg) => self
684 .upcast::<WorkerGlobalScope>()
685 .handle_devtools_message(msg, cx),
686 MixedMessage::Worker(DedicatedWorkerScriptMsg::CommonWorker(linked_worker, msg)) => {
687 let _ar = AutoWorkerReset::new(self, linked_worker);
688 self.handle_script_event(msg, cx);
689 },
690 MixedMessage::Worker(DedicatedWorkerScriptMsg::WakeUp) => {},
691 MixedMessage::Control(DedicatedWorkerControlMsg::Exit) => {
692 return false;
693 },
694 MixedMessage::Timer => {},
695 }
696 true
697 }
698
699 pub(crate) fn forward_error_to_worker_object(&self, error_info: ErrorInfo) {
701 let worker = self.worker.borrow().as_ref().unwrap().clone();
703 let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
704 let task = Box::new(task!(forward_error_to_worker_object: move |cx| {
705 let worker = worker.root();
706 let global = worker.global();
707
708 let event = ErrorEvent::new(
711 cx,
712 &global,
713 atom!("error"),
714 EventBubbles::DoesNotBubble,
715 EventCancelable::Cancelable,
716 error_info.message.as_str().into(),
717 error_info.filename.as_str().into(),
718 error_info.lineno,
719 error_info.column,
720 HandleValue::null(),
721 );
722
723 if event.upcast::<Event>().fire(cx, worker.upcast::<EventTarget>()) {
725 global.report_an_error(cx, error_info, HandleValue::null());
726 }
727 }));
728 self.parent_event_loop_sender
729 .send(CommonScriptMsg::Task(
730 WorkerEvent,
731 task,
732 Some(pipeline_id),
733 TaskSourceName::DOMManipulation,
734 ))
735 .unwrap();
736 }
737
738 fn post_message_impl(
740 &self,
741 cx: &mut JSContext,
742 message: HandleValue,
743 transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
744 ) -> ErrorResult {
745 let data = structuredclone::write(cx, message, Some(transfer))?;
746 let worker = self.worker.borrow().as_ref().unwrap().clone();
747 let global_scope = self.upcast::<GlobalScope>();
748 let pipeline_id = global_scope.pipeline_id();
749 let task = Box::new(task!(post_worker_message: move |cx| {
750 Worker::handle_message(worker, data, cx);
751 }));
752 self.parent_event_loop_sender
753 .send(CommonScriptMsg::Task(
754 WorkerEvent,
755 task,
756 Some(pipeline_id),
757 TaskSourceName::DOMManipulation,
758 ))
759 .expect("Sending to parent failed");
760 Ok(())
761 }
762
763 pub(crate) fn browsing_context(&self) -> Option<BrowsingContextId> {
764 self.browsing_context
765 }
766
767 pub(crate) fn report_csp_violations(&self, violations: Vec<Violation>) {
768 let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
769 self.parent_event_loop_sender
770 .send(CommonScriptMsg::ReportCspViolations(
771 pipeline_id,
772 violations,
773 ))
774 .unwrap_or_else(|error| {
775 log::warn!("Failed to send CSP violations to parent event loop: {error}");
776 });
777 }
778
779 pub(crate) fn forward_simple_error_at_worker(&self) {
780 let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
781 let worker = self.worker.borrow().clone().expect("worker must be set");
782 self.parent_event_loop_sender
783 .send(CommonScriptMsg::Task(
784 WorkerEvent,
785 Box::new(SimpleWorkerErrorHandler::new(worker)),
786 Some(pipeline_id),
787 TaskSourceName::DOMManipulation,
788 ))
789 .expect("Sending to parent failed");
790 }
791}
792
793pub(crate) fn fetch_a_classic_worker_script(
795 workerscope: &WorkerGlobalScope,
796 url_with_blob_lock: UrlWithBlobClaim,
797 fetch_client: ModuleFetchClient,
798 destination: Destination,
799 webview_id: Option<WebViewId>,
800 referrer: Referrer,
801) {
802 let request = RequestBuilder::new(webview_id, url_with_blob_lock.clone(), referrer)
804 .insecure_requests_policy(fetch_client.insecure_requests_policy)
806 .has_trustworthy_ancestor_origin(fetch_client.has_trustworthy_ancestor_origin)
807 .policy_container(fetch_client.policy_container.clone())
808 .client(fetch_client.client)
809 .pipeline_id(Some(fetch_client.pipeline_id))
810 .origin(fetch_client.origin)
811 .destination(destination)
813 .mode(RequestMode::SameOrigin)
816 .credentials_mode(CredentialsMode::CredentialsSameOrigin)
818 .parser_metadata(ParserMetadata::NotParserInserted)
820 .use_url_credentials(true);
822
823 let context = ScriptFetchContext::new(
824 Trusted::new(workerscope),
825 url_with_blob_lock.url(),
826 fetch_client.policy_container,
827 );
828 let global = workerscope.upcast::<GlobalScope>();
829 let task_source = global.task_manager().networking_task_source().to_sendable();
830 global.fetch(request, context, task_source);
831}
832
833impl DedicatedWorkerGlobalScopeMethods<crate::DomTypeHolder> for DedicatedWorkerGlobalScope {
834 fn Name(&self) -> DOMString {
836 self.workerglobalscope.worker_name()
837 }
838
839 fn PostMessage(
841 &self,
842 cx: &mut JSContext,
843 message: HandleValue,
844 transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
845 ) -> ErrorResult {
846 self.post_message_impl(cx, message, transfer)
847 }
848
849 fn PostMessage_(
851 &self,
852 cx: &mut JSContext,
853 message: HandleValue,
854 options: RootedTraceableBox<StructuredSerializeOptions>,
855 ) -> ErrorResult {
856 let mut rooted = CustomAutoRooter::new(
857 options
858 .transfer
859 .iter()
860 .map(|js: &RootedTraceableBox<Heap<*mut JSObject>>| js.get())
861 .collect(),
862 );
863 #[expect(unsafe_code)]
864 let guard = unsafe { CustomAutoRooterGuard::new(cx.raw_cx(), &mut rooted) };
865 self.post_message_impl(cx, message, guard)
866 }
867
868 fn Close(&self) {
870 self.upcast::<WorkerGlobalScope>().close();
872 }
873
874 event_handler!(message, GetOnmessage, SetOnmessage);
876
877 event_handler!(messageerror, GetOnmessageerror, SetOnmessageerror);
879}
880
881impl HasOrigin for DedicatedWorkerGlobalScope {
882 fn origin(&self) -> MutableOrigin {
883 self.upcast::<WorkerGlobalScope>().origin()
884 }
885}