1#![cfg_attr(crown, allow(crown::jscontext_first_arg))]
6
7use std::collections::VecDeque;
8use std::io;
9use std::sync::Arc;
10use std::sync::atomic::AtomicBool;
11use std::thread::{self, JoinHandle};
12
13use content_security_policy::Violation;
14use crossbeam_channel::{Receiver, Sender, unbounded};
15#[cfg(feature = "devtools")]
16use devtools_traits::DevtoolScriptControlMsg;
17use dom_struct::dom_struct;
18use fonts::FontContext;
19use js::context::JSContext;
20use js::conversions::ToJSValConvertible;
21use js::jsval::UndefinedValue;
22use net_traits::blob_url_store::UrlWithBlobClaim;
23use net_traits::image_cache::ImageCache;
24use net_traits::policy_container::PolicyContainer;
25use net_traits::request::{
26 CredentialsMode, Destination, InsecureRequestsPolicy, Origin, PreloadedResources, Referrer,
27 RequestClient,
28};
29use script_bindings::cell::DomRefCell;
30use script_bindings::interfaces::HasOrigin;
31use servo_base::generic_channel::{GenericReceiver, RoutedReceiver};
32use servo_base::id::{BrowsingContextId, ScriptEventLoopId, WebViewId};
33use servo_constellation_traits::{MessagePortImpl, WorkerGlobalScopeInit, WorkerScriptLoadOrigin};
34use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
35use style::thread_state::{self, ThreadState};
36use stylo_atoms::Atom;
37use uuid::Uuid;
38
39use crate::dom::abstractworker::{SimpleWorkerErrorHandler, WorkerScriptMsg};
40use crate::dom::abstractworkerglobalscope::{WorkerEventLoopMethods, run_worker_event_loop};
41use crate::dom::bindings::codegen::Bindings::SharedWorkerGlobalScopeBinding;
42use crate::dom::bindings::codegen::Bindings::SharedWorkerGlobalScopeBinding::SharedWorkerGlobalScopeMethods;
43use crate::dom::bindings::codegen::Bindings::WorkerBinding::WorkerType;
44use crate::dom::bindings::codegen::UnionTypes::WindowProxyOrMessagePortOrServiceWorker;
45use crate::dom::bindings::inheritance::Castable;
46use crate::dom::bindings::refcounted::Trusted;
47use crate::dom::bindings::root::{Dom, DomRoot};
48use crate::dom::bindings::str::DOMString;
49use crate::dom::bindings::trace::CustomTraceable;
50use crate::dom::dedicatedworkerglobalscope::fetch_a_classic_worker_script;
51use crate::dom::event::Event;
52use crate::dom::event::messageevent::MessageEvent;
53use crate::dom::eventtarget::EventTarget;
54use crate::dom::globalscope::GlobalScope;
55use crate::dom::html::htmlscriptelement::Script;
56use crate::dom::messageport::MessagePort;
57use crate::dom::sharedworker::{SharedWorker, SharedWorkerStorageKey, TrustedSharedWorkerAddress};
58#[cfg(feature = "devtools")]
59use crate::dom::types::DebuggerGlobalScope;
60#[cfg(feature = "webgpu")]
61use crate::dom::webgpu::identityhub::IdentityHub;
62use crate::dom::workerglobalscope::{
63 WorkerDebuggerGlobalScope, WorkerDevtoolsControlMsg, WorkerGlobalScope,
64};
65use crate::messaging::{CommonScriptMsg, ScriptEventLoopReceiver, ScriptEventLoopSender};
66use crate::runtime::script_runtime::ScriptThreadEventCategory::WorkerEvent;
67use crate::runtime::script_runtime::{IntroductionType, Runtime};
68use crate::scripting::script_module::fetch_a_module_script_graph;
69use crate::tasks::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue};
70use crate::tasks::task_source::TaskSourceName;
71
72pub(crate) enum SharedWorkerScriptMsg {
73 CommonWorker(WorkerScriptMsg),
74 Connect(MessagePortImpl),
75 WakeUp,
76}
77
78#[allow(dead_code)]
79pub(crate) enum SharedWorkerControlMsg {
80 Exit,
81}
82
83pub(crate) enum MixedMessage {
84 SharedWorker(SharedWorkerScriptMsg),
85 #[cfg(feature = "devtools")]
86 Devtools(DevtoolScriptControlMsg),
87 Control(SharedWorkerControlMsg),
88 Timer,
89}
90
91struct SharedWorkerRegistrationCleanup {
92 registration_id: Uuid,
93}
94
95impl Drop for SharedWorkerRegistrationCleanup {
96 fn drop(&mut self) {
97 SharedWorker::unregister_shared_worker(self.registration_id);
98 }
99}
100
101impl QueuedTaskConversion for SharedWorkerScriptMsg {
102 fn task_source_name(&self) -> Option<&TaskSourceName> {
103 let script_msg = match self {
104 SharedWorkerScriptMsg::CommonWorker(WorkerScriptMsg::Common(script_msg)) => script_msg,
105 _ => return None,
106 };
107 match script_msg {
108 CommonScriptMsg::Task(_category, _boxed, _pipeline_id, task_source) => {
109 Some(task_source)
110 },
111 _ => None,
112 }
113 }
114
115 fn pipeline_id(&self) -> Option<servo_base::id::PipelineId> {
116 None
117 }
118
119 fn into_queued_task(self) -> Option<QueuedTask> {
120 let script_msg = match self {
121 SharedWorkerScriptMsg::CommonWorker(WorkerScriptMsg::Common(script_msg)) => script_msg,
122 _ => return None,
123 };
124 let (event_category, task, pipeline_id, task_source) = match script_msg {
125 CommonScriptMsg::Task(category, boxed, pipeline_id, task_source) => {
126 (category, boxed, pipeline_id, task_source)
127 },
128 _ => return None,
129 };
130 Some(QueuedTask {
131 worker: None,
132 event_category,
133 task,
134 pipeline_id,
135 task_source,
136 })
137 }
138
139 fn from_queued_task(queued_task: QueuedTask) -> Self {
140 let script_msg = CommonScriptMsg::Task(
141 queued_task.event_category,
142 queued_task.task,
143 queued_task.pipeline_id,
144 queued_task.task_source,
145 );
146 SharedWorkerScriptMsg::CommonWorker(WorkerScriptMsg::Common(script_msg))
147 }
148
149 fn inactive_msg() -> Self {
150 panic!("Workers should never receive messages marked as inactive");
151 }
152
153 fn wake_up_msg() -> Self {
154 SharedWorkerScriptMsg::WakeUp
155 }
156
157 fn is_wake_up(&self) -> bool {
158 matches!(self, SharedWorkerScriptMsg::WakeUp)
159 }
160}
161
162unsafe_no_jsmanaged_fields!(TaskQueue<SharedWorkerScriptMsg>);
163
164#[dom_struct]
166pub(crate) struct SharedWorkerGlobalScope {
167 workerglobalscope: WorkerGlobalScope,
168 #[no_trace]
170 webview_id: WebViewId,
171 #[ignore_malloc_size_of = "Defined in std"]
172 task_queue: TaskQueue<SharedWorkerScriptMsg>,
173 own_sender: Sender<SharedWorkerScriptMsg>,
174 worker: DomRefCell<Option<TrustedSharedWorkerAddress>>,
175 parent_event_loop_sender: ScriptEventLoopSender,
176 #[ignore_malloc_size_of = "ImageCache"]
177 #[no_trace]
178 image_cache: Arc<dyn ImageCache>,
179 #[no_trace]
180 browsing_context: Option<BrowsingContextId>,
181 pending_connect: DomRefCell<VecDeque<Dom<MessagePort>>>,
183 #[no_trace]
184 control_receiver: Receiver<SharedWorkerControlMsg>,
185 #[cfg(feature = "devtools")]
186 debugger_global: Dom<DebuggerGlobalScope>,
187 #[no_trace]
189 storage_key: SharedWorkerStorageKey,
190 #[no_trace]
191 constructor_origin: ImmutableOrigin,
192 #[no_trace]
193 constructor_url: ServoUrl,
194 #[no_trace]
195 credentials: CredentialsMode,
196 extended_lifetime: bool,
197 #[no_trace]
198 registration_id: Uuid,
199}
200
201impl WorkerEventLoopMethods for SharedWorkerGlobalScope {
202 type WorkerMsg = SharedWorkerScriptMsg;
203 type ControlMsg = SharedWorkerControlMsg;
204 type Event = MixedMessage;
205
206 fn task_queue(&self) -> &TaskQueue<SharedWorkerScriptMsg> {
207 &self.task_queue
208 }
209
210 fn handle_event(&self, event: MixedMessage, cx: &mut JSContext) -> bool {
211 self.handle_mixed_message(event, cx)
212 }
213
214 fn handle_worker_post_event(
215 &self,
216 _worker: &crate::dom::worker::TrustedWorkerAddress,
217 ) -> Option<crate::dom::dedicatedworkerglobalscope::AutoWorkerReset<'_>> {
218 None
219 }
220
221 fn from_control_msg(msg: SharedWorkerControlMsg) -> MixedMessage {
222 MixedMessage::Control(msg)
223 }
224
225 fn from_worker_msg(msg: SharedWorkerScriptMsg) -> MixedMessage {
226 MixedMessage::SharedWorker(msg)
227 }
228
229 #[cfg(feature = "devtools")]
230 fn from_devtools_msg(msg: DevtoolScriptControlMsg) -> MixedMessage {
231 MixedMessage::Devtools(msg)
232 }
233
234 fn from_timer_msg() -> MixedMessage {
235 MixedMessage::Timer
236 }
237
238 fn control_receiver(&self) -> &Receiver<SharedWorkerControlMsg> {
239 &self.control_receiver
240 }
241}
242
243impl SharedWorkerGlobalScope {
244 #[allow(clippy::too_many_arguments)]
245 fn new_inherited(
246 init: WorkerGlobalScopeInit,
247 webview_id: WebViewId,
248 worker_name: DOMString,
249 worker_type: WorkerType,
250 worker_url: ServoUrl,
251 worker: TrustedSharedWorkerAddress,
252 parent_event_loop_sender: ScriptEventLoopSender,
253 from_devtools_receiver: Option<RoutedReceiver<WorkerDevtoolsControlMsg>>,
254 runtime: Runtime,
255 own_sender: Sender<SharedWorkerScriptMsg>,
256 receiver: Receiver<SharedWorkerScriptMsg>,
257 closing: Arc<AtomicBool>,
258 image_cache: Arc<dyn ImageCache>,
259 browsing_context: Option<BrowsingContextId>,
260 #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
261 control_receiver: Receiver<SharedWorkerControlMsg>,
262 insecure_requests_policy: InsecureRequestsPolicy,
263 font_context: Arc<FontContext>,
264 debugger_global: Option<&WorkerDebuggerGlobalScope>,
265 storage_key: SharedWorkerStorageKey,
266 constructor_origin: ImmutableOrigin,
267 constructor_url: ServoUrl,
268 credentials: CredentialsMode,
269 extended_lifetime: bool,
270 registration_id: Uuid,
271 ) -> SharedWorkerGlobalScope {
272 SharedWorkerGlobalScope {
273 workerglobalscope: WorkerGlobalScope::new_inherited(
274 init,
275 worker_name,
276 worker_type,
277 worker_url,
278 runtime,
279 from_devtools_receiver,
280 closing,
281 #[cfg(feature = "webgpu")]
282 gpu_id_hub,
283 insecure_requests_policy,
284 font_context,
285 Some(ScriptEventLoopSender::SharedWorker(own_sender.clone())),
286 ),
287 webview_id,
288 task_queue: TaskQueue::new(receiver, own_sender.clone()),
289 own_sender,
290 worker: DomRefCell::new(Some(worker)),
291 parent_event_loop_sender,
292 image_cache,
293 browsing_context,
294 pending_connect: DomRefCell::new(VecDeque::new()),
295 control_receiver,
296 #[cfg(feature = "devtools")]
297 debugger_global: Dom::from_ref(
298 debugger_global.expect("debugger global must exist when devtools is enabled"),
299 ),
300 storage_key,
301 constructor_origin,
302 constructor_url,
303 credentials,
304 extended_lifetime,
305 registration_id,
306 }
307 }
308
309 #[allow(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 worker: TrustedSharedWorkerAddress,
317 parent_event_loop_sender: ScriptEventLoopSender,
318 from_devtools_receiver: Option<RoutedReceiver<WorkerDevtoolsControlMsg>>,
319 runtime: Runtime,
320 own_sender: Sender<SharedWorkerScriptMsg>,
321 receiver: Receiver<SharedWorkerScriptMsg>,
322 closing: Arc<AtomicBool>,
323 image_cache: Arc<dyn ImageCache>,
324 browsing_context: Option<BrowsingContextId>,
325 #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
326 control_receiver: Receiver<SharedWorkerControlMsg>,
327 insecure_requests_policy: InsecureRequestsPolicy,
328 font_context: Arc<FontContext>,
329 debugger_global: Option<&WorkerDebuggerGlobalScope>,
330 storage_key: SharedWorkerStorageKey,
331 constructor_origin: ImmutableOrigin,
332 constructor_url: ServoUrl,
333 credentials: CredentialsMode,
334 extended_lifetime: bool,
335 registration_id: Uuid,
336 cx: &mut js::context::JSContext,
337 ) -> DomRoot<SharedWorkerGlobalScope> {
338 let scope = Box::new(SharedWorkerGlobalScope::new_inherited(
339 init,
340 webview_id,
341 worker_name,
342 worker_type,
343 worker_url,
344 worker,
345 parent_event_loop_sender,
346 from_devtools_receiver,
347 runtime,
348 own_sender,
349 receiver,
350 closing,
351 image_cache,
352 browsing_context,
353 #[cfg(feature = "webgpu")]
354 gpu_id_hub,
355 control_receiver,
356 insecure_requests_policy,
357 font_context,
358 debugger_global,
359 storage_key,
360 constructor_origin,
361 constructor_url,
362 credentials,
363 extended_lifetime,
364 registration_id,
365 ));
366 SharedWorkerGlobalScopeBinding::Wrap::<crate::DomTypeHolder>(cx, &scope.origin(), scope)
367 }
368
369 #[expect(unsafe_code)]
371 #[allow(clippy::too_many_arguments)]
372 pub(crate) fn run_shared_worker_scope(
373 mut init: WorkerGlobalScopeInit,
374 webview_id: WebViewId,
375 browsing_context: Option<BrowsingContextId>,
376 worker_name: DOMString,
377 worker_type: WorkerType,
378 worker_url: UrlWithBlobClaim,
379 worker: TrustedSharedWorkerAddress,
380 parent_event_loop_sender: ScriptEventLoopSender,
381 #[cfg(feature = "devtools")] from_devtools_receiver: GenericReceiver<
382 DevtoolScriptControlMsg,
383 >,
384 own_sender: Sender<SharedWorkerScriptMsg>,
385 receiver: Receiver<SharedWorkerScriptMsg>,
386 worker_load_origin: WorkerScriptLoadOrigin,
387 closing: Arc<AtomicBool>,
388 image_cache: Arc<dyn ImageCache>,
389 #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
390 control_receiver: Receiver<SharedWorkerControlMsg>,
391 setup_sender: Sender<bool>,
392 registration_receiver: Receiver<()>,
393 registration_id: Uuid,
394 credentials: CredentialsMode,
395 extended_lifetime: bool,
396 constructor_origin: ImmutableOrigin,
397 constructor_url: ServoUrl,
398 storage_key: SharedWorkerStorageKey,
399 insecure_requests_policy: InsecureRequestsPolicy,
400 policy_container: Arc<PolicyContainer>,
401 font_context: Arc<FontContext>,
402 ) -> io::Result<JoinHandle<()>> {
403 let event_loop_id = ScriptEventLoopId::installed()
404 .expect("Should always be in a ScriptThread or in a worker");
405 let current_global = GlobalScope::current().expect("No current global object");
406 let origin = current_global.origin().immutable().clone();
407 let referrer = current_global.get_referrer();
408 let is_secure_context = current_global.is_secure_context();
409 let current_global_ancestor_trustworthy = current_global.has_trustworthy_ancestor_origin();
410 let is_nested_browsing_context = current_global.is_nested_browsing_context();
411 let worker_name = worker_name.to_string();
412
413 thread::Builder::new()
414 .name(format!("SWW:{}", worker_url.debug_compact()))
415 .spawn(move || {
416 thread_state::initialize(ThreadState::SCRIPT | ThreadState::IN_WORKER);
420 ScriptEventLoopId::install(event_loop_id);
421
422 let WorkerScriptLoadOrigin {
423 referrer_url,
424 pipeline_id,
425 ..
426 } = worker_load_origin;
427
428 let referrer = referrer_url.map(Referrer::ReferrerUrl).unwrap_or(referrer);
429
430 let request_client = RequestClient {
431 preloaded_resources: PreloadedResources::default(),
432 policy_container: policy_container.clone(),
433 origin: Origin::Origin(origin.clone()),
434 is_nested_browsing_context,
435 insecure_requests_policy,
436 has_trustworthy_ancestor_origin: current_global_ancestor_trustworthy,
437 };
438
439 let event_loop_sender = ScriptEventLoopSender::SharedWorker(own_sender.clone());
440
441 let runtime = Runtime::new(Some(event_loop_sender.clone()));
445 let mut cx = unsafe { runtime.cx() };
449 let cx = &mut cx;
450 #[cfg(feature = "devtools")]
451 let debugger_global = DebuggerGlobalScope::new(
452 pipeline_id,
453 init.to_devtools_sender.clone(),
454 init.from_devtools_sender
455 .clone()
456 .expect("Guaranteed by SharedWorker::Constructor"),
457 init.mem_profiler_chan.clone(),
458 init.time_profiler_chan.clone(),
459 init.script_to_constellation_chan.clone(),
460 init.script_to_embedder_chan.clone(),
461 init.resource_threads.clone(),
462 init.storage_threads.clone(),
463 #[cfg(feature = "webgpu")]
464 gpu_id_hub.clone(),
465 cx,
466 );
467
468 #[cfg(feature = "devtools")]
469 let (devtools_mpsc_port, debugger_global_for_scope, devtools_enabled) = {
470 debugger_global.execute(cx);
471 (
472 Some(from_devtools_receiver.route_preserving_errors()),
473 Some(&*debugger_global),
474 init.to_devtools_sender.is_some(),
475 )
476 };
477 #[cfg(not(feature = "devtools"))]
478 let (devtools_mpsc_port, debugger_global_for_scope, devtools_enabled) =
479 (None, None, false);
480 if worker_url.scheme() == "data" {
482 if is_secure_context {
483 init.origin = ImmutableOrigin::new_opaque_data_url_worker();
484 } else {
485 init.origin = ImmutableOrigin::new_opaque();
486 }
487 }
488 let global = SharedWorkerGlobalScope::new(
491 init,
492 webview_id,
493 worker_name.into(),
494 worker_type,
495 worker_url.url(),
496 worker,
497 parent_event_loop_sender,
498 devtools_mpsc_port,
499 runtime,
500 own_sender,
501 receiver,
502 closing,
503 image_cache,
504 browsing_context,
505 #[cfg(feature = "webgpu")]
506 gpu_id_hub,
507 control_receiver,
508 insecure_requests_policy,
509 font_context,
510 debugger_global_for_scope,
511 storage_key,
512 constructor_origin,
513 constructor_url,
514 credentials,
515 extended_lifetime,
516 registration_id,
517 cx,
518 );
519
520 struct ClearJsRuntime<'a>(&'a WorkerGlobalScope);
523 impl Drop for ClearJsRuntime<'_> {
524 fn drop(&mut self) {
525 self.0.clear_js_runtime();
526 }
527 }
528
529 let scope = global.upcast::<WorkerGlobalScope>();
530 let _clear_js_runtime = ClearJsRuntime(scope);
531 let global_scope = global.upcast::<GlobalScope>();
532
533 let worker_is_secure_context = global_scope.is_secure_context();
535 #[cfg(feature = "devtools")]
536 if devtools_enabled {
537 debugger_global.fire_add_debuggee(
538 cx,
539 global_scope,
540 pipeline_id,
541 Some(scope.worker_id()),
542 );
543 }
544
545 if setup_sender.send(worker_is_secure_context).is_err() {
546 return;
547 }
548
549 if registration_receiver.recv().is_err() {
550 return;
551 }
552 let _registration_cleanup = SharedWorkerRegistrationCleanup { registration_id };
555
556 match worker_type {
560 WorkerType::Classic => {
561 fetch_a_classic_worker_script(
562 scope,
563 worker_url,
564 request_client,
565 Destination::SharedWorker,
566 Some(webview_id),
567 referrer,
568 );
569 },
570 WorkerType::Module => {
571 let worker_scope = DomRoot::from_ref(scope);
572 fetch_a_module_script_graph(
573 cx,
574 global_scope,
575 worker_url,
576 request_client,
577 Destination::SharedWorker,
578 referrer,
579 credentials,
580 Some(IntroductionType::WORKER),
581 move |cx, module_tree| {
582 worker_scope.on_complete(cx, module_tree.map(Script::Module));
583 },
584 );
585 },
586 }
587
588 let reporter_name = format!("shared-worker-reporter-{}", scope.worker_id());
589 scope
590 .upcast::<GlobalScope>()
591 .mem_profiler_chan()
592 .run_with_memory_reporting(
593 || {
594 while !scope.is_closing() {
596 run_worker_event_loop(&*global, None, cx);
597 }
598 },
599 reporter_name,
600 event_loop_sender,
601 CommonScriptMsg::CollectReports,
602 );
603 })
604 }
605
606 pub(crate) fn event_loop_sender(&self) -> ScriptEventLoopSender {
607 ScriptEventLoopSender::SharedWorker(self.own_sender.clone())
608 }
609
610 pub(crate) fn webview_id(&self) -> WebViewId {
611 self.webview_id
612 }
613
614 pub(crate) fn image_cache(&self) -> Arc<dyn ImageCache> {
615 self.image_cache.clone()
616 }
617
618 pub(crate) fn browsing_context(&self) -> Option<BrowsingContextId> {
619 self.browsing_context
620 }
621
622 pub(crate) fn new_script_pair(&self) -> (ScriptEventLoopSender, ScriptEventLoopReceiver) {
623 let (sender, receiver) = unbounded();
624 (
625 ScriptEventLoopSender::SharedWorker(sender),
626 ScriptEventLoopReceiver::SharedWorker(receiver),
627 )
628 }
629
630 pub(crate) fn forward_simple_error_at_worker(&self) {
632 SharedWorker::unregister_shared_worker(self.registration_id);
633 let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
634 let worker = self.worker.borrow().clone().expect("worker must be set");
635 if let Err(error) = self.parent_event_loop_sender.send(CommonScriptMsg::Task(
638 WorkerEvent,
639 Box::new(SimpleWorkerErrorHandler::new(worker)),
640 Some(pipeline_id),
641 TaskSourceName::DOMManipulation,
642 )) {
643 log::warn!("Failed to send forward simple error to parent event loop: {error}.")
646 }
647 }
648
649 pub(crate) fn report_csp_violations(&self, violations: Vec<Violation>) {
650 let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
651 self.parent_event_loop_sender
652 .send(CommonScriptMsg::ReportCspViolations(
653 pipeline_id,
654 violations,
655 ))
656 .unwrap_or_else(|error| {
657 log::warn!("Failed to send CSP violations to parent event loop: {error}");
658 });
659 }
660
661 pub(crate) fn enable_outside_port_message_queue(&self) {
663 let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
664 let worker = self.worker.borrow().clone().expect("worker must be set");
665
666 if let Err(error) = self.parent_event_loop_sender.send(CommonScriptMsg::Task(
667 WorkerEvent,
668 Box::new(
669 task!(sharedworker_enable_outside_port_message_queue: move |cx| {
670 SharedWorker::enable_outside_port_message_queue(worker, cx);
671 }),
672 ),
673 Some(pipeline_id),
674 TaskSourceName::DOMManipulation,
675 )) {
676 log::warn!(
679 "Failed to send enable outside port message queue to parent event loop: {error}."
680 )
681 }
682 }
683
684 fn handle_connect(
685 &self,
686 port_impl: MessagePortImpl,
687 cx: &mut JSContext,
688 ) -> DomRoot<MessagePort> {
689 let inside_port = MessagePort::new_transferred(
691 cx,
692 self.upcast::<GlobalScope>(),
693 *port_impl.message_port_id(),
694 port_impl.entangled_port_id(),
695 );
696 self.upcast::<GlobalScope>()
697 .track_message_port(&inside_port, Some(port_impl));
698 inside_port
699 }
700
701 fn dispatch_connect_event(&self, inside_port: &MessagePort) {
703 let worker_global = Trusted::new(self);
704 let inside_port = Trusted::new(inside_port);
705
706 self.upcast::<GlobalScope>()
707 .task_manager()
708 .dom_manipulation_task_source()
709 .queue(task!(sharedworker_connect_event: move |cx| {
710 let worker_global = worker_global.root();
711 let worker_global = &*worker_global;
712 let inside_port = inside_port.root();
713
714 rooted!(&in(cx) let mut data = UndefinedValue());
715 DOMString::new().to_jsval(cx, data.handle_mut());
716
717 let source = WindowProxyOrMessagePortOrServiceWorker::MessagePort(
718 inside_port.clone(),
719 );
720 let event = MessageEvent::new(
721 cx,
722 worker_global.upcast::<GlobalScope>(),
723 Atom::from("connect"),
724 false,
725 false,
726 data.handle(),
727 DOMString::new(),
728 Some(&source),
729 DOMString::new(),
730 vec![inside_port],
731 );
732
733 event
734 .upcast::<Event>()
735 .fire(cx, worker_global.upcast::<EventTarget>());
736 }));
737 }
738
739 pub(crate) fn fire_pending_connect(&self, _cx: &mut JSContext) {
740 loop {
741 let inside_port = self
742 .pending_connect
743 .borrow_mut()
744 .pop_front()
745 .map(|inside_port| inside_port.as_rooted());
746 let Some(inside_port) = inside_port else {
747 break;
748 };
749 if self.upcast::<WorkerGlobalScope>().is_closing() {
750 return;
751 }
752 self.dispatch_connect_event(&inside_port);
754 }
755 }
756
757 fn handle_script_event(&self, msg: SharedWorkerScriptMsg, cx: &mut JSContext) {
758 match msg {
759 SharedWorkerScriptMsg::CommonWorker(WorkerScriptMsg::Common(msg)) => {
760 self.upcast::<WorkerGlobalScope>().process_event(msg, cx);
761 },
762 SharedWorkerScriptMsg::Connect(port_impl) => {
763 let inside_port = self.handle_connect(port_impl, cx);
764 if self.upcast::<WorkerGlobalScope>().is_execution_ready() {
765 self.dispatch_connect_event(&inside_port);
767 } else {
768 self.pending_connect
770 .borrow_mut()
771 .push_back(Dom::from_ref(&*inside_port));
772 }
773 },
774 SharedWorkerScriptMsg::CommonWorker(WorkerScriptMsg::DOMMessage(_)) => {
775 debug_assert!(
778 false,
779 "SharedWorkerGlobalScope does not support direct DOMMessage dispatch"
780 );
781 },
782 SharedWorkerScriptMsg::WakeUp => {},
783 }
784 }
785
786 fn handle_mixed_message(&self, msg: MixedMessage, cx: &mut JSContext) -> bool {
787 if self.upcast::<WorkerGlobalScope>().is_closing() {
788 return false;
789 }
790
791 match msg {
792 #[cfg(feature = "devtools")]
793 MixedMessage::Devtools(msg) => match msg {
794 DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, _bool_val) => {},
795 DevtoolScriptControlMsg::Eval(code, id, frame_actor_id, eager, reply) => {
796 self.debugger_global.fire_eval(
797 cx,
798 code.into(),
799 id,
800 Some(self.upcast::<WorkerGlobalScope>().worker_id()),
801 frame_actor_id,
802 eager,
803 reply,
804 );
805 },
806 _ => debug!("got an unusable devtools control message inside the worker!"),
807 },
808 MixedMessage::SharedWorker(msg) => {
809 self.handle_script_event(msg, cx);
810 },
811 MixedMessage::Control(SharedWorkerControlMsg::Exit) => {
812 return false;
813 },
814 MixedMessage::Timer => {},
815 }
816
817 true
818 }
819}
820
821impl SharedWorkerGlobalScopeMethods<crate::DomTypeHolder> for SharedWorkerGlobalScope {
822 fn Name(&self) -> DOMString {
824 self.workerglobalscope.worker_name()
827 }
828
829 fn Close(&self) {
831 self.upcast::<WorkerGlobalScope>().close()
833 }
834
835 event_handler!(connect, GetOnconnect, SetOnconnect);
837}
838
839impl HasOrigin for SharedWorkerGlobalScope {
840 fn origin(&self) -> MutableOrigin {
841 self.upcast::<WorkerGlobalScope>().origin()
842 }
843}