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