1use std::cell::{Cell, OnceCell, Ref};
6use std::collections::hash_map::Entry;
7use std::collections::{HashMap, HashSet, VecDeque};
8use std::ffi::CStr;
9use std::ops::Index;
10use std::rc::Rc;
11use std::sync::atomic::{AtomicBool, Ordering};
12use std::sync::{Arc, Mutex};
13use std::thread::JoinHandle;
14use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
15use std::{mem, ptr};
16
17use base::id::{
18 BlobId, BroadcastChannelRouterId, MessagePortId, MessagePortRouterId, PipelineId,
19 ServiceWorkerId, ServiceWorkerRegistrationId, WebViewId,
20};
21use constellation_traits::{
22 BlobData, BlobImpl, BroadcastChannelMsg, FileBlob, MessagePortImpl, MessagePortMsg,
23 PortMessageTask, ScriptToConstellationChan, ScriptToConstellationMessage,
24};
25use content_security_policy::CspList;
26use crossbeam_channel::Sender;
27use devtools_traits::{PageError, ScriptToDevtoolsControlMsg};
28use dom_struct::dom_struct;
29use embedder_traits::{EmbedderMsg, JavaScriptEvaluationError, ScriptToEmbedderChan};
30use fonts::FontContext;
31use ipc_channel::ipc::{self, IpcSender};
32use ipc_channel::router::ROUTER;
33use js::glue::{IsWrapper, UnwrapObjectDynamic};
34use js::jsapi::{
35 Compile1, CurrentGlobalOrNull, DelazificationOption, GetNonCCWObjectGlobal, HandleObject, Heap,
36 InstantiateGlobalStencil, InstantiateOptions, JSContext, JSObject, JSScript, SetScriptPrivate,
37};
38use js::jsval::{PrivateValue, UndefinedValue};
39use js::panic::maybe_resume_unwind;
40use js::rust::wrappers::{JS_ExecuteScript, JS_GetScriptPrivate};
41use js::rust::{
42 CompileOptionsWrapper, CustomAutoRooter, CustomAutoRooterGuard, HandleValue,
43 MutableHandleValue, ParentRuntime, Runtime, get_object_class, transform_str_to_source_text,
44};
45use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL};
46use net_traits::blob_url_store::{BlobBuf, get_blob_origin};
47use net_traits::filemanager_thread::{
48 FileManagerResult, FileManagerThreadMsg, ReadFileProgress, RelativePos,
49};
50use net_traits::image_cache::ImageCache;
51use net_traits::policy_container::PolicyContainer;
52use net_traits::request::{InsecureRequestsPolicy, Referrer, RequestBuilder};
53use net_traits::response::HttpsState;
54use net_traits::{
55 CoreResourceMsg, CoreResourceThread, FetchResponseListener, IpcSend, ReferrerPolicy,
56 ResourceThreads, fetch_async,
57};
58use profile_traits::{ipc as profile_ipc, mem as profile_mem, time as profile_time};
59use rustc_hash::{FxBuildHasher, FxHashMap};
60use script_bindings::interfaces::GlobalScopeHelpers;
61use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
62use timers::{TimerEventRequest, TimerId};
63use uuid::Uuid;
64#[cfg(feature = "webgpu")]
65use webgpu_traits::{DeviceLostReason, WebGPUDevice};
66
67use super::bindings::codegen::Bindings::MessagePortBinding::StructuredSerializeOptions;
68#[cfg(feature = "webgpu")]
69use super::bindings::codegen::Bindings::WebGPUBinding::GPUDeviceLostReason;
70use super::bindings::error::Fallible;
71use super::bindings::trace::{HashMapTracedValues, RootedTraceableBox};
72use super::serviceworkerglobalscope::ServiceWorkerGlobalScope;
73use super::transformstream::CrossRealmTransform;
74use crate::dom::bindings::cell::{DomRefCell, RefMut};
75use crate::dom::bindings::codegen::Bindings::BroadcastChannelBinding::BroadcastChannelMethods;
76use crate::dom::bindings::codegen::Bindings::EventSourceBinding::EventSource_Binding::EventSourceMethods;
77use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function;
78use crate::dom::bindings::codegen::Bindings::NotificationBinding::NotificationPermissionCallback;
79use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::{
80 PermissionName, PermissionState,
81};
82use crate::dom::bindings::codegen::Bindings::ReportingObserverBinding::Report;
83use crate::dom::bindings::codegen::Bindings::VoidFunctionBinding::VoidFunction;
84use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
85use crate::dom::bindings::codegen::Bindings::WorkerGlobalScopeBinding::WorkerGlobalScopeMethods;
86use crate::dom::bindings::conversions::{root_from_object, root_from_object_static};
87use crate::dom::bindings::error::{Error, ErrorInfo, report_pending_exception};
88use crate::dom::bindings::frozenarray::CachedFrozenArray;
89use crate::dom::bindings::inheritance::Castable;
90use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
91use crate::dom::bindings::reflector::{DomGlobal, DomObject};
92use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
93use crate::dom::bindings::settings_stack::{AutoEntryScript, entry_global, incumbent_global};
94use crate::dom::bindings::str::DOMString;
95use crate::dom::bindings::structuredclone;
96use crate::dom::bindings::trace::CustomTraceable;
97use crate::dom::bindings::weakref::{DOMTracker, WeakRef};
98use crate::dom::blob::Blob;
99use crate::dom::broadcastchannel::BroadcastChannel;
100use crate::dom::crypto::Crypto;
101use crate::dom::dedicatedworkerglobalscope::{
102 DedicatedWorkerControlMsg, DedicatedWorkerGlobalScope,
103};
104use crate::dom::errorevent::ErrorEvent;
105use crate::dom::event::{Event, EventBubbles, EventCancelable};
106use crate::dom::eventsource::EventSource;
107use crate::dom::eventtarget::EventTarget;
108use crate::dom::file::File;
109use crate::dom::html::htmlscriptelement::{ScriptId, SourceCode};
110use crate::dom::messageport::MessagePort;
111use crate::dom::paintworkletglobalscope::PaintWorkletGlobalScope;
112use crate::dom::performance::Performance;
113use crate::dom::performanceobserver::VALID_ENTRY_TYPES;
114use crate::dom::promise::Promise;
115use crate::dom::readablestream::{CrossRealmTransformReadable, ReadableStream};
116use crate::dom::reportingobserver::ReportingObserver;
117use crate::dom::serviceworker::ServiceWorker;
118use crate::dom::serviceworkerregistration::ServiceWorkerRegistration;
119use crate::dom::trustedtypepolicyfactory::TrustedTypePolicyFactory;
120use crate::dom::types::{CookieStore, DebuggerGlobalScope, MessageEvent};
121use crate::dom::underlyingsourcecontainer::UnderlyingSourceType;
122#[cfg(feature = "webgpu")]
123use crate::dom::webgpu::gpudevice::GPUDevice;
124#[cfg(feature = "webgpu")]
125use crate::dom::webgpu::identityhub::IdentityHub;
126use crate::dom::window::Window;
127use crate::dom::workerglobalscope::WorkerGlobalScope;
128use crate::dom::workletglobalscope::WorkletGlobalScope;
129use crate::dom::writablestream::CrossRealmTransformWritable;
130use crate::messaging::{CommonScriptMsg, ScriptEventLoopReceiver, ScriptEventLoopSender};
131use crate::microtask::{Microtask, MicrotaskQueue, UserMicrotask};
132use crate::network_listener::{NetworkListener, PreInvoke};
133use crate::realms::{InRealm, enter_realm};
134use crate::script_module::{
135 DynamicModuleList, ImportMap, ModuleScript, ModuleTree, ResolvedModule, ScriptFetchOptions,
136};
137use crate::script_runtime::{CanGc, JSContext as SafeJSContext, ThreadSafeJSContext};
138use crate::script_thread::{ScriptThread, with_script_thread};
139use crate::task_manager::TaskManager;
140use crate::task_source::SendableTaskSource;
141use crate::timers::{
142 IsInterval, OneshotTimerCallback, OneshotTimerHandle, OneshotTimers, TimerCallback,
143 TimerEventId, TimerSource,
144};
145use crate::unminify::unminified_path;
146
147#[derive(JSTraceable)]
148pub(crate) struct AutoCloseWorker {
149 closing: Arc<AtomicBool>,
151 join_handle: Option<JoinHandle<()>>,
153 #[no_trace]
156 control_sender: Sender<DedicatedWorkerControlMsg>,
157 #[no_trace]
159 context: ThreadSafeJSContext,
160}
161
162impl Drop for AutoCloseWorker {
163 fn drop(&mut self) {
165 self.closing.store(true, Ordering::SeqCst);
167
168 if self
169 .control_sender
170 .send(DedicatedWorkerControlMsg::Exit)
171 .is_err()
172 {
173 warn!("Couldn't send an exit message to a dedicated worker.");
174 }
175
176 self.context.request_interrupt_callback();
177
178 if self
181 .join_handle
182 .take()
183 .expect("No handle to join on worker.")
184 .join()
185 .is_err()
186 {
187 warn!("Failed to join on dedicated worker thread.");
188 }
189 }
190}
191
192#[dom_struct]
193pub(crate) struct GlobalScope {
194 eventtarget: EventTarget,
195 crypto: MutNullableDom<Crypto>,
196
197 task_manager: OnceCell<TaskManager>,
199
200 message_port_state: DomRefCell<MessagePortState>,
202
203 broadcast_channel_state: DomRefCell<BroadcastChannelState>,
205
206 blob_state: DomRefCell<HashMapTracedValues<BlobId, BlobInfo, FxBuildHasher>>,
208
209 registration_map: DomRefCell<
211 HashMapTracedValues<
212 ServiceWorkerRegistrationId,
213 Dom<ServiceWorkerRegistration>,
214 FxBuildHasher,
215 >,
216 >,
217
218 cookie_store: MutNullableDom<CookieStore>,
220
221 worker_map: DomRefCell<HashMapTracedValues<ServiceWorkerId, Dom<ServiceWorker>, FxBuildHasher>>,
223
224 #[no_trace]
226 pipeline_id: PipelineId,
227
228 devtools_wants_updates: Cell<bool>,
231
232 console_timers: DomRefCell<HashMap<DOMString, Instant>>,
234
235 #[ignore_malloc_size_of = "mozjs"]
238 module_map: DomRefCell<HashMapTracedValues<ServoUrl, Rc<ModuleTree>>>,
239
240 #[ignore_malloc_size_of = "mozjs"]
241 inline_module_map: DomRefCell<FxHashMap<ScriptId, Rc<ModuleTree>>>,
242
243 #[no_trace]
245 devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
246
247 #[ignore_malloc_size_of = "channels are hard"]
249 #[no_trace]
250 mem_profiler_chan: profile_mem::ProfilerChan,
251
252 #[ignore_malloc_size_of = "channels are hard"]
254 #[no_trace]
255 time_profiler_chan: profile_time::ProfilerChan,
256
257 #[ignore_malloc_size_of = "channels are hard"]
259 #[no_trace]
260 script_to_constellation_chan: ScriptToConstellationChan,
261
262 #[ignore_malloc_size_of = "channels are hard"]
264 #[no_trace]
265 script_to_embedder_chan: ScriptToEmbedderChan,
266
267 in_error_reporting_mode: Cell<bool>,
269
270 #[no_trace]
273 resource_threads: ResourceThreads,
274
275 timers: OnceCell<OneshotTimers>,
278
279 #[no_trace]
281 origin: MutableOrigin,
282
283 #[no_trace]
285 creation_url: ServoUrl,
286
287 #[no_trace]
289 top_level_creation_url: Option<ServoUrl>,
290
291 permission_state_invocation_results: DomRefCell<HashMap<PermissionName, PermissionState>>,
293
294 #[ignore_malloc_size_of = "Rc<T> is hard"]
301 microtask_queue: Rc<MicrotaskQueue>,
302
303 #[ignore_malloc_size_of = "Arc"]
305 list_auto_close_worker: DomRefCell<Vec<AutoCloseWorker>>,
306
307 event_source_tracker: DOMTracker<EventSource>,
309
310 #[ignore_malloc_size_of = "mozjs"]
319 #[allow(clippy::vec_box)]
322 uncaught_rejections: DomRefCell<Vec<Box<Heap<*mut JSObject>>>>,
323
324 #[ignore_malloc_size_of = "mozjs"]
330 #[allow(clippy::vec_box)]
333 consumed_rejections: DomRefCell<Vec<Box<Heap<*mut JSObject>>>>,
334
335 #[ignore_malloc_size_of = "defined in wgpu"]
337 #[no_trace]
338 #[cfg(feature = "webgpu")]
339 gpu_id_hub: Arc<IdentityHub>,
340
341 #[cfg(feature = "webgpu")]
343 gpu_devices: DomRefCell<HashMapTracedValues<WebGPUDevice, WeakRef<GPUDevice>, FxBuildHasher>>,
344
345 #[ignore_malloc_size_of = "mozjs"]
347 frozen_supported_performance_entry_types: CachedFrozenArray,
348
349 #[no_trace]
351 https_state: Cell<HttpsState>,
352
353 console_group_stack: DomRefCell<Vec<DOMString>>,
355
356 console_count_map: DomRefCell<HashMap<DOMString, usize>>,
360
361 dynamic_modules: DomRefCell<DynamicModuleList>,
363
364 inherited_secure_context: Option<bool>,
366
367 unminified_js_dir: Option<String>,
370
371 #[ignore_malloc_size_of = "Rc<T> is hard"]
376 byte_length_queuing_strategy_size_function: OnceCell<Rc<Function>>,
377
378 #[ignore_malloc_size_of = "Rc<T> is hard"]
383 count_queuing_strategy_size_function: OnceCell<Rc<Function>>,
384
385 #[ignore_malloc_size_of = "Rc<T> is hard"]
386 notification_permission_request_callback_map:
387 DomRefCell<HashMap<String, Rc<NotificationPermissionCallback>>>,
388
389 import_map: DomRefCell<ImportMap>,
394
395 resolved_module_set: DomRefCell<HashSet<ResolvedModule>>,
397
398 #[conditional_malloc_size_of]
402 #[no_trace]
403 font_context: Option<Arc<FontContext>>,
404}
405
406struct MessageListener {
408 task_source: SendableTaskSource,
409 context: Trusted<GlobalScope>,
410}
411
412struct BroadcastListener {
414 task_source: SendableTaskSource,
415 context: Trusted<GlobalScope>,
416}
417
418type FileListenerCallback = Box<dyn Fn(Rc<Promise>, Fallible<Vec<u8>>) + Send>;
419
420struct FileListener {
422 state: Option<FileListenerState>,
426 task_source: SendableTaskSource,
427}
428
429enum FileListenerTarget {
430 Promise(TrustedPromise, FileListenerCallback),
431 Stream(Trusted<ReadableStream>),
432}
433
434enum FileListenerState {
435 Empty(FileListenerTarget),
436 Receiving(Vec<u8>, FileListenerTarget),
437}
438
439#[derive(JSTraceable, MallocSizeOf)]
440pub(crate) enum BlobTracker {
442 File(WeakRef<File>),
444 Blob(WeakRef<Blob>),
446}
447
448#[derive(JSTraceable, MallocSizeOf)]
449pub(crate) struct BlobInfo {
451 tracker: BlobTracker,
453 #[no_trace]
455 blob_impl: BlobImpl,
456 has_url: bool,
459}
460
461enum BlobResult {
465 Bytes(Vec<u8>),
466 File(Uuid, usize),
467}
468
469#[derive(JSTraceable, MallocSizeOf)]
471#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
472pub(crate) struct ManagedMessagePort {
473 dom_port: Dom<MessagePort>,
475 #[no_trace]
480 port_impl: Option<MessagePortImpl>,
481 pending: bool,
485 explicitly_closed: bool,
488 cross_realm_transform: Option<CrossRealmTransform>,
491}
492
493#[derive(JSTraceable, MallocSizeOf)]
495#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
496pub(crate) enum BroadcastChannelState {
497 Managed(
502 #[no_trace] BroadcastChannelRouterId,
503 HashMap<DOMString, VecDeque<Dom<BroadcastChannel>>>,
505 ),
506 UnManaged,
508}
509
510#[derive(JSTraceable, MallocSizeOf)]
512#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
513pub(crate) enum MessagePortState {
514 Managed(
516 #[no_trace] MessagePortRouterId,
517 HashMapTracedValues<MessagePortId, ManagedMessagePort, FxBuildHasher>,
518 ),
519 UnManaged,
521}
522
523impl BroadcastListener {
524 fn handle(&self, event: BroadcastChannelMsg) {
527 let context = self.context.clone();
528
529 self.task_source
535 .queue(task!(broadcast_message_event: move || {
536 let global = context.root();
537 global.broadcast_message_event(event, None);
540 }));
541 }
542}
543
544impl MessageListener {
545 fn notify(&self, msg: MessagePortMsg) {
549 match msg {
550 MessagePortMsg::CompleteTransfer(ports) => {
551 let context = self.context.clone();
552 self.task_source.queue(
553 task!(process_complete_transfer: move || {
554 let global = context.root();
555
556 let router_id = match global.port_router_id() {
557 Some(router_id) => router_id,
558 None => {
559 let _ = global.script_to_constellation_chan().send(
562 ScriptToConstellationMessage::MessagePortTransferResult(None, vec![], ports),
563 );
564 return;
565 }
566 };
567
568 let mut succeeded = vec![];
569 let mut failed = FxHashMap::default();
570
571 for (id, info) in ports.into_iter() {
572 if global.is_managing_port(&id) {
573 succeeded.push(id);
574 global.complete_port_transfer(
575 id,
576 info.port_message_queue,
577 info.disentangled,
578 CanGc::note()
579 );
580 } else {
581 failed.insert(id, info);
582 }
583 }
584 let _ = global.script_to_constellation_chan().send(
585 ScriptToConstellationMessage::MessagePortTransferResult(Some(router_id), succeeded, failed),
586 );
587 })
588 );
589 },
590 MessagePortMsg::CompletePendingTransfer(port_id, info) => {
591 let context = self.context.clone();
592 self.task_source.queue(task!(complete_pending: move || {
593 let global = context.root();
594 global.complete_port_transfer(port_id, info.port_message_queue, info.disentangled, CanGc::note());
595 }));
596 },
597 MessagePortMsg::CompleteDisentanglement(port_id) => {
598 let context = self.context.clone();
599 self.task_source
600 .queue(task!(try_complete_disentanglement: move || {
601 let global = context.root();
602 global.try_complete_disentanglement(port_id, CanGc::note());
603 }));
604 },
605 MessagePortMsg::NewTask(port_id, task) => {
606 let context = self.context.clone();
607 self.task_source.queue(task!(process_new_task: move || {
608 let global = context.root();
609 global.route_task_to_port(port_id, task, CanGc::note());
610 }));
611 },
612 }
613 }
614}
615
616fn stream_handle_incoming(stream: &ReadableStream, bytes: Fallible<Vec<u8>>, can_gc: CanGc) {
618 match bytes {
619 Ok(b) => {
620 stream.enqueue_native(b, can_gc);
621 },
622 Err(e) => {
623 stream.error_native(e, can_gc);
624 },
625 }
626}
627
628fn stream_handle_eof(stream: &ReadableStream, can_gc: CanGc) {
630 stream.controller_close_native(can_gc);
631}
632
633impl FileListener {
634 fn handle(&mut self, msg: FileManagerResult<ReadFileProgress>) {
635 match msg {
636 Ok(ReadFileProgress::Meta(blob_buf)) => match self.state.take() {
637 Some(FileListenerState::Empty(target)) => {
638 let bytes = if let FileListenerTarget::Stream(ref trusted_stream) = target {
639 let trusted = trusted_stream.clone();
640
641 let task = task!(enqueue_stream_chunk: move || {
642 let stream = trusted.root();
643 stream_handle_incoming(&stream, Ok(blob_buf.bytes), CanGc::note());
644 });
645 self.task_source.queue(task);
646
647 Vec::with_capacity(0)
648 } else {
649 blob_buf.bytes
650 };
651
652 self.state = Some(FileListenerState::Receiving(bytes, target));
653 },
654 _ => panic!(
655 "Unexpected FileListenerState when receiving ReadFileProgress::Meta msg."
656 ),
657 },
658 Ok(ReadFileProgress::Partial(mut bytes_in)) => match self.state.take() {
659 Some(FileListenerState::Receiving(mut bytes, target)) => {
660 if let FileListenerTarget::Stream(ref trusted_stream) = target {
661 let trusted = trusted_stream.clone();
662
663 let task = task!(enqueue_stream_chunk: move || {
664 let stream = trusted.root();
665 stream_handle_incoming(&stream, Ok(bytes_in), CanGc::note());
666 });
667
668 self.task_source.queue(task);
669 } else {
670 bytes.append(&mut bytes_in);
671 };
672
673 self.state = Some(FileListenerState::Receiving(bytes, target));
674 },
675 _ => panic!(
676 "Unexpected FileListenerState when receiving ReadFileProgress::Partial msg."
677 ),
678 },
679 Ok(ReadFileProgress::EOF) => match self.state.take() {
680 Some(FileListenerState::Receiving(bytes, target)) => match target {
681 FileListenerTarget::Promise(trusted_promise, callback) => {
682 let task = task!(resolve_promise: move || {
683 let promise = trusted_promise.root();
684 let _ac = enter_realm(&*promise.global());
685 callback(promise, Ok(bytes));
686 });
687
688 self.task_source.queue(task);
689 },
690 FileListenerTarget::Stream(trusted_stream) => {
691 let trusted = trusted_stream.clone();
692
693 let task = task!(enqueue_stream_chunk: move || {
694 let stream = trusted.root();
695 stream_handle_eof(&stream, CanGc::note());
696 });
697
698 self.task_source.queue(task);
699 },
700 },
701 _ => {
702 panic!("Unexpected FileListenerState when receiving ReadFileProgress::EOF msg.")
703 },
704 },
705 Err(_) => match self.state.take() {
706 Some(FileListenerState::Receiving(_, target)) |
707 Some(FileListenerState::Empty(target)) => {
708 let error = Err(Error::Network);
709
710 match target {
711 FileListenerTarget::Promise(trusted_promise, callback) => {
712 self.task_source.queue(task!(reject_promise: move || {
713 let promise = trusted_promise.root();
714 let _ac = enter_realm(&*promise.global());
715 callback(promise, error);
716 }));
717 },
718 FileListenerTarget::Stream(trusted_stream) => {
719 self.task_source.queue(task!(error_stream: move || {
720 let stream = trusted_stream.root();
721 stream_handle_incoming(&stream, error, CanGc::note());
722 }));
723 },
724 }
725 },
726 _ => panic!("Unexpected FileListenerState when receiving Err msg."),
727 },
728 }
729 }
730}
731
732impl GlobalScope {
733 pub(crate) fn webview_id(&self) -> Option<WebViewId> {
737 if let Some(window) = self.downcast::<Window>() {
738 Some(window.webview_id())
739 } else if let Some(dedicated) = self.downcast::<DedicatedWorkerGlobalScope>() {
740 dedicated.webview_id()
741 } else {
742 None
744 }
745 }
746
747 #[allow(clippy::too_many_arguments)]
748 pub(crate) fn new_inherited(
749 pipeline_id: PipelineId,
750 devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
751 mem_profiler_chan: profile_mem::ProfilerChan,
752 time_profiler_chan: profile_time::ProfilerChan,
753 script_to_constellation_chan: ScriptToConstellationChan,
754 script_to_embedder_chan: ScriptToEmbedderChan,
755 resource_threads: ResourceThreads,
756 origin: MutableOrigin,
757 creation_url: ServoUrl,
758 top_level_creation_url: Option<ServoUrl>,
759 microtask_queue: Rc<MicrotaskQueue>,
760 #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
761 inherited_secure_context: Option<bool>,
762 unminify_js: bool,
763 font_context: Option<Arc<FontContext>>,
764 ) -> Self {
765 Self {
766 task_manager: Default::default(),
767 message_port_state: DomRefCell::new(MessagePortState::UnManaged),
768 broadcast_channel_state: DomRefCell::new(BroadcastChannelState::UnManaged),
769 blob_state: Default::default(),
770 eventtarget: EventTarget::new_inherited(),
771 crypto: Default::default(),
772 registration_map: DomRefCell::new(HashMapTracedValues::new_fx()),
773 cookie_store: Default::default(),
774 worker_map: DomRefCell::new(HashMapTracedValues::new_fx()),
775 pipeline_id,
776 devtools_wants_updates: Default::default(),
777 console_timers: DomRefCell::new(Default::default()),
778 module_map: DomRefCell::new(Default::default()),
779 inline_module_map: DomRefCell::new(Default::default()),
780 devtools_chan,
781 mem_profiler_chan,
782 time_profiler_chan,
783 script_to_constellation_chan,
784 script_to_embedder_chan,
785 in_error_reporting_mode: Default::default(),
786 resource_threads,
787 timers: OnceCell::default(),
788 origin,
789 creation_url,
790 top_level_creation_url,
791 permission_state_invocation_results: Default::default(),
792 microtask_queue,
793 list_auto_close_worker: Default::default(),
794 event_source_tracker: DOMTracker::new(),
795 uncaught_rejections: Default::default(),
796 consumed_rejections: Default::default(),
797 #[cfg(feature = "webgpu")]
798 gpu_id_hub,
799 #[cfg(feature = "webgpu")]
800 gpu_devices: DomRefCell::new(HashMapTracedValues::new_fx()),
801 frozen_supported_performance_entry_types: CachedFrozenArray::new(),
802 https_state: Cell::new(HttpsState::None),
803 console_group_stack: DomRefCell::new(Vec::new()),
804 console_count_map: Default::default(),
805 dynamic_modules: DomRefCell::new(DynamicModuleList::new()),
806 inherited_secure_context,
807 unminified_js_dir: unminify_js.then(|| unminified_path("unminified-js")),
808 byte_length_queuing_strategy_size_function: OnceCell::new(),
809 count_queuing_strategy_size_function: OnceCell::new(),
810 notification_permission_request_callback_map: Default::default(),
811 import_map: Default::default(),
812 resolved_module_set: Default::default(),
813 font_context,
814 }
815 }
816
817 fn port_router_id(&self) -> Option<MessagePortRouterId> {
819 if let MessagePortState::Managed(id, _message_ports) = &*self.message_port_state.borrow() {
820 Some(*id)
821 } else {
822 None
823 }
824 }
825
826 fn is_managing_port(&self, port_id: &MessagePortId) -> bool {
828 if let MessagePortState::Managed(_router_id, message_ports) =
829 &*self.message_port_state.borrow()
830 {
831 return message_ports.contains_key(port_id);
832 }
833 false
834 }
835
836 fn timers(&self) -> &OneshotTimers {
837 self.timers.get_or_init(|| OneshotTimers::new(self))
838 }
839
840 pub(crate) fn font_context(&self) -> Option<&Arc<FontContext>> {
841 self.font_context.as_ref()
842 }
843
844 #[allow(clippy::too_many_arguments)]
846 pub(crate) fn get_serviceworker_registration(
847 &self,
848 script_url: &ServoUrl,
849 scope: &ServoUrl,
850 registration_id: ServiceWorkerRegistrationId,
851 installing_worker: Option<ServiceWorkerId>,
852 _waiting_worker: Option<ServiceWorkerId>,
853 _active_worker: Option<ServiceWorkerId>,
854 can_gc: CanGc,
855 ) -> DomRoot<ServiceWorkerRegistration> {
856 let mut registrations = self.registration_map.borrow_mut();
858
859 if let Some(registration) = registrations.get(®istration_id) {
860 return DomRoot::from_ref(&**registration);
862 }
863
864 let new_registration =
866 ServiceWorkerRegistration::new(self, scope.clone(), registration_id, can_gc);
867
868 if let Some(worker_id) = installing_worker {
870 let worker = self.get_serviceworker(script_url, scope, worker_id, can_gc);
871 new_registration.set_installing(&worker);
872 }
873
874 registrations.insert(registration_id, Dom::from_ref(&*new_registration));
880
881 new_registration
883 }
884
885 pub(crate) fn get_serviceworker(
887 &self,
888 script_url: &ServoUrl,
889 scope: &ServoUrl,
890 worker_id: ServiceWorkerId,
891 can_gc: CanGc,
892 ) -> DomRoot<ServiceWorker> {
893 let mut workers = self.worker_map.borrow_mut();
895
896 if let Some(worker) = workers.get(&worker_id) {
897 DomRoot::from_ref(&**worker)
899 } else {
900 let new_worker =
903 ServiceWorker::new(self, script_url.clone(), scope.clone(), worker_id, can_gc);
904
905 workers.insert(worker_id, Dom::from_ref(&*new_worker));
907
908 new_worker
910 }
911 }
912
913 fn complete_port_transfer(
915 &self,
916 port_id: MessagePortId,
917 tasks: VecDeque<PortMessageTask>,
918 disentangled: bool,
919 can_gc: CanGc,
920 ) {
921 let should_start = if let MessagePortState::Managed(_id, message_ports) =
922 &mut *self.message_port_state.borrow_mut()
923 {
924 match message_ports.get_mut(&port_id) {
925 None => {
926 panic!("complete_port_transfer called for an unknown port.");
927 },
928 Some(managed_port) => {
929 if managed_port.pending {
930 panic!("CompleteTransfer msg received for a pending port.");
931 }
932 if let Some(port_impl) = managed_port.port_impl.as_mut() {
933 port_impl.complete_transfer(tasks);
934 if disentangled {
935 port_impl.disentangle();
936 managed_port.dom_port.disentangle();
937 }
938 port_impl.enabled()
939 } else {
940 panic!("managed-port has no port-impl.");
941 }
942 },
943 }
944 } else {
945 panic!("complete_port_transfer called for an unknown port.");
946 };
947 if should_start {
948 self.start_message_port(&port_id, can_gc);
949 }
950 }
951
952 fn try_complete_disentanglement(&self, port_id: MessagePortId, can_gc: CanGc) {
955 let dom_port = if let MessagePortState::Managed(_id, message_ports) =
956 &mut *self.message_port_state.borrow_mut()
957 {
958 if let Some(managed_port) = message_ports.get_mut(&port_id) {
959 if managed_port.pending {
960 unreachable!("CompleteDisentanglement msg received for a pending port.");
961 }
962 let port_impl = managed_port
963 .port_impl
964 .as_mut()
965 .expect("managed-port has no port-impl.");
966 port_impl.disentangle();
967 managed_port.dom_port.as_rooted()
968 } else {
969 return;
973 }
974 } else {
975 return;
976 };
977
978 dom_port.upcast().fire_event(atom!("close"), can_gc);
980
981 let res = self.script_to_constellation_chan().send(
982 ScriptToConstellationMessage::DisentanglePorts(port_id, None),
983 );
984 if res.is_err() {
985 warn!("Sending DisentanglePorts failed");
986 }
987 }
988
989 pub(crate) fn perform_a_dom_garbage_collection_checkpoint(&self) {
991 self.perform_a_message_port_garbage_collection_checkpoint();
992 self.perform_a_blob_garbage_collection_checkpoint();
993 self.perform_a_broadcast_channel_garbage_collection_checkpoint();
994 }
995
996 pub(crate) fn remove_web_messaging_and_dedicated_workers_infra(&self) {
999 self.remove_message_ports_router();
1000 self.remove_broadcast_channel_router();
1001
1002 self.list_auto_close_worker
1006 .borrow_mut()
1007 .drain(0..)
1008 .for_each(drop);
1009 }
1010
1011 fn remove_message_ports_router(&self) {
1014 if let MessagePortState::Managed(router_id, _message_ports) =
1015 &*self.message_port_state.borrow()
1016 {
1017 let _ = self.script_to_constellation_chan().send(
1018 ScriptToConstellationMessage::RemoveMessagePortRouter(*router_id),
1019 );
1020 }
1021 *self.message_port_state.borrow_mut() = MessagePortState::UnManaged;
1022 }
1023
1024 fn remove_broadcast_channel_router(&self) {
1027 if let BroadcastChannelState::Managed(router_id, _channels) =
1028 &*self.broadcast_channel_state.borrow()
1029 {
1030 let _ = self.script_to_constellation_chan().send(
1031 ScriptToConstellationMessage::RemoveBroadcastChannelRouter(
1032 *router_id,
1033 self.origin().immutable().clone(),
1034 ),
1035 );
1036 }
1037 *self.broadcast_channel_state.borrow_mut() = BroadcastChannelState::UnManaged;
1038 }
1039
1040 pub(crate) fn disentangle_port(&self, port: &MessagePort, can_gc: CanGc) {
1042 let initiator_port = port.message_port_id();
1043 let Some(other_port) = port.disentangle() else {
1045 return;
1049 };
1050
1051 let dom_port = if let MessagePortState::Managed(_id, message_ports) =
1054 &mut *self.message_port_state.borrow_mut()
1055 {
1056 let mut dom_port = None;
1057 for port_id in &[initiator_port, &other_port] {
1058 match message_ports.get_mut(port_id) {
1059 None => {
1060 continue;
1061 },
1062 Some(managed_port) => {
1063 let port_impl = managed_port
1064 .port_impl
1065 .as_mut()
1066 .expect("managed-port has no port-impl.");
1067 managed_port.dom_port.disentangle();
1068 port_impl.disentangle();
1069
1070 if **port_id == other_port {
1071 dom_port = Some(managed_port.dom_port.as_rooted())
1072 }
1073 },
1074 }
1075 }
1076 dom_port
1077 } else {
1078 panic!("disentangle_port called on a global not managing any ports.");
1079 };
1080
1081 if let Some(dom_port) = dom_port {
1084 dom_port.upcast().fire_event(atom!("close"), can_gc);
1085 }
1086
1087 let chan = self.script_to_constellation_chan().clone();
1088 let initiator_port = *initiator_port;
1089 self.task_manager()
1090 .port_message_queue()
1091 .queue(task!(post_message: move || {
1092 let res = chan.send(ScriptToConstellationMessage::DisentanglePorts(initiator_port, Some(other_port)));
1095 if res.is_err() {
1096 warn!("Sending DisentanglePorts failed");
1097 }
1098 }));
1099 }
1100
1101 pub(crate) fn entangle_ports(&self, port1: MessagePortId, port2: MessagePortId) {
1103 if let MessagePortState::Managed(_id, message_ports) =
1104 &mut *self.message_port_state.borrow_mut()
1105 {
1106 for (port_id, entangled_id) in &[(port1, port2), (port2, port1)] {
1107 match message_ports.get_mut(port_id) {
1108 None => {
1109 return warn!("entangled_ports called on a global not managing the port.");
1110 },
1111 Some(managed_port) => {
1112 if let Some(port_impl) = managed_port.port_impl.as_mut() {
1113 managed_port.dom_port.entangle(*entangled_id);
1114 port_impl.entangle(*entangled_id);
1115 } else {
1116 panic!("managed-port has no port-impl.");
1117 }
1118 },
1119 }
1120 }
1121 } else {
1122 panic!("entangled_ports called on a global not managing any ports.");
1123 }
1124
1125 let _ = self
1126 .script_to_constellation_chan()
1127 .send(ScriptToConstellationMessage::EntanglePorts(port1, port2));
1128 }
1129
1130 pub(crate) fn mark_port_as_transferred(&self, port_id: &MessagePortId) -> MessagePortImpl {
1132 if let MessagePortState::Managed(_id, message_ports) =
1133 &mut *self.message_port_state.borrow_mut()
1134 {
1135 let mut port_impl = message_ports
1136 .remove(port_id)
1137 .map(|ref mut managed_port| {
1138 managed_port
1139 .port_impl
1140 .take()
1141 .expect("Managed port doesn't have a port-impl.")
1142 })
1143 .expect("mark_port_as_transferred called on a global not managing the port.");
1144 port_impl.set_has_been_shipped();
1145 let _ = self
1146 .script_to_constellation_chan()
1147 .send(ScriptToConstellationMessage::MessagePortShipped(*port_id));
1148 port_impl
1149 } else {
1150 panic!("mark_port_as_transferred called on a global not managing any ports.");
1151 }
1152 }
1153
1154 pub(crate) fn start_message_port(&self, port_id: &MessagePortId, can_gc: CanGc) {
1156 let (message_buffer, dom_port) = if let MessagePortState::Managed(_id, message_ports) =
1157 &mut *self.message_port_state.borrow_mut()
1158 {
1159 let (message_buffer, dom_port) = match message_ports.get_mut(port_id) {
1160 None => panic!("start_message_port called on a unknown port."),
1161 Some(managed_port) => {
1162 if let Some(port_impl) = managed_port.port_impl.as_mut() {
1163 (port_impl.start(), managed_port.dom_port.as_rooted())
1164 } else {
1165 panic!("managed-port has no port-impl.");
1166 }
1167 },
1168 };
1169 (message_buffer, dom_port)
1170 } else {
1171 return warn!("start_message_port called on a global not managing any ports.");
1172 };
1173 if let Some(message_buffer) = message_buffer {
1174 for task in message_buffer {
1175 self.route_task_to_port(*port_id, task, CanGc::note());
1176 }
1177 if dom_port.disentangled() {
1178 dom_port.upcast().fire_event(atom!("close"), can_gc);
1181
1182 let res = self.script_to_constellation_chan().send(
1183 ScriptToConstellationMessage::DisentanglePorts(*port_id, None),
1184 );
1185 if res.is_err() {
1186 warn!("Sending DisentanglePorts failed");
1187 }
1188 }
1189 }
1190 }
1191
1192 pub(crate) fn close_message_port(&self, port_id: &MessagePortId) {
1194 if let MessagePortState::Managed(_id, message_ports) =
1195 &mut *self.message_port_state.borrow_mut()
1196 {
1197 match message_ports.get_mut(port_id) {
1198 None => panic!("close_message_port called on an unknown port."),
1199 Some(managed_port) => {
1200 if let Some(port_impl) = managed_port.port_impl.as_mut() {
1201 port_impl.close();
1202 managed_port.explicitly_closed = true;
1203 } else {
1204 panic!("managed-port has no port-impl.");
1205 }
1206 },
1207 };
1208 } else {
1209 warn!("close_message_port called on a global not managing any ports.")
1210 }
1211 }
1212
1213 pub(crate) fn post_messageport_msg(&self, port_id: MessagePortId, task: PortMessageTask) {
1216 if let MessagePortState::Managed(_id, message_ports) =
1217 &mut *self.message_port_state.borrow_mut()
1218 {
1219 let entangled_port = match message_ports.get_mut(&port_id) {
1220 None => panic!("post_messageport_msg called on an unknown port."),
1221 Some(managed_port) => {
1222 if let Some(port_impl) = managed_port.port_impl.as_mut() {
1223 port_impl.entangled_port_id()
1224 } else {
1225 panic!("managed-port has no port-impl.");
1226 }
1227 },
1228 };
1229 if let Some(entangled_id) = entangled_port {
1230 let this = Trusted::new(self);
1232 self.task_manager()
1233 .port_message_queue()
1234 .queue(task!(post_message: move || {
1235 let global = this.root();
1236 global.route_task_to_port(entangled_id, task, CanGc::note());
1239 }));
1240 }
1241 } else {
1242 warn!("post_messageport_msg called on a global not managing any ports.");
1243 }
1244 }
1245
1246 fn re_route_port_task(&self, port_id: MessagePortId, task: PortMessageTask) {
1249 let _ = self.script_to_constellation_chan().send(
1250 ScriptToConstellationMessage::RerouteMessagePort(port_id, task),
1251 );
1252 }
1253
1254 pub(crate) fn schedule_broadcast(&self, msg: BroadcastChannelMsg, channel_id: &Uuid) {
1257 self.broadcast_message_event(msg.clone(), Some(channel_id));
1259
1260 if let BroadcastChannelState::Managed(router_id, _) =
1261 &*self.broadcast_channel_state.borrow()
1262 {
1263 let _ = self.script_to_constellation_chan().send(
1268 ScriptToConstellationMessage::ScheduleBroadcast(*router_id, msg),
1269 );
1270 } else {
1271 panic!("Attemps to broadcast a message via global not managing any channels.");
1272 }
1273 }
1274
1275 pub(crate) fn broadcast_message_event(
1278 &self,
1279 event: BroadcastChannelMsg,
1280 channel_id: Option<&Uuid>,
1281 ) {
1282 if let BroadcastChannelState::Managed(_, channels) = &*self.broadcast_channel_state.borrow()
1283 {
1284 let BroadcastChannelMsg {
1285 data,
1286 origin,
1287 channel_name,
1288 } = event;
1289
1290 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
1294 if worker.is_closing() {
1295 return;
1296 }
1297 }
1298
1299 if let Some(window) = self.downcast::<Window>() {
1301 if !window.Document().is_fully_active() {
1302 return;
1303 }
1304 }
1305
1306 let channel_name = DOMString::from_string(channel_name);
1308
1309 if let Some(channels) = channels.get(&channel_name) {
1310 channels
1311 .iter()
1312 .filter(|channel| {
1313 if let Some(id) = channel_id {
1316 channel.id() != id
1317 } else {
1318 true
1319 }
1320 })
1321 .map(|channel| DomRoot::from_ref(&**channel))
1322 .for_each(|channel| {
1325 let data = data.clone_for_broadcast();
1326 let origin = origin.clone();
1327
1328 let channel = Trusted::new(&*channel);
1331 let global = Trusted::new(self);
1332 self.task_manager().dom_manipulation_task_source().queue(
1333 task!(process_pending_port_messages: move || {
1334 let destination = channel.root();
1335 let global = global.root();
1336
1337 if destination.closed() {
1339 return;
1340 }
1341
1342 rooted!(in(*GlobalScope::get_cx()) let mut message = UndefinedValue());
1343
1344 if let Ok(ports) = structuredclone::read(&global, data, message.handle_mut()) {
1346 MessageEvent::dispatch_jsval(
1348 destination.upcast(),
1349 &global,
1350 message.handle(),
1351 Some(&origin.ascii_serialization()),
1352 None,
1353 ports,
1354 CanGc::note()
1355 );
1356 } else {
1357 MessageEvent::dispatch_error(destination.upcast(), &global, CanGc::note());
1359 }
1360 })
1361 );
1362 });
1363 }
1364 }
1365 }
1366
1367 pub(crate) fn note_cross_realm_transform_readable(
1371 &self,
1372 cross_realm_transform_readable: &CrossRealmTransformReadable,
1373 port_id: &MessagePortId,
1374 ) {
1375 let MessagePortState::Managed(_id, message_ports) =
1376 &mut *self.message_port_state.borrow_mut()
1377 else {
1378 unreachable!(
1379 "Cross realm transform readable must be called on a global managing ports"
1380 );
1381 };
1382
1383 let Some(managed_port) = message_ports.get_mut(port_id) else {
1384 unreachable!("Cross realm transform readable must match a managed port");
1385 };
1386
1387 managed_port.cross_realm_transform = Some(CrossRealmTransform::Readable(
1388 cross_realm_transform_readable.clone(),
1389 ));
1390 }
1391
1392 pub(crate) fn note_cross_realm_transform_writable(
1396 &self,
1397 cross_realm_transform_writable: &CrossRealmTransformWritable,
1398 port_id: &MessagePortId,
1399 ) {
1400 let MessagePortState::Managed(_id, message_ports) =
1401 &mut *self.message_port_state.borrow_mut()
1402 else {
1403 unreachable!(
1404 "Cross realm transform writable must be called on a global managing ports"
1405 );
1406 };
1407
1408 let Some(managed_port) = message_ports.get_mut(port_id) else {
1409 unreachable!("Cross realm transform writable must match a managed port");
1410 };
1411
1412 managed_port.cross_realm_transform = Some(CrossRealmTransform::Writable(
1413 cross_realm_transform_writable.clone(),
1414 ));
1415 }
1416
1417 pub(crate) fn route_task_to_port(
1420 &self,
1421 port_id: MessagePortId,
1422 task: PortMessageTask,
1423 can_gc: CanGc,
1424 ) {
1425 let cx = GlobalScope::get_cx();
1426 rooted!(in(*cx) let mut cross_realm_transform = None);
1427
1428 let should_dispatch = if let MessagePortState::Managed(_id, message_ports) =
1429 &mut *self.message_port_state.borrow_mut()
1430 {
1431 if !message_ports.contains_key(&port_id) {
1432 self.re_route_port_task(port_id, task);
1433 return;
1434 }
1435 match message_ports.get_mut(&port_id) {
1436 None => panic!("route_task_to_port called for an unknown port."),
1437 Some(managed_port) => {
1438 if let Some(port_impl) = managed_port.port_impl.as_mut() {
1441 let to_dispatch = port_impl.handle_incoming(task).map(|to_dispatch| {
1442 (DomRoot::from_ref(&*managed_port.dom_port), to_dispatch)
1443 });
1444 cross_realm_transform.set(managed_port.cross_realm_transform.clone());
1445 to_dispatch
1446 } else {
1447 panic!("managed-port has no port-impl.");
1448 }
1449 },
1450 }
1451 } else {
1452 self.re_route_port_task(port_id, task);
1453 return;
1454 };
1455
1456 if let Some((dom_port, PortMessageTask { origin, data })) = should_dispatch {
1461 let message_event_target = dom_port.upcast();
1463
1464 rooted!(in(*cx) let mut message_clone = UndefinedValue());
1470
1471 let realm = enter_realm(self);
1472 let comp = InRealm::Entered(&realm);
1473
1474 let _aes = AutoEntryScript::new(self);
1478
1479 if let Ok(ports) = structuredclone::read(self, data, message_clone.handle_mut()) {
1485 if let Some(transform) = cross_realm_transform.as_ref() {
1487 match transform {
1488 CrossRealmTransform::Readable(readable) => {
1491 readable.handle_message(
1492 cx,
1493 self,
1494 &dom_port,
1495 message_clone.handle(),
1496 comp,
1497 can_gc,
1498 );
1499 },
1500 CrossRealmTransform::Writable(writable) => {
1503 writable.handle_message(cx, self, message_clone.handle(), comp, can_gc);
1504 },
1505 }
1506 } else {
1507 MessageEvent::dispatch_jsval(
1512 message_event_target,
1513 self,
1514 message_clone.handle(),
1515 Some(&origin.ascii_serialization()),
1516 None,
1517 ports,
1518 can_gc,
1519 );
1520 }
1521 } else if let Some(transform) = cross_realm_transform.as_ref() {
1522 match transform {
1523 CrossRealmTransform::Readable(readable) => {
1526 readable.handle_error(cx, self, &dom_port, comp, can_gc);
1527 },
1528 CrossRealmTransform::Writable(writable) => {
1531 writable.handle_error(cx, self, &dom_port, comp, can_gc);
1532 },
1533 }
1534 } else {
1535 MessageEvent::dispatch_error(message_event_target, self, can_gc);
1539 }
1540 }
1541 }
1542
1543 pub(crate) fn maybe_add_pending_ports(&self) {
1546 if let MessagePortState::Managed(router_id, message_ports) =
1547 &mut *self.message_port_state.borrow_mut()
1548 {
1549 let to_be_added: Vec<MessagePortId> = message_ports
1550 .iter()
1551 .filter_map(|(id, managed_port)| {
1552 if managed_port.pending {
1553 Some(*id)
1554 } else {
1555 None
1556 }
1557 })
1558 .collect();
1559 for id in to_be_added.iter() {
1560 let managed_port = message_ports
1561 .get_mut(id)
1562 .expect("Collected port-id to match an entry");
1563 if !managed_port.pending {
1564 panic!("Only pending ports should be found in to_be_added")
1565 }
1566 managed_port.pending = false;
1567 }
1568 let _ = self.script_to_constellation_chan().send(
1569 ScriptToConstellationMessage::CompleteMessagePortTransfer(*router_id, to_be_added),
1570 );
1571 } else {
1572 warn!("maybe_add_pending_ports called on a global not managing any ports.");
1573 }
1574 }
1575
1576 pub(crate) fn perform_a_message_port_garbage_collection_checkpoint(&self) {
1578 let is_empty = if let MessagePortState::Managed(_id, message_ports) =
1579 &mut *self.message_port_state.borrow_mut()
1580 {
1581 let to_be_removed: Vec<MessagePortId> = message_ports
1582 .iter()
1583 .filter_map(|(id, managed_port)| {
1584 if managed_port.explicitly_closed {
1585 Some(*id)
1586 } else {
1587 None
1588 }
1589 })
1590 .collect();
1591 for id in to_be_removed {
1592 message_ports.remove(&id);
1593 }
1594 message_ports.is_empty()
1598 } else {
1599 false
1600 };
1601 if is_empty {
1602 self.remove_message_ports_router();
1603 }
1604 }
1605
1606 pub(crate) fn perform_a_broadcast_channel_garbage_collection_checkpoint(&self) {
1610 let is_empty = if let BroadcastChannelState::Managed(router_id, channels) =
1611 &mut *self.broadcast_channel_state.borrow_mut()
1612 {
1613 channels.retain(|name, ref mut channels| {
1614 channels.retain(|chan| !chan.closed());
1615 if channels.is_empty() {
1616 let _ = self.script_to_constellation_chan().send(
1617 ScriptToConstellationMessage::RemoveBroadcastChannelNameInRouter(
1618 *router_id,
1619 name.to_string(),
1620 self.origin().immutable().clone(),
1621 ),
1622 );
1623 false
1624 } else {
1625 true
1626 }
1627 });
1628 channels.is_empty()
1629 } else {
1630 false
1631 };
1632 if is_empty {
1633 self.remove_broadcast_channel_router();
1634 }
1635 }
1636
1637 pub(crate) fn track_broadcast_channel(&self, dom_channel: &BroadcastChannel) {
1639 let mut current_state = self.broadcast_channel_state.borrow_mut();
1640
1641 if let BroadcastChannelState::UnManaged = &*current_state {
1642 let (broadcast_control_sender, broadcast_control_receiver) =
1644 ipc::channel().expect("ipc channel failure");
1645 let context = Trusted::new(self);
1646 let listener = BroadcastListener {
1647 task_source: self.task_manager().dom_manipulation_task_source().into(),
1648 context,
1649 };
1650 ROUTER.add_typed_route(
1651 broadcast_control_receiver,
1652 Box::new(move |message| match message {
1653 Ok(msg) => listener.handle(msg),
1654 Err(err) => warn!("Error receiving a BroadcastChannelMsg: {:?}", err),
1655 }),
1656 );
1657 let router_id = BroadcastChannelRouterId::new();
1658 *current_state = BroadcastChannelState::Managed(router_id, HashMap::new());
1659 let _ = self.script_to_constellation_chan().send(
1660 ScriptToConstellationMessage::NewBroadcastChannelRouter(
1661 router_id,
1662 broadcast_control_sender,
1663 self.origin().immutable().clone(),
1664 ),
1665 );
1666 }
1667
1668 if let BroadcastChannelState::Managed(router_id, channels) = &mut *current_state {
1669 let entry = channels.entry(dom_channel.Name()).or_insert_with(|| {
1670 let _ = self.script_to_constellation_chan().send(
1671 ScriptToConstellationMessage::NewBroadcastChannelNameInRouter(
1672 *router_id,
1673 dom_channel.Name().to_string(),
1674 self.origin().immutable().clone(),
1675 ),
1676 );
1677 VecDeque::new()
1678 });
1679 entry.push_back(Dom::from_ref(dom_channel));
1680 } else {
1681 panic!("track_broadcast_channel should have first switched the state to managed.");
1682 }
1683 }
1684
1685 pub(crate) fn track_message_port(
1687 &self,
1688 dom_port: &MessagePort,
1689 port_impl: Option<MessagePortImpl>,
1690 ) {
1691 let mut current_state = self.message_port_state.borrow_mut();
1692
1693 if let MessagePortState::UnManaged = &*current_state {
1694 let (port_control_sender, port_control_receiver) =
1696 ipc::channel().expect("ipc channel failure");
1697 let context = Trusted::new(self);
1698 let listener = MessageListener {
1699 task_source: self.task_manager().port_message_queue().into(),
1700 context,
1701 };
1702 ROUTER.add_typed_route(
1703 port_control_receiver,
1704 Box::new(move |message| match message {
1705 Ok(msg) => listener.notify(msg),
1706 Err(err) => warn!("Error receiving a MessagePortMsg: {:?}", err),
1707 }),
1708 );
1709 let router_id = MessagePortRouterId::new();
1710 *current_state = MessagePortState::Managed(router_id, HashMapTracedValues::new_fx());
1711 let _ = self.script_to_constellation_chan().send(
1712 ScriptToConstellationMessage::NewMessagePortRouter(router_id, port_control_sender),
1713 );
1714 }
1715
1716 if let MessagePortState::Managed(router_id, message_ports) = &mut *current_state {
1717 if let Some(port_impl) = port_impl {
1718 message_ports.insert(
1722 *dom_port.message_port_id(),
1723 ManagedMessagePort {
1724 port_impl: Some(port_impl),
1725 dom_port: Dom::from_ref(dom_port),
1726 pending: true,
1727 explicitly_closed: false,
1728 cross_realm_transform: None,
1729 },
1730 );
1731
1732 let this = Trusted::new(self);
1735 self.task_manager().port_message_queue().queue(
1736 task!(process_pending_port_messages: move || {
1737 let target_global = this.root();
1738 target_global.maybe_add_pending_ports();
1739 }),
1740 );
1741 } else {
1742 let port_impl = MessagePortImpl::new(*dom_port.message_port_id());
1744 message_ports.insert(
1745 *dom_port.message_port_id(),
1746 ManagedMessagePort {
1747 port_impl: Some(port_impl),
1748 dom_port: Dom::from_ref(dom_port),
1749 pending: false,
1750 explicitly_closed: false,
1751 cross_realm_transform: None,
1752 },
1753 );
1754 let _ = self.script_to_constellation_chan().send(
1755 ScriptToConstellationMessage::NewMessagePort(
1756 *router_id,
1757 *dom_port.message_port_id(),
1758 ),
1759 );
1760 };
1761 } else {
1762 panic!("track_message_port should have first switched the state to managed.");
1763 }
1764 }
1765
1766 pub(crate) fn serialize_blob(&self, blob_id: &BlobId) -> BlobImpl {
1770 let bytes = self
1774 .get_blob_bytes(blob_id)
1775 .expect("Could not read bytes from blob as part of serialization steps.");
1776 let type_string = self.get_blob_type_string(blob_id);
1777
1778 BlobImpl::new_from_bytes(bytes, type_string)
1780 }
1781
1782 fn track_blob_info(&self, blob_info: BlobInfo, blob_id: BlobId) {
1783 self.blob_state.borrow_mut().insert(blob_id, blob_info);
1784 }
1785
1786 pub(crate) fn track_blob(&self, dom_blob: &Blob, blob_impl: BlobImpl) {
1788 let blob_id = blob_impl.blob_id();
1789
1790 let blob_info = BlobInfo {
1791 blob_impl,
1792 tracker: BlobTracker::Blob(WeakRef::new(dom_blob)),
1793 has_url: false,
1794 };
1795
1796 self.track_blob_info(blob_info, blob_id);
1797 }
1798
1799 pub(crate) fn track_file(&self, file: &File, blob_impl: BlobImpl) {
1801 let blob_id = blob_impl.blob_id();
1802
1803 let blob_info = BlobInfo {
1804 blob_impl,
1805 tracker: BlobTracker::File(WeakRef::new(file)),
1806 has_url: false,
1807 };
1808
1809 self.track_blob_info(blob_info, blob_id);
1810 }
1811
1812 fn perform_a_blob_garbage_collection_checkpoint(&self) {
1816 let mut blob_state = self.blob_state.borrow_mut();
1817 blob_state.0.retain(|_id, blob_info| {
1818 let garbage_collected = match &blob_info.tracker {
1819 BlobTracker::File(weak) => weak.root().is_none(),
1820 BlobTracker::Blob(weak) => weak.root().is_none(),
1821 };
1822 if garbage_collected && !blob_info.has_url {
1823 if let BlobData::File(f) = blob_info.blob_impl.blob_data() {
1824 self.decrement_file_ref(f.get_id());
1825 }
1826 false
1827 } else {
1828 true
1829 }
1830 });
1831 }
1832
1833 pub(crate) fn clean_up_all_file_resources(&self) {
1836 self.blob_state
1837 .borrow_mut()
1838 .drain()
1839 .for_each(|(_id, blob_info)| {
1840 if let BlobData::File(f) = blob_info.blob_impl.blob_data() {
1841 self.decrement_file_ref(f.get_id());
1842 }
1843 });
1844 }
1845
1846 fn decrement_file_ref(&self, id: Uuid) {
1847 let origin = get_blob_origin(&self.get_url());
1848
1849 let (tx, rx) = profile_ipc::channel(self.time_profiler_chan().clone()).unwrap();
1850
1851 let msg = FileManagerThreadMsg::DecRef(id, origin, tx);
1852 self.send_to_file_manager(msg);
1853 let _ = rx.recv();
1854 }
1855
1856 pub(crate) fn get_blob_bytes(&self, blob_id: &BlobId) -> Result<Vec<u8>, ()> {
1859 let parent = {
1860 match *self.get_blob_data(blob_id) {
1861 BlobData::Sliced(parent, rel_pos) => Some((parent, rel_pos)),
1862 _ => None,
1863 }
1864 };
1865
1866 match parent {
1867 Some((parent_id, rel_pos)) => self.get_blob_bytes_non_sliced(&parent_id).map(|v| {
1868 let range = rel_pos.to_abs_range(v.len());
1869 v.index(range).to_vec()
1870 }),
1871 None => self.get_blob_bytes_non_sliced(blob_id),
1872 }
1873 }
1874
1875 pub(crate) fn get_blob_data<'a>(&'a self, blob_id: &BlobId) -> Ref<'a, BlobData> {
1880 Ref::map(self.blob_state.borrow(), |blob_state| {
1881 blob_state
1882 .get(blob_id)
1883 .expect("get_blob_impl called for a unknown blob")
1884 .blob_impl
1885 .blob_data()
1886 })
1887 }
1888
1889 fn get_blob_bytes_non_sliced(&self, blob_id: &BlobId) -> Result<Vec<u8>, ()> {
1891 match *self.get_blob_data(blob_id) {
1892 BlobData::File(ref f) => {
1893 let (buffer, is_new_buffer) = match f.get_cache() {
1894 Some(bytes) => (bytes, false),
1895 None => {
1896 let bytes = self.read_file(f.get_id())?;
1897 (bytes, true)
1898 },
1899 };
1900
1901 if is_new_buffer {
1903 f.cache_bytes(buffer.clone());
1904 }
1905
1906 Ok(buffer)
1907 },
1908 BlobData::Memory(ref s) => Ok(s.clone()),
1909 BlobData::Sliced(_, _) => panic!("This blob doesn't have a parent."),
1910 }
1911 }
1912
1913 fn get_blob_bytes_or_file_id(&self, blob_id: &BlobId) -> BlobResult {
1920 let parent = {
1921 match *self.get_blob_data(blob_id) {
1922 BlobData::Sliced(parent, rel_pos) => Some((parent, rel_pos)),
1923 _ => None,
1924 }
1925 };
1926
1927 match parent {
1928 Some((parent_id, rel_pos)) => {
1929 match self.get_blob_bytes_non_sliced_or_file_id(&parent_id) {
1930 BlobResult::Bytes(bytes) => {
1931 let range = rel_pos.to_abs_range(bytes.len());
1932 BlobResult::Bytes(bytes.index(range).to_vec())
1933 },
1934 res => res,
1935 }
1936 },
1937 None => self.get_blob_bytes_non_sliced_or_file_id(blob_id),
1938 }
1939 }
1940
1941 fn get_blob_bytes_non_sliced_or_file_id(&self, blob_id: &BlobId) -> BlobResult {
1947 match *self.get_blob_data(blob_id) {
1948 BlobData::File(ref f) => match f.get_cache() {
1949 Some(bytes) => BlobResult::Bytes(bytes.clone()),
1950 None => BlobResult::File(f.get_id(), f.get_size() as usize),
1951 },
1952 BlobData::Memory(ref s) => BlobResult::Bytes(s.clone()),
1953 BlobData::Sliced(_, _) => panic!("This blob doesn't have a parent."),
1954 }
1955 }
1956
1957 pub(crate) fn get_blob_type_string(&self, blob_id: &BlobId) -> String {
1959 let blob_state = self.blob_state.borrow();
1960 let blob_info = blob_state
1961 .get(blob_id)
1962 .expect("get_blob_type_string called for a unknown blob.");
1963 blob_info.blob_impl.type_string()
1964 }
1965
1966 pub(crate) fn get_blob_size(&self, blob_id: &BlobId) -> u64 {
1968 let parent = {
1969 match *self.get_blob_data(blob_id) {
1970 BlobData::Sliced(parent, rel_pos) => Some((parent, rel_pos)),
1971 _ => None,
1972 }
1973 };
1974 match parent {
1975 Some((parent_id, rel_pos)) => {
1976 let parent_size = match *self.get_blob_data(&parent_id) {
1977 BlobData::File(ref f) => f.get_size(),
1978 BlobData::Memory(ref v) => v.len() as u64,
1979 BlobData::Sliced(_, _) => panic!("Blob ancestry should be only one level."),
1980 };
1981 rel_pos.to_abs_range(parent_size as usize).len() as u64
1982 },
1983 None => match *self.get_blob_data(blob_id) {
1984 BlobData::File(ref f) => f.get_size(),
1985 BlobData::Memory(ref v) => v.len() as u64,
1986 BlobData::Sliced(_, _) => {
1987 panic!("It was previously checked that this blob does not have a parent.")
1988 },
1989 },
1990 }
1991 }
1992
1993 pub(crate) fn get_blob_url_id(&self, blob_id: &BlobId) -> Uuid {
1994 let mut blob_state = self.blob_state.borrow_mut();
1995 let parent = {
1996 let blob_info = blob_state
1997 .get_mut(blob_id)
1998 .expect("get_blob_url_id called for a unknown blob.");
1999
2000 blob_info.has_url = true;
2002
2003 match blob_info.blob_impl.blob_data() {
2004 BlobData::Sliced(parent, rel_pos) => Some((*parent, *rel_pos)),
2005 _ => None,
2006 }
2007 };
2008 match parent {
2009 Some((parent_id, rel_pos)) => {
2010 let parent_info = blob_state
2011 .get_mut(&parent_id)
2012 .expect("Parent of blob whose url is requested is unknown.");
2013 let parent_file_id = self.promote(parent_info, false);
2014 let parent_size = match parent_info.blob_impl.blob_data() {
2015 BlobData::File(f) => f.get_size(),
2016 BlobData::Memory(v) => v.len() as u64,
2017 BlobData::Sliced(_, _) => panic!("Blob ancestry should be only one level."),
2018 };
2019 let parent_size = rel_pos.to_abs_range(parent_size as usize).len() as u64;
2020 let blob_info = blob_state
2021 .get_mut(blob_id)
2022 .expect("Blob whose url is requested is unknown.");
2023 self.create_sliced_url_id(blob_info, &parent_file_id, &rel_pos, parent_size)
2024 },
2025 None => {
2026 let blob_info = blob_state
2027 .get_mut(blob_id)
2028 .expect("Blob whose url is requested is unknown.");
2029 self.promote(blob_info, true)
2030 },
2031 }
2032 }
2033
2034 fn create_sliced_url_id(
2036 &self,
2037 blob_info: &mut BlobInfo,
2038 parent_file_id: &Uuid,
2039 rel_pos: &RelativePos,
2040 parent_len: u64,
2041 ) -> Uuid {
2042 let origin = get_blob_origin(&self.get_url());
2043
2044 let (tx, rx) = profile_ipc::channel(self.time_profiler_chan().clone()).unwrap();
2045 let msg =
2046 FileManagerThreadMsg::AddSlicedURLEntry(*parent_file_id, *rel_pos, tx, origin.clone());
2047 self.send_to_file_manager(msg);
2048 match rx.recv().expect("File manager thread is down.") {
2049 Ok(new_id) => {
2050 *blob_info.blob_impl.blob_data_mut() = BlobData::File(FileBlob::new(
2051 new_id,
2052 None,
2053 None,
2054 rel_pos.to_abs_range(parent_len as usize).len() as u64,
2055 ));
2056
2057 new_id
2059 },
2060 Err(_) => {
2061 Uuid::new_v4()
2063 },
2064 }
2065 }
2066
2067 pub(crate) fn promote(&self, blob_info: &mut BlobInfo, set_valid: bool) -> Uuid {
2073 let mut bytes = vec![];
2074 let global_url = self.get_url();
2075
2076 match blob_info.blob_impl.blob_data_mut() {
2077 BlobData::Sliced(_, _) => {
2078 panic!("Sliced blobs should use create_sliced_url_id instead of promote.");
2079 },
2080 BlobData::File(f) => {
2081 if set_valid {
2082 let origin = get_blob_origin(&global_url);
2083 let (tx, rx) = profile_ipc::channel(self.time_profiler_chan().clone()).unwrap();
2084
2085 let msg = FileManagerThreadMsg::ActivateBlobURL(f.get_id(), tx, origin.clone());
2086 self.send_to_file_manager(msg);
2087
2088 match rx.recv().unwrap() {
2089 Ok(_) => return f.get_id(),
2090 Err(_) => return Uuid::new_v4(),
2092 }
2093 } else {
2094 return f.get_id();
2096 }
2097 },
2098 BlobData::Memory(bytes_in) => mem::swap(bytes_in, &mut bytes),
2099 };
2100
2101 let origin = get_blob_origin(&global_url);
2102
2103 let blob_buf = BlobBuf {
2104 filename: None,
2105 type_string: blob_info.blob_impl.type_string(),
2106 size: bytes.len() as u64,
2107 bytes: bytes.to_vec(),
2108 };
2109
2110 let id = Uuid::new_v4();
2111 let msg = FileManagerThreadMsg::PromoteMemory(id, blob_buf, set_valid, origin.clone());
2112 self.send_to_file_manager(msg);
2113
2114 *blob_info.blob_impl.blob_data_mut() = BlobData::File(FileBlob::new(
2115 id,
2116 None,
2117 Some(bytes.to_vec()),
2118 bytes.len() as u64,
2119 ));
2120
2121 id
2122 }
2123
2124 fn send_to_file_manager(&self, msg: FileManagerThreadMsg) {
2125 let resource_threads = self.resource_threads();
2126 let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg));
2127 }
2128
2129 fn read_file(&self, id: Uuid) -> Result<Vec<u8>, ()> {
2130 let recv = self.send_msg(id);
2131 GlobalScope::read_msg(recv)
2132 }
2133
2134 pub(crate) fn get_blob_stream(
2136 &self,
2137 blob_id: &BlobId,
2138 can_gc: CanGc,
2139 ) -> Fallible<DomRoot<ReadableStream>> {
2140 let (file_id, size) = match self.get_blob_bytes_or_file_id(blob_id) {
2141 BlobResult::Bytes(bytes) => {
2142 return ReadableStream::new_from_bytes(self, bytes, can_gc);
2144 },
2145 BlobResult::File(id, size) => (id, size),
2146 };
2147
2148 let stream = ReadableStream::new_with_external_underlying_source(
2149 self,
2150 UnderlyingSourceType::Blob(size),
2151 can_gc,
2152 )?;
2153
2154 let recv = self.send_msg(file_id);
2155
2156 let trusted_stream = Trusted::new(&*stream.clone());
2157 let mut file_listener = FileListener {
2158 state: Some(FileListenerState::Empty(FileListenerTarget::Stream(
2159 trusted_stream,
2160 ))),
2161 task_source: self.task_manager().file_reading_task_source().into(),
2162 };
2163
2164 ROUTER.add_typed_route(
2165 recv.to_ipc_receiver(),
2166 Box::new(move |msg| {
2167 file_listener.handle(msg.expect("Deserialization of file listener msg failed."));
2168 }),
2169 );
2170
2171 Ok(stream)
2172 }
2173
2174 pub(crate) fn read_file_async(
2175 &self,
2176 id: Uuid,
2177 promise: Rc<Promise>,
2178 callback: FileListenerCallback,
2179 ) {
2180 let recv = self.send_msg(id);
2181
2182 let trusted_promise = TrustedPromise::new(promise);
2183 let mut file_listener = FileListener {
2184 state: Some(FileListenerState::Empty(FileListenerTarget::Promise(
2185 trusted_promise,
2186 callback,
2187 ))),
2188 task_source: self.task_manager().file_reading_task_source().into(),
2189 };
2190
2191 ROUTER.add_typed_route(
2192 recv.to_ipc_receiver(),
2193 Box::new(move |msg| {
2194 file_listener.handle(msg.expect("Deserialization of file listener msg failed."));
2195 }),
2196 );
2197 }
2198
2199 fn send_msg(&self, id: Uuid) -> profile_ipc::IpcReceiver<FileManagerResult<ReadFileProgress>> {
2200 let resource_threads = self.resource_threads();
2201 let (chan, recv) = profile_ipc::channel(self.time_profiler_chan().clone()).unwrap();
2202 let origin = get_blob_origin(&self.get_url());
2203 let msg = FileManagerThreadMsg::ReadFile(chan, id, origin);
2204 let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg));
2205 recv
2206 }
2207
2208 fn read_msg(
2209 receiver: profile_ipc::IpcReceiver<FileManagerResult<ReadFileProgress>>,
2210 ) -> Result<Vec<u8>, ()> {
2211 let mut bytes = vec![];
2212
2213 loop {
2214 match receiver.recv().unwrap() {
2215 Ok(ReadFileProgress::Meta(mut blob_buf)) => {
2216 bytes.append(&mut blob_buf.bytes);
2217 },
2218 Ok(ReadFileProgress::Partial(mut bytes_in)) => {
2219 bytes.append(&mut bytes_in);
2220 },
2221 Ok(ReadFileProgress::EOF) => {
2222 return Ok(bytes);
2223 },
2224 Err(_) => return Err(()),
2225 }
2226 }
2227 }
2228
2229 pub(crate) fn permission_state_invocation_results(
2230 &self,
2231 ) -> &DomRefCell<HashMap<PermissionName, PermissionState>> {
2232 &self.permission_state_invocation_results
2233 }
2234
2235 pub(crate) fn track_worker(
2236 &self,
2237 closing: Arc<AtomicBool>,
2238 join_handle: JoinHandle<()>,
2239 control_sender: Sender<DedicatedWorkerControlMsg>,
2240 context: ThreadSafeJSContext,
2241 ) {
2242 self.list_auto_close_worker
2243 .borrow_mut()
2244 .push(AutoCloseWorker {
2245 closing,
2246 join_handle: Some(join_handle),
2247 control_sender,
2248 context,
2249 });
2250 }
2251
2252 pub(crate) fn track_event_source(&self, event_source: &EventSource) {
2253 self.event_source_tracker.track(event_source);
2254 }
2255
2256 pub(crate) fn close_event_sources(&self) -> bool {
2257 let mut canceled_any_fetch = false;
2258 self.event_source_tracker
2259 .for_each(
2260 |event_source: DomRoot<EventSource>| match event_source.ReadyState() {
2261 2 => {},
2262 _ => {
2263 event_source.cancel();
2264 canceled_any_fetch = true;
2265 },
2266 },
2267 );
2268 canceled_any_fetch
2269 }
2270
2271 #[allow(unsafe_code)]
2274 pub(crate) fn from_reflector<T: DomObject>(reflector: &T, _realm: InRealm) -> DomRoot<Self> {
2275 unsafe { GlobalScope::from_object(*reflector.reflector().get_jsobject()) }
2276 }
2277
2278 #[allow(unsafe_code)]
2280 pub(crate) unsafe fn from_object(obj: *mut JSObject) -> DomRoot<Self> {
2281 assert!(!obj.is_null());
2282 let global = unsafe { GetNonCCWObjectGlobal(obj) };
2283 unsafe { global_scope_from_global_static(global) }
2284 }
2285
2286 #[allow(unsafe_code)]
2288 pub(crate) unsafe fn from_context(cx: *mut JSContext, _realm: InRealm) -> DomRoot<Self> {
2289 let global = unsafe { CurrentGlobalOrNull(cx) };
2290 assert!(!global.is_null());
2291 unsafe { global_scope_from_global(global, cx) }
2292 }
2293
2294 #[allow(unsafe_code)]
2296 pub(crate) fn from_safe_context(cx: SafeJSContext, realm: InRealm) -> DomRoot<Self> {
2297 unsafe { Self::from_context(*cx, realm) }
2298 }
2299
2300 #[allow(unsafe_code)]
2303 pub(crate) unsafe fn from_object_maybe_wrapped(
2304 mut obj: *mut JSObject,
2305 cx: *mut JSContext,
2306 ) -> DomRoot<Self> {
2307 unsafe {
2308 if IsWrapper(obj) {
2309 obj = UnwrapObjectDynamic(obj, cx, false);
2310 assert!(!obj.is_null());
2311 }
2312 GlobalScope::from_object(obj)
2313 }
2314 }
2315
2316 pub(crate) fn add_uncaught_rejection(&self, rejection: HandleObject) {
2317 self.uncaught_rejections
2318 .borrow_mut()
2319 .push(Heap::boxed(rejection.get()));
2320 }
2321
2322 pub(crate) fn remove_uncaught_rejection(&self, rejection: HandleObject) {
2323 let mut uncaught_rejections = self.uncaught_rejections.borrow_mut();
2324
2325 if let Some(index) = uncaught_rejections
2326 .iter()
2327 .position(|promise| *promise == Heap::boxed(rejection.get()))
2328 {
2329 uncaught_rejections.remove(index);
2330 }
2331 }
2332
2333 #[allow(clippy::vec_box)]
2336 pub(crate) fn get_uncaught_rejections(&self) -> &DomRefCell<Vec<Box<Heap<*mut JSObject>>>> {
2337 &self.uncaught_rejections
2338 }
2339
2340 pub(crate) fn add_consumed_rejection(&self, rejection: HandleObject) {
2341 self.consumed_rejections
2342 .borrow_mut()
2343 .push(Heap::boxed(rejection.get()));
2344 }
2345
2346 pub(crate) fn remove_consumed_rejection(&self, rejection: HandleObject) {
2347 let mut consumed_rejections = self.consumed_rejections.borrow_mut();
2348
2349 if let Some(index) = consumed_rejections
2350 .iter()
2351 .position(|promise| *promise == Heap::boxed(rejection.get()))
2352 {
2353 consumed_rejections.remove(index);
2354 }
2355 }
2356
2357 #[allow(clippy::vec_box)]
2360 pub(crate) fn get_consumed_rejections(&self) -> &DomRefCell<Vec<Box<Heap<*mut JSObject>>>> {
2361 &self.consumed_rejections
2362 }
2363
2364 pub(crate) fn set_module_map(&self, url: ServoUrl, module: ModuleTree) {
2365 self.module_map.borrow_mut().insert(url, Rc::new(module));
2366 }
2367
2368 pub(crate) fn get_module_map(
2369 &self,
2370 ) -> &DomRefCell<HashMapTracedValues<ServoUrl, Rc<ModuleTree>>> {
2371 &self.module_map
2372 }
2373
2374 pub(crate) fn set_inline_module_map(&self, script_id: ScriptId, module: ModuleTree) {
2375 self.inline_module_map
2376 .borrow_mut()
2377 .insert(script_id, Rc::new(module));
2378 }
2379
2380 pub(crate) fn get_inline_module_map(&self) -> &DomRefCell<FxHashMap<ScriptId, Rc<ModuleTree>>> {
2381 &self.inline_module_map
2382 }
2383
2384 #[allow(unsafe_code)]
2385 pub(crate) fn get_cx() -> SafeJSContext {
2386 let cx = Runtime::get()
2387 .expect("Can't obtain context after runtime shutdown")
2388 .as_ptr();
2389 unsafe { SafeJSContext::from_ptr(cx) }
2390 }
2391
2392 pub(crate) fn crypto(&self, can_gc: CanGc) -> DomRoot<Crypto> {
2393 self.crypto.or_init(|| Crypto::new(self, can_gc))
2394 }
2395
2396 pub(crate) fn cookie_store(&self, can_gc: CanGc) -> DomRoot<CookieStore> {
2397 self.cookie_store.or_init(|| CookieStore::new(self, can_gc))
2398 }
2399
2400 pub(crate) fn live_devtools_updates(&self) -> bool {
2401 self.devtools_wants_updates.get()
2402 }
2403
2404 pub(crate) fn set_devtools_wants_updates(&self, value: bool) {
2405 self.devtools_wants_updates.set(value);
2406 }
2407
2408 pub(crate) fn time(&self, label: DOMString) -> Result<(), ()> {
2409 let mut timers = self.console_timers.borrow_mut();
2410 if timers.len() >= 10000 {
2411 return Err(());
2412 }
2413 match timers.entry(label) {
2414 Entry::Vacant(entry) => {
2415 entry.insert(Instant::now());
2416 Ok(())
2417 },
2418 Entry::Occupied(_) => Err(()),
2419 }
2420 }
2421
2422 pub(crate) fn time_log(&self, label: &str) -> Result<u64, ()> {
2426 self.console_timers
2427 .borrow()
2428 .get(label)
2429 .ok_or(())
2430 .map(|&start| (Instant::now() - start).as_millis() as u64)
2431 }
2432
2433 pub(crate) fn time_end(&self, label: &str) -> Result<u64, ()> {
2438 self.console_timers
2439 .borrow_mut()
2440 .remove(label)
2441 .ok_or(())
2442 .map(|start| (Instant::now() - start).as_millis() as u64)
2443 }
2444
2445 pub(crate) fn devtools_chan(&self) -> Option<&IpcSender<ScriptToDevtoolsControlMsg>> {
2448 self.devtools_chan.as_ref()
2449 }
2450
2451 pub(crate) fn issue_page_warning(&self, warning: &str) {
2452 if let Some(ref chan) = self.devtools_chan {
2453 let _ = chan.send(ScriptToDevtoolsControlMsg::ReportPageError(
2454 self.pipeline_id,
2455 PageError {
2456 type_: "PageError".to_string(),
2457 error_message: warning.to_string(),
2458 source_name: self.get_url().to_string(),
2459 line_text: "".to_string(),
2460 line_number: 0,
2461 column_number: 0,
2462 category: "script".to_string(),
2463 time_stamp: SystemTime::now()
2464 .duration_since(UNIX_EPOCH)
2465 .unwrap_or_default()
2466 .as_millis() as u64,
2467 error: false,
2468 warning: true,
2469 exception: true,
2470 strict: false,
2471 private: false,
2472 },
2473 ));
2474 }
2475 }
2476
2477 pub(crate) fn mem_profiler_chan(&self) -> &profile_mem::ProfilerChan {
2479 &self.mem_profiler_chan
2480 }
2481
2482 pub(crate) fn time_profiler_chan(&self) -> &profile_time::ProfilerChan {
2484 &self.time_profiler_chan
2485 }
2486
2487 pub(crate) fn script_to_constellation_chan(&self) -> &ScriptToConstellationChan {
2489 &self.script_to_constellation_chan
2490 }
2491
2492 pub(crate) fn script_to_embedder_chan(&self) -> &ScriptToEmbedderChan {
2493 &self.script_to_embedder_chan
2494 }
2495
2496 pub(crate) fn send_to_embedder(&self, msg: EmbedderMsg) {
2497 self.script_to_embedder_chan().send(msg).unwrap();
2498 }
2499
2500 pub(crate) fn send_to_constellation(&self, msg: ScriptToConstellationMessage) {
2501 self.script_to_constellation_chan().send(msg).unwrap();
2502 }
2503
2504 pub(crate) fn pipeline_id(&self) -> PipelineId {
2506 self.pipeline_id
2507 }
2508
2509 pub(crate) fn origin(&self) -> &MutableOrigin {
2511 &self.origin
2512 }
2513
2514 pub(crate) fn creation_url(&self) -> &ServoUrl {
2516 &self.creation_url
2517 }
2518
2519 pub(crate) fn top_level_creation_url(&self) -> &Option<ServoUrl> {
2521 &self.top_level_creation_url
2522 }
2523
2524 pub(crate) fn image_cache(&self) -> Arc<dyn ImageCache> {
2525 if let Some(window) = self.downcast::<Window>() {
2526 return window.image_cache();
2527 }
2528 if let Some(worker) = self.downcast::<DedicatedWorkerGlobalScope>() {
2529 return worker.image_cache();
2530 }
2531 if let Some(worker) = self.downcast::<PaintWorkletGlobalScope>() {
2532 return worker.image_cache();
2533 }
2534 unreachable!();
2535 }
2536
2537 pub(crate) fn schedule_timer(&self, request: TimerEventRequest) -> Option<TimerId> {
2541 match self.downcast::<WorkerGlobalScope>() {
2542 Some(worker_global) => Some(worker_global.timer_scheduler().schedule_timer(request)),
2543 _ => with_script_thread(|script_thread| Some(script_thread.schedule_timer(request))),
2544 }
2545 }
2546
2547 pub(crate) fn policy_container(&self) -> PolicyContainer {
2549 if let Some(window) = self.downcast::<Window>() {
2550 return window.Document().policy_container().to_owned();
2551 }
2552 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2553 return worker.policy_container().to_owned();
2554 }
2555 unreachable!();
2556 }
2557
2558 pub(crate) fn api_base_url(&self) -> ServoUrl {
2561 if let Some(window) = self.downcast::<Window>() {
2562 return window.Document().base_url();
2564 }
2565 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2566 return worker.get_url().clone();
2568 }
2569 if let Some(worklet) = self.downcast::<WorkletGlobalScope>() {
2570 return worklet.base_url();
2572 }
2573 if let Some(_debugger_global) = self.downcast::<DebuggerGlobalScope>() {
2574 return self.creation_url.clone();
2575 }
2576 unreachable!();
2577 }
2578
2579 pub(crate) fn get_url(&self) -> ServoUrl {
2581 if let Some(window) = self.downcast::<Window>() {
2582 return window.get_url();
2583 }
2584 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2585 return worker.get_url().clone();
2586 }
2587 if let Some(worklet) = self.downcast::<WorkletGlobalScope>() {
2588 return worklet.base_url();
2590 }
2591 if let Some(_debugger_global) = self.downcast::<DebuggerGlobalScope>() {
2592 return self.creation_url.clone();
2593 }
2594 unreachable!();
2595 }
2596
2597 pub(crate) fn get_referrer_policy(&self) -> ReferrerPolicy {
2599 if let Some(window) = self.downcast::<Window>() {
2600 let document = window.Document();
2601
2602 return document.get_referrer_policy();
2603 }
2604 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2605 let policy_container = worker.policy_container().to_owned();
2606
2607 return policy_container.get_referrer_policy();
2608 }
2609 unreachable!();
2610 }
2611
2612 pub(crate) fn get_referrer(&self) -> Referrer {
2614 if let Some(window) = self.downcast::<Window>() {
2616 let mut document = window.Document();
2620
2621 if let ImmutableOrigin::Opaque(_) = document.origin().immutable() {
2623 return Referrer::NoReferrer;
2624 }
2625
2626 let mut url = document.url();
2627
2628 while url.as_str() == "about:srcdoc" {
2630 let Some(parent_document) =
2633 document.browsing_context().and_then(|browsing_context| {
2634 browsing_context
2635 .parent()
2636 .and_then(|parent| parent.document())
2637 })
2638 else {
2639 return Referrer::NoReferrer;
2640 };
2641 document = parent_document;
2642 url = document.url();
2643 }
2644
2645 Referrer::Client(url)
2647 } else {
2648 Referrer::Client(self.get_url())
2650 }
2651 }
2652
2653 pub(crate) fn as_window(&self) -> &Window {
2655 self.downcast::<Window>().expect("expected a Window scope")
2656 }
2657
2658 pub(crate) fn insecure_requests_policy(&self) -> InsecureRequestsPolicy {
2660 if let Some(window) = self.downcast::<Window>() {
2661 return window.Document().insecure_requests_policy();
2662 }
2663 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2664 return worker.insecure_requests_policy();
2665 }
2666 debug!("unsupported global, defaulting insecure requests policy to DoNotUpgrade");
2667 InsecureRequestsPolicy::DoNotUpgrade
2668 }
2669
2670 pub(crate) fn has_trustworthy_ancestor_origin(&self) -> bool {
2672 self.downcast::<Window>()
2673 .is_some_and(|window| window.Document().has_trustworthy_ancestor_origin())
2674 }
2675
2676 pub(crate) fn has_trustworthy_ancestor_or_current_origin(&self) -> bool {
2678 self.downcast::<Window>().is_some_and(|window| {
2679 window
2680 .Document()
2681 .has_trustworthy_ancestor_or_current_origin()
2682 })
2683 }
2684
2685 pub(crate) fn report_an_error(&self, error_info: ErrorInfo, value: HandleValue, can_gc: CanGc) {
2687 if self.in_error_reporting_mode.get() {
2689 return;
2690 }
2691
2692 self.in_error_reporting_mode.set(true);
2694
2695 let event = ErrorEvent::new(
2701 self,
2702 atom!("error"),
2703 EventBubbles::DoesNotBubble,
2704 EventCancelable::Cancelable,
2705 error_info.message.as_str().into(),
2706 error_info.filename.as_str().into(),
2707 error_info.lineno,
2708 error_info.column,
2709 value,
2710 can_gc,
2711 );
2712
2713 let not_handled = event
2714 .upcast::<Event>()
2715 .fire(self.upcast::<EventTarget>(), can_gc);
2716
2717 self.in_error_reporting_mode.set(false);
2719
2720 if not_handled {
2722 if let Some(dedicated) = self.downcast::<DedicatedWorkerGlobalScope>() {
2724 dedicated.forward_error_to_worker_object(error_info);
2725 } else if self.is::<Window>() {
2726 if let Some(ref chan) = self.devtools_chan {
2727 let _ = chan.send(ScriptToDevtoolsControlMsg::ReportPageError(
2728 self.pipeline_id,
2729 PageError {
2730 type_: "PageError".to_string(),
2731 error_message: error_info.message.clone(),
2732 source_name: error_info.filename.clone(),
2733 line_text: "".to_string(), line_number: error_info.lineno,
2735 column_number: error_info.column,
2736 category: "script".to_string(),
2737 time_stamp: SystemTime::now()
2738 .duration_since(UNIX_EPOCH)
2739 .unwrap_or_default()
2740 .as_millis() as u64,
2741 error: true,
2742 warning: false,
2743 exception: true,
2744 strict: false,
2745 private: false,
2746 },
2747 ));
2748 }
2749 }
2750 }
2751 }
2752
2753 pub(crate) fn resource_threads(&self) -> &ResourceThreads {
2755 &self.resource_threads
2756 }
2757
2758 pub(crate) fn core_resource_thread(&self) -> CoreResourceThread {
2760 self.resource_threads().sender()
2761 }
2762
2763 pub(crate) fn event_loop_sender(&self) -> Option<ScriptEventLoopSender> {
2767 if let Some(window) = self.downcast::<Window>() {
2768 Some(window.event_loop_sender())
2769 } else if let Some(dedicated) = self.downcast::<DedicatedWorkerGlobalScope>() {
2770 dedicated.event_loop_sender()
2771 } else if let Some(service_worker) = self.downcast::<ServiceWorkerGlobalScope>() {
2772 Some(service_worker.event_loop_sender())
2773 } else {
2774 unreachable!(
2775 "Tried to access event loop sender for incompatible \
2776 GlobalScope (PaintWorklet or DissimilarOriginWindow)"
2777 );
2778 }
2779 }
2780
2781 pub(crate) fn task_manager(&self) -> &TaskManager {
2783 let shared_canceller = self
2784 .downcast::<WorkerGlobalScope>()
2785 .map(WorkerGlobalScope::shared_task_canceller);
2786 self.task_manager.get_or_init(|| {
2787 TaskManager::new(
2788 self.event_loop_sender(),
2789 self.pipeline_id(),
2790 shared_canceller,
2791 )
2792 })
2793 }
2794
2795 pub(crate) fn evaluate_js_on_global_with_result(
2797 &self,
2798 code: &str,
2799 rval: MutableHandleValue,
2800 fetch_options: ScriptFetchOptions,
2801 script_base_url: ServoUrl,
2802 can_gc: CanGc,
2803 introduction_type: Option<&'static CStr>,
2804 ) -> Result<(), JavaScriptEvaluationError> {
2805 let source_code = SourceCode::Text(Rc::new(DOMString::from_string((*code).to_string())));
2806 self.evaluate_script_on_global_with_result(
2807 &source_code,
2808 "",
2809 rval,
2810 1,
2811 fetch_options,
2812 script_base_url,
2813 can_gc,
2814 introduction_type,
2815 )
2816 }
2817
2818 #[allow(unsafe_code)]
2820 #[allow(clippy::too_many_arguments)]
2821 pub(crate) fn evaluate_script_on_global_with_result(
2822 &self,
2823 code: &SourceCode,
2824 filename: &str,
2825 rval: MutableHandleValue,
2826 line_number: u32,
2827 fetch_options: ScriptFetchOptions,
2828 script_base_url: ServoUrl,
2829 can_gc: CanGc,
2830 introduction_type: Option<&'static CStr>,
2831 ) -> Result<(), JavaScriptEvaluationError> {
2832 let cx = GlobalScope::get_cx();
2833
2834 let ar = enter_realm(self);
2835
2836 let _aes = AutoEntryScript::new(self);
2837
2838 unsafe {
2839 rooted!(in(*cx) let mut compiled_script = std::ptr::null_mut::<JSScript>());
2840 match code {
2841 SourceCode::Text(text_code) => {
2842 let mut options = CompileOptionsWrapper::new(*cx, filename, line_number);
2843 if let Some(introduction_type) = introduction_type {
2844 options.set_introduction_type(introduction_type);
2845 }
2846
2847 debug!("compiling dom string");
2848 compiled_script.set(Compile1(
2849 *cx,
2850 options.ptr,
2851 &mut transform_str_to_source_text(text_code),
2852 ));
2853
2854 if compiled_script.is_null() {
2855 debug!("error compiling Dom string");
2856 report_pending_exception(cx, true, InRealm::Entered(&ar), can_gc);
2857 return Err(JavaScriptEvaluationError::CompilationFailure);
2858 }
2859 },
2860 SourceCode::Compiled(pre_compiled_script) => {
2861 let options = InstantiateOptions {
2862 skipFilenameValidation: false,
2863 hideScriptFromDebugger: false,
2864 deferDebugMetadata: false,
2865 eagerDelazificationStrategy_: DelazificationOption::OnDemandOnly,
2866 };
2867 let script = InstantiateGlobalStencil(
2868 *cx,
2869 &options,
2870 *pre_compiled_script.source_code,
2871 ptr::null_mut(),
2872 );
2873 compiled_script.set(script);
2874 },
2875 };
2876
2877 assert!(!compiled_script.is_null());
2878
2879 rooted!(in(*cx) let mut script_private = UndefinedValue());
2880 JS_GetScriptPrivate(*compiled_script, script_private.handle_mut());
2881
2882 if script_private.is_undefined() {
2885 debug!("Set script private for {}", script_base_url);
2886
2887 let module_script_data = Rc::new(ModuleScript::new(
2888 script_base_url,
2889 fetch_options,
2890 None,
2894 ));
2895
2896 SetScriptPrivate(
2897 *compiled_script,
2898 &PrivateValue(Rc::into_raw(module_script_data) as *const _),
2899 );
2900 }
2901
2902 let result = JS_ExecuteScript(*cx, compiled_script.handle(), rval);
2903
2904 if !result {
2905 debug!("error evaluating Dom string");
2906 report_pending_exception(cx, true, InRealm::Entered(&ar), can_gc);
2907 return Err(JavaScriptEvaluationError::EvaluationFailure);
2908 }
2909
2910 maybe_resume_unwind();
2911 Ok(())
2912 }
2913 }
2914
2915 pub(crate) fn schedule_callback(
2917 &self,
2918 callback: OneshotTimerCallback,
2919 duration: Duration,
2920 ) -> OneshotTimerHandle {
2921 self.timers()
2922 .schedule_callback(callback, duration, self.timer_source())
2923 }
2924
2925 pub(crate) fn unschedule_callback(&self, handle: OneshotTimerHandle) {
2926 self.timers().unschedule_callback(handle);
2927 }
2928
2929 pub(crate) fn set_timeout_or_interval(
2931 &self,
2932 callback: TimerCallback,
2933 arguments: Vec<HandleValue>,
2934 timeout: Duration,
2935 is_interval: IsInterval,
2936 can_gc: CanGc,
2937 ) -> Fallible<i32> {
2938 self.timers().set_timeout_or_interval(
2939 self,
2940 callback,
2941 arguments,
2942 timeout,
2943 is_interval,
2944 self.timer_source(),
2945 can_gc,
2946 )
2947 }
2948
2949 pub(crate) fn clear_timeout_or_interval(&self, handle: i32) {
2950 self.timers().clear_timeout_or_interval(self, handle);
2951 }
2952
2953 pub(crate) fn queue_function_as_microtask(&self, callback: Rc<VoidFunction>) {
2954 self.enqueue_microtask(Microtask::User(UserMicrotask {
2955 callback,
2956 pipeline: self.pipeline_id(),
2957 }))
2958 }
2959
2960 pub(crate) fn fire_timer(&self, handle: TimerEventId, can_gc: CanGc) {
2961 self.timers().fire_timer(handle, self, can_gc);
2962 }
2963
2964 pub(crate) fn resume(&self) {
2965 self.timers().resume();
2966 }
2967
2968 pub(crate) fn suspend(&self) {
2969 self.timers().suspend();
2970 }
2971
2972 pub(crate) fn slow_down_timers(&self) {
2973 self.timers().slow_down();
2974 }
2975
2976 pub(crate) fn speed_up_timers(&self) {
2977 self.timers().speed_up();
2978 }
2979
2980 fn timer_source(&self) -> TimerSource {
2981 if self.is::<Window>() {
2982 return TimerSource::FromWindow(self.pipeline_id());
2983 }
2984 if self.is::<WorkerGlobalScope>() {
2985 return TimerSource::FromWorker;
2986 }
2987 unreachable!();
2988 }
2989
2990 pub(crate) fn can_continue_running(&self) -> bool {
2993 if self.is::<Window>() {
2994 return ScriptThread::can_continue_running();
2995 }
2996 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
2997 return !worker.is_closing();
2998 }
2999
3000 true
3002 }
3003
3004 pub(crate) fn perform_a_microtask_checkpoint(&self, can_gc: CanGc) {
3006 if self.can_continue_running() {
3008 self.microtask_queue.checkpoint(
3009 GlobalScope::get_cx(),
3010 |_| Some(DomRoot::from_ref(self)),
3011 vec![DomRoot::from_ref(self)],
3012 can_gc,
3013 );
3014 }
3015 }
3016
3017 pub(crate) fn enqueue_microtask(&self, job: Microtask) {
3019 self.microtask_queue.enqueue(job, GlobalScope::get_cx());
3020 }
3021
3022 pub(crate) fn new_script_pair(&self) -> (ScriptEventLoopSender, ScriptEventLoopReceiver) {
3026 if let Some(window) = self.downcast::<Window>() {
3027 return window.new_script_pair();
3028 }
3029 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3030 return worker.new_script_pair();
3031 }
3032 unreachable!();
3033 }
3034
3035 pub(crate) fn microtask_queue(&self) -> &Rc<MicrotaskQueue> {
3037 &self.microtask_queue
3038 }
3039
3040 pub(crate) fn process_event(&self, msg: CommonScriptMsg) -> bool {
3044 if self.is::<Window>() {
3045 return ScriptThread::process_event(msg);
3046 }
3047 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3048 return worker.process_event(msg);
3049 }
3050 unreachable!();
3051 }
3052
3053 pub(crate) fn runtime_handle(&self) -> ParentRuntime {
3054 if self.is::<Window>() {
3055 ScriptThread::runtime_handle()
3056 } else if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3057 worker.runtime_handle()
3058 } else {
3059 unreachable!()
3060 }
3061 }
3062
3063 #[allow(unsafe_code)]
3067 pub(crate) fn current() -> Option<DomRoot<Self>> {
3068 let cx = Runtime::get()?;
3069 unsafe {
3070 let global = CurrentGlobalOrNull(cx.as_ptr());
3071 if global.is_null() {
3072 None
3073 } else {
3074 Some(global_scope_from_global(global, cx.as_ptr()))
3075 }
3076 }
3077 }
3078
3079 pub(crate) fn entry() -> DomRoot<Self> {
3083 entry_global()
3084 }
3085
3086 pub(crate) fn incumbent() -> Option<DomRoot<Self>> {
3090 incumbent_global()
3091 }
3092
3093 pub(crate) fn performance(&self) -> DomRoot<Performance> {
3094 if let Some(window) = self.downcast::<Window>() {
3095 return window.Performance();
3096 }
3097 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3098 return worker.Performance();
3099 }
3100 unreachable!();
3101 }
3102
3103 pub(crate) fn supported_performance_entry_types(
3105 &self,
3106 cx: SafeJSContext,
3107 retval: MutableHandleValue,
3108 can_gc: CanGc,
3109 ) {
3110 self.frozen_supported_performance_entry_types.get_or_init(
3111 || {
3112 VALID_ENTRY_TYPES
3113 .iter()
3114 .map(|t| DOMString::from(t.to_string()))
3115 .collect()
3116 },
3117 cx,
3118 retval,
3119 can_gc,
3120 );
3121 }
3122
3123 pub(crate) fn get_https_state(&self) -> HttpsState {
3124 self.https_state.get()
3125 }
3126
3127 pub(crate) fn set_https_state(&self, https_state: HttpsState) {
3128 self.https_state.set(https_state);
3129 }
3130
3131 pub(crate) fn is_secure_context(&self) -> bool {
3133 if Some(false) == self.inherited_secure_context {
3138 return false;
3139 }
3140 match self.top_level_creation_url() {
3143 None => {
3144 assert!(
3146 self.downcast::<WorkerGlobalScope>().is_some() ||
3147 self.downcast::<WorkletGlobalScope>().is_some()
3148 );
3149 true
3150 },
3151 Some(top_level_creation_url) => {
3152 assert!(self.downcast::<Window>().is_some());
3153 if top_level_creation_url.scheme() == "blob" &&
3157 Some(true) == self.inherited_secure_context
3158 {
3159 return true;
3160 }
3161 top_level_creation_url.is_potentially_trustworthy()
3162 },
3163 }
3164 }
3165
3166 pub(crate) fn get_csp_list(&self) -> Option<CspList> {
3168 if self.downcast::<Window>().is_some() || self.downcast::<WorkerGlobalScope>().is_some() {
3169 return self.policy_container().csp_list;
3170 }
3171 None
3173 }
3174
3175 pub(crate) fn status_code(&self) -> Option<u16> {
3176 if let Some(window) = self.downcast::<Window>() {
3177 return window.Document().status_code();
3178 }
3179 None
3180 }
3181
3182 #[cfg(feature = "webgpu")]
3183 pub(crate) fn wgpu_id_hub(&self) -> Arc<IdentityHub> {
3184 self.gpu_id_hub.clone()
3185 }
3186
3187 #[cfg(feature = "webgpu")]
3188 pub(crate) fn add_gpu_device(&self, device: &GPUDevice) {
3189 self.gpu_devices
3190 .borrow_mut()
3191 .insert(device.id(), WeakRef::new(device));
3192 }
3193
3194 #[cfg(feature = "webgpu")]
3195 pub(crate) fn remove_gpu_device(&self, device: WebGPUDevice) {
3196 let device = self
3197 .gpu_devices
3198 .borrow_mut()
3199 .remove(&device)
3200 .expect("GPUDevice should still be in devices hashmap");
3201 assert!(device.root().is_none())
3202 }
3203
3204 #[cfg(feature = "webgpu")]
3205 pub(crate) fn gpu_device_lost(
3206 &self,
3207 device: WebGPUDevice,
3208 reason: DeviceLostReason,
3209 msg: String,
3210 ) {
3211 let reason = match reason {
3212 DeviceLostReason::Unknown => GPUDeviceLostReason::Unknown,
3213 DeviceLostReason::Destroyed => GPUDeviceLostReason::Destroyed,
3214 };
3215 let _ac = enter_realm(self);
3216 if let Some(device) = self
3217 .gpu_devices
3218 .borrow_mut()
3219 .get_mut(&device)
3220 .expect("GPUDevice should still be in devices hashmap")
3221 .root()
3222 {
3223 device.lose(reason, msg);
3224 }
3225 }
3226
3227 #[cfg(feature = "webgpu")]
3228 pub(crate) fn handle_uncaptured_gpu_error(
3229 &self,
3230 device: WebGPUDevice,
3231 error: webgpu_traits::Error,
3232 ) {
3233 if let Some(gpu_device) = self
3234 .gpu_devices
3235 .borrow()
3236 .get(&device)
3237 .and_then(|device| device.root())
3238 {
3239 gpu_device.fire_uncaptured_error(error);
3240 } else {
3241 warn!("Recived error for lost GPUDevice!")
3242 }
3243 }
3244
3245 pub(crate) fn current_group_label(&self) -> Option<DOMString> {
3246 self.console_group_stack
3247 .borrow()
3248 .last()
3249 .map(|label| DOMString::from(format!("[{}]", label)))
3250 }
3251
3252 pub(crate) fn push_console_group(&self, group: DOMString) {
3253 self.console_group_stack.borrow_mut().push(group);
3254 }
3255
3256 pub(crate) fn pop_console_group(&self) {
3257 let _ = self.console_group_stack.borrow_mut().pop();
3258 }
3259
3260 pub(crate) fn increment_console_count(&self, label: &DOMString) -> usize {
3261 *self
3262 .console_count_map
3263 .borrow_mut()
3264 .entry(label.clone())
3265 .and_modify(|e| *e += 1)
3266 .or_insert(1)
3267 }
3268
3269 pub(crate) fn reset_console_count(&self, label: &DOMString) -> Result<(), ()> {
3270 match self.console_count_map.borrow_mut().get_mut(label) {
3271 Some(value) => {
3272 *value = 0;
3273 Ok(())
3274 },
3275 None => Err(()),
3276 }
3277 }
3278
3279 pub(crate) fn dynamic_module_list(&self) -> RefMut<'_, DynamicModuleList> {
3280 self.dynamic_modules.borrow_mut()
3281 }
3282
3283 pub(crate) fn structured_clone(
3284 &self,
3285 cx: SafeJSContext,
3286 value: HandleValue,
3287 options: RootedTraceableBox<StructuredSerializeOptions>,
3288 retval: MutableHandleValue,
3289 ) -> Fallible<()> {
3290 let mut rooted = CustomAutoRooter::new(
3291 options
3292 .transfer
3293 .iter()
3294 .map(|js: &RootedTraceableBox<Heap<*mut JSObject>>| js.get())
3295 .collect(),
3296 );
3297 let guard = CustomAutoRooterGuard::new(*cx, &mut rooted);
3298
3299 let data = structuredclone::write(cx, value, Some(guard))?;
3300
3301 structuredclone::read(self, data, retval)?;
3302
3303 Ok(())
3304 }
3305
3306 pub(crate) fn fetch<Listener: FetchResponseListener + PreInvoke + Send + 'static>(
3307 &self,
3308 request_builder: RequestBuilder,
3309 context: Arc<Mutex<Listener>>,
3310 task_source: SendableTaskSource,
3311 ) {
3312 let network_listener = NetworkListener {
3313 context,
3314 task_source,
3315 };
3316 self.fetch_with_network_listener(request_builder, network_listener);
3317 }
3318
3319 pub(crate) fn fetch_with_network_listener<
3320 Listener: FetchResponseListener + PreInvoke + Send + 'static,
3321 >(
3322 &self,
3323 request_builder: RequestBuilder,
3324 network_listener: NetworkListener<Listener>,
3325 ) {
3326 fetch_async(
3327 &self.core_resource_thread(),
3328 request_builder,
3329 None,
3330 network_listener.into_callback(),
3331 );
3332 }
3333
3334 pub(crate) fn unminified_js_dir(&self) -> Option<String> {
3335 self.unminified_js_dir.clone()
3336 }
3337
3338 pub(crate) fn set_byte_length_queuing_strategy_size(&self, function: Rc<Function>) {
3339 if self
3340 .byte_length_queuing_strategy_size_function
3341 .set(function)
3342 .is_err()
3343 {
3344 warn!("byte length queuing strategy size function is set twice.");
3345 };
3346 }
3347
3348 pub(crate) fn get_byte_length_queuing_strategy_size(&self) -> Option<Rc<Function>> {
3349 self.byte_length_queuing_strategy_size_function
3350 .get()
3351 .cloned()
3352 }
3353
3354 pub(crate) fn set_count_queuing_strategy_size(&self, function: Rc<Function>) {
3355 if self
3356 .count_queuing_strategy_size_function
3357 .set(function)
3358 .is_err()
3359 {
3360 warn!("count queuing strategy size function is set twice.");
3361 };
3362 }
3363
3364 pub(crate) fn get_count_queuing_strategy_size(&self) -> Option<Rc<Function>> {
3365 self.count_queuing_strategy_size_function.get().cloned()
3366 }
3367
3368 pub(crate) fn add_notification_permission_request_callback(
3369 &self,
3370 callback_id: String,
3371 callback: Rc<NotificationPermissionCallback>,
3372 ) {
3373 self.notification_permission_request_callback_map
3374 .borrow_mut()
3375 .insert(callback_id, callback.clone());
3376 }
3377
3378 pub(crate) fn remove_notification_permission_request_callback(
3379 &self,
3380 callback_id: String,
3381 ) -> Option<Rc<NotificationPermissionCallback>> {
3382 self.notification_permission_request_callback_map
3383 .borrow_mut()
3384 .remove(&callback_id)
3385 }
3386
3387 pub(crate) fn trusted_types(&self, can_gc: CanGc) -> DomRoot<TrustedTypePolicyFactory> {
3388 if let Some(window) = self.downcast::<Window>() {
3389 return window.TrustedTypes(can_gc);
3390 }
3391 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3392 return worker.TrustedTypes(can_gc);
3393 }
3394 unreachable!();
3395 }
3396
3397 pub(crate) fn append_reporting_observer(&self, reporting_observer: &ReportingObserver) {
3398 if let Some(window) = self.downcast::<Window>() {
3399 return window.append_reporting_observer(DomRoot::from_ref(reporting_observer));
3400 }
3401 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3402 return worker.append_reporting_observer(DomRoot::from_ref(reporting_observer));
3403 }
3404 unreachable!();
3405 }
3406
3407 pub(crate) fn remove_reporting_observer(&self, reporting_observer: &ReportingObserver) {
3408 if let Some(window) = self.downcast::<Window>() {
3409 return window.remove_reporting_observer(reporting_observer);
3410 }
3411 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3412 return worker.remove_reporting_observer(reporting_observer);
3413 }
3414 unreachable!();
3415 }
3416
3417 pub(crate) fn registered_reporting_observers(&self) -> Vec<DomRoot<ReportingObserver>> {
3418 if let Some(window) = self.downcast::<Window>() {
3419 return window.registered_reporting_observers();
3420 }
3421 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3422 return worker.registered_reporting_observers();
3423 }
3424 unreachable!();
3425 }
3426
3427 pub(crate) fn append_report(&self, report: Report) {
3428 if let Some(window) = self.downcast::<Window>() {
3429 return window.append_report(report);
3430 }
3431 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3432 return worker.append_report(report);
3433 }
3434 unreachable!();
3435 }
3436
3437 pub(crate) fn buffered_reports(&self) -> Vec<Report> {
3438 if let Some(window) = self.downcast::<Window>() {
3439 return window.buffered_reports();
3440 }
3441 if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
3442 return worker.buffered_reports();
3443 }
3444 unreachable!();
3445 }
3446
3447 pub(crate) fn import_map(&self) -> Ref<'_, ImportMap> {
3448 self.import_map.borrow()
3449 }
3450
3451 pub(crate) fn import_map_mut(&self) -> RefMut<'_, ImportMap> {
3452 self.import_map.borrow_mut()
3453 }
3454
3455 pub(crate) fn resolved_module_set(&self) -> Ref<'_, HashSet<ResolvedModule>> {
3456 self.resolved_module_set.borrow()
3457 }
3458
3459 pub(crate) fn resolved_module_set_mut(&self) -> RefMut<'_, HashSet<ResolvedModule>> {
3460 self.resolved_module_set.borrow_mut()
3461 }
3462
3463 pub(crate) fn add_module_to_resolved_module_set(
3465 &self,
3466 base_url: &str,
3467 specifier: &str,
3468 specifier_url: Option<ServoUrl>,
3469 ) {
3470 if self.is::<Window>() {
3473 let record =
3477 ResolvedModule::new(base_url.to_owned(), specifier.to_owned(), specifier_url);
3478 self.resolved_module_set.borrow_mut().insert(record);
3480 }
3481 }
3482}
3483
3484#[allow(unsafe_code)]
3486unsafe fn global_scope_from_global(
3487 global: *mut JSObject,
3488 cx: *mut JSContext,
3489) -> DomRoot<GlobalScope> {
3490 unsafe {
3491 assert!(!global.is_null());
3492 let clasp = get_object_class(global);
3493 assert_ne!(
3494 ((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)),
3495 0
3496 );
3497 root_from_object(global, cx).unwrap()
3498 }
3499}
3500
3501#[allow(unsafe_code)]
3503unsafe fn global_scope_from_global_static(global: *mut JSObject) -> DomRoot<GlobalScope> {
3504 assert!(!global.is_null());
3505 let clasp = unsafe { get_object_class(global) };
3506
3507 unsafe {
3508 assert_ne!(
3509 ((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)),
3510 0
3511 );
3512 }
3513
3514 root_from_object_static(global).unwrap()
3515}
3516
3517#[allow(unsafe_code)]
3518impl GlobalScopeHelpers<crate::DomTypeHolder> for GlobalScope {
3519 unsafe fn from_context(cx: *mut JSContext, realm: InRealm) -> DomRoot<Self> {
3520 unsafe { GlobalScope::from_context(cx, realm) }
3521 }
3522
3523 fn get_cx() -> SafeJSContext {
3524 GlobalScope::get_cx()
3525 }
3526
3527 unsafe fn from_object(obj: *mut JSObject) -> DomRoot<Self> {
3528 GlobalScope::from_object(obj)
3529 }
3530
3531 fn from_reflector(reflector: &impl DomObject, realm: InRealm) -> DomRoot<Self> {
3532 GlobalScope::from_reflector(reflector, realm)
3533 }
3534
3535 fn origin(&self) -> &MutableOrigin {
3536 GlobalScope::origin(self)
3537 }
3538
3539 fn incumbent() -> Option<DomRoot<Self>> {
3540 GlobalScope::incumbent()
3541 }
3542
3543 fn perform_a_microtask_checkpoint(&self, can_gc: CanGc) {
3544 GlobalScope::perform_a_microtask_checkpoint(self, can_gc)
3545 }
3546
3547 fn get_url(&self) -> ServoUrl {
3548 self.get_url()
3549 }
3550
3551 fn is_secure_context(&self) -> bool {
3552 self.is_secure_context()
3553 }
3554}