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