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