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::jsval::UndefinedValue;
18use net_traits::blob_url_store::UrlWithBlobClaim;
19use net_traits::image_cache::ImageCache;
20use net_traits::policy_container::PolicyContainer;
21use net_traits::request::{
22 CredentialsMode, Destination, InsecureRequestsPolicy, Origin, PreloadedResources, Referrer,
23 RequestClient,
24};
25use script_bindings::cell::DomRefCell;
26use script_bindings::conversions::SafeToJSValConvertible;
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::script_module::fetch_a_module_worker_script_graph;
61use crate::script_runtime::Runtime;
62use crate::script_runtime::ScriptThreadEventCategory::WorkerEvent;
63use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue};
64use crate::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: Option<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: Option<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: Option<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_worker_script_graph(
540 cx,
541 global_scope,
542 worker_url.url(),
543 request_client,
544 Destination::SharedWorker,
545 referrer,
546 credentials,
547 move |cx, module_tree| {
548 worker_scope.on_complete(cx, module_tree.map(Script::Module));
549 },
550 );
551 },
552 }
553
554 let reporter_name = format!("shared-worker-reporter-{}", worker_id);
555 scope
556 .upcast::<GlobalScope>()
557 .mem_profiler_chan()
558 .run_with_memory_reporting(
559 || {
560 while !scope.is_closing() {
562 run_worker_event_loop(&*global, None, cx);
563 }
564 },
565 reporter_name,
566 event_loop_sender,
567 CommonScriptMsg::CollectReports,
568 );
569
570 scope.clear_js_runtime();
571 })
572 }
573
574 pub(crate) fn event_loop_sender(&self) -> ScriptEventLoopSender {
575 ScriptEventLoopSender::SharedWorker(self.own_sender.clone())
576 }
577
578 pub(crate) fn webview_id(&self) -> WebViewId {
579 self.webview_id
580 }
581
582 pub(crate) fn image_cache(&self) -> Arc<dyn ImageCache> {
583 self.image_cache.clone()
584 }
585
586 pub(crate) fn browsing_context(&self) -> Option<BrowsingContextId> {
587 self.browsing_context
588 }
589
590 pub(crate) fn new_script_pair(&self) -> (ScriptEventLoopSender, ScriptEventLoopReceiver) {
591 let (sender, receiver) = unbounded();
592 (
593 ScriptEventLoopSender::SharedWorker(sender),
594 ScriptEventLoopReceiver::SharedWorker(receiver),
595 )
596 }
597
598 pub(crate) fn forward_simple_error_at_worker(&self) {
600 SharedWorker::unregister_shared_worker(self.registration_id);
601 let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
602 let worker = self.worker.borrow().clone().expect("worker must be set");
603 self.parent_event_loop_sender
605 .send(CommonScriptMsg::Task(
606 WorkerEvent,
607 Box::new(SimpleWorkerErrorHandler::new(worker)),
608 Some(pipeline_id),
609 TaskSourceName::DOMManipulation,
610 ))
611 .expect("Sending to parent failed");
612 }
613
614 pub(crate) fn report_csp_violations(&self, violations: Vec<Violation>) {
615 let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
616 self.parent_event_loop_sender
617 .send(CommonScriptMsg::ReportCspViolations(
618 pipeline_id,
619 violations,
620 ))
621 .unwrap_or_else(|error| {
622 log::warn!("Failed to send CSP violations to parent event loop: {error}");
623 });
624 }
625
626 pub(crate) fn enable_outside_port_message_queue(&self) {
628 let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
629 let worker = self.worker.borrow().clone().expect("worker must be set");
630
631 self.parent_event_loop_sender
632 .send(CommonScriptMsg::Task(
633 WorkerEvent,
634 Box::new(
635 task!(sharedworker_enable_outside_port_message_queue: move |cx| {
636 SharedWorker::enable_outside_port_message_queue(worker, cx);
637 }),
638 ),
639 Some(pipeline_id),
640 TaskSourceName::DOMManipulation,
641 ))
642 .expect("Sending to parent failed");
643 }
644
645 fn handle_connect(
646 &self,
647 port_impl: MessagePortImpl,
648 cx: &mut JSContext,
649 ) -> DomRoot<MessagePort> {
650 let inside_port = MessagePort::new_transferred(
652 cx,
653 self.upcast::<GlobalScope>(),
654 *port_impl.message_port_id(),
655 port_impl.entangled_port_id(),
656 );
657 self.upcast::<GlobalScope>()
658 .track_message_port(&inside_port, Some(port_impl));
659 inside_port
660 }
661
662 fn dispatch_connect_event(&self, inside_port: &MessagePort) {
664 let worker_global = Trusted::new(self);
665 let inside_port = Trusted::new(inside_port);
666
667 self.upcast::<GlobalScope>()
668 .task_manager()
669 .dom_manipulation_task_source()
670 .queue(task!(sharedworker_connect_event: move |cx| {
671 let worker_global = worker_global.root();
672 let worker_global = &*worker_global;
673 let inside_port = inside_port.root();
674
675 rooted!(&in(cx) let mut data = UndefinedValue());
676 DOMString::from("").safe_to_jsval(cx,
677 data.handle_mut(),
678 );
679
680 let source = WindowProxyOrMessagePortOrServiceWorker::MessagePort(
681 inside_port.clone(),
682 );
683 let event = MessageEvent::new(
684 cx,
685 worker_global.upcast::<GlobalScope>(),
686 Atom::from("connect"),
687 false,
688 false,
689 data.handle(),
690 DOMString::from(""),
691 Some(&source),
692 DOMString::new(),
693 vec![inside_port],
694 );
695
696 event
697 .upcast::<Event>()
698 .fire(cx, worker_global.upcast::<EventTarget>());
699 }));
700 }
701
702 pub(crate) fn fire_pending_connect(&self, _cx: &mut JSContext) {
703 loop {
704 let inside_port = self
705 .pending_connect
706 .borrow_mut()
707 .pop_front()
708 .map(|inside_port| inside_port.as_rooted());
709 let Some(inside_port) = inside_port else {
710 break;
711 };
712 if self.upcast::<WorkerGlobalScope>().is_closing() {
713 return;
714 }
715 self.dispatch_connect_event(&inside_port);
717 }
718 }
719
720 fn handle_script_event(&self, msg: SharedWorkerScriptMsg, cx: &mut JSContext) {
721 match msg {
722 SharedWorkerScriptMsg::CommonWorker(WorkerScriptMsg::Common(msg)) => {
723 self.upcast::<WorkerGlobalScope>().process_event(msg, cx);
724 },
725 SharedWorkerScriptMsg::Connect(port_impl) => {
726 let inside_port = self.handle_connect(port_impl, cx);
727 if self.upcast::<WorkerGlobalScope>().is_execution_ready() {
728 self.dispatch_connect_event(&inside_port);
730 } else {
731 self.pending_connect
733 .borrow_mut()
734 .push_back(Dom::from_ref(&*inside_port));
735 }
736 },
737 SharedWorkerScriptMsg::CommonWorker(WorkerScriptMsg::DOMMessage(_)) => {
738 debug_assert!(
741 false,
742 "SharedWorkerGlobalScope does not support direct DOMMessage dispatch"
743 );
744 },
745 SharedWorkerScriptMsg::WakeUp => {},
746 }
747 }
748
749 fn handle_mixed_message(&self, msg: MixedMessage, cx: &mut JSContext) -> bool {
750 if self.upcast::<WorkerGlobalScope>().is_closing() {
751 return false;
752 }
753
754 match msg {
755 MixedMessage::Devtools(msg) => match msg {
756 DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, _bool_val) => {},
757 DevtoolScriptControlMsg::Eval(code, id, frame_actor_id, reply) => {
758 self.debugger_global.fire_eval(
759 cx,
760 code.into(),
761 id,
762 Some(self.upcast::<WorkerGlobalScope>().worker_id()),
763 frame_actor_id,
764 reply,
765 );
766 },
767 _ => debug!("got an unusable devtools control message inside the worker!"),
768 },
769 MixedMessage::SharedWorker(msg) => {
770 self.handle_script_event(msg, cx);
771 },
772 MixedMessage::Control(SharedWorkerControlMsg::Exit) => {
773 return false;
774 },
775 MixedMessage::Timer => {},
776 }
777
778 true
779 }
780}
781
782impl SharedWorkerGlobalScopeMethods<crate::DomTypeHolder> for SharedWorkerGlobalScope {
783 fn Name(&self) -> DOMString {
785 self.workerglobalscope.worker_name()
788 }
789
790 fn Close(&self) {
792 self.upcast::<WorkerGlobalScope>().close()
794 }
795
796 event_handler!(connect, GetOnconnect, SetOnconnect);
798}
799
800impl HasOrigin for SharedWorkerGlobalScope {
801 fn origin(&self) -> MutableOrigin {
802 self.upcast::<WorkerGlobalScope>().origin()
803 }
804}