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