1use std::borrow::Cow;
6use std::cell::{RefCell, RefMut};
7use std::default::Default;
8use std::rc::Rc;
9use std::sync::Arc;
10use std::sync::atomic::{AtomicBool, Ordering};
11use std::time::Duration;
12
13use base::IpcSend;
14use base::cross_process_instant::CrossProcessInstant;
15use base::id::{PipelineId, PipelineNamespace};
16use constellation_traits::WorkerGlobalScopeInit;
17use content_security_policy::CspList;
18use crossbeam_channel::Receiver;
19use devtools_traits::{DevtoolScriptControlMsg, WorkerId};
20use dom_struct::dom_struct;
21use encoding_rs::UTF_8;
22use fonts::FontContext;
23use headers::{HeaderMapExt, ReferrerPolicy as ReferrerPolicyHeader};
24use ipc_channel::ipc::IpcSender;
25use js::jsapi::JS_AddInterruptCallback;
26use js::jsval::UndefinedValue;
27use js::panic::maybe_resume_unwind;
28use js::rust::{HandleValue, MutableHandleValue, ParentRuntime};
29use mime::Mime;
30use net_traits::policy_container::PolicyContainer;
31use net_traits::request::{
32 CredentialsMode, Destination, InsecureRequestsPolicy, ParserMetadata,
33 RequestBuilder as NetRequestInit, RequestId,
34};
35use net_traits::{FetchMetadata, Metadata, NetworkError, ReferrerPolicy, ResourceFetchTiming};
36use profile_traits::mem::{ProcessReports, perform_memory_report};
37use servo_url::{MutableOrigin, ServoUrl};
38use timers::TimerScheduler;
39use uuid::Uuid;
40
41use crate::dom::bindings::cell::{DomRefCell, Ref};
42use crate::dom::bindings::codegen::Bindings::ImageBitmapBinding::{
43 ImageBitmapOptions, ImageBitmapSource,
44};
45use crate::dom::bindings::codegen::Bindings::MessagePortBinding::StructuredSerializeOptions;
46use crate::dom::bindings::codegen::Bindings::ReportingObserverBinding::Report;
47use crate::dom::bindings::codegen::Bindings::RequestBinding::RequestInit;
48use crate::dom::bindings::codegen::Bindings::VoidFunctionBinding::VoidFunction;
49use crate::dom::bindings::codegen::Bindings::WorkerBinding::WorkerType;
50use crate::dom::bindings::codegen::Bindings::WorkerGlobalScopeBinding::WorkerGlobalScopeMethods;
51use crate::dom::bindings::codegen::UnionTypes::{
52 RequestOrUSVString, TrustedScriptOrString, TrustedScriptOrStringOrFunction,
53 TrustedScriptURLOrUSVString,
54};
55use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
56use crate::dom::bindings::inheritance::Castable;
57use crate::dom::bindings::refcounted::Trusted;
58use crate::dom::bindings::reflector::{DomGlobal, DomObject};
59use crate::dom::bindings::root::{DomRoot, MutNullableDom};
60use crate::dom::bindings::str::{DOMString, USVString};
61use crate::dom::bindings::trace::RootedTraceableBox;
62use crate::dom::bindings::utils::define_all_exposed_interfaces;
63use crate::dom::crypto::Crypto;
64use crate::dom::csp::{GlobalCspReporting, Violation, parse_csp_list_from_metadata};
65use crate::dom::dedicatedworkerglobalscope::{
66 AutoWorkerReset, DedicatedWorkerGlobalScope, interrupt_callback,
67};
68use crate::dom::globalscope::GlobalScope;
69use crate::dom::htmlscriptelement::{SCRIPT_JS_MIMES, ScriptOrigin, ScriptType};
70use crate::dom::indexeddb::idbfactory::IDBFactory;
71use crate::dom::performance::performance::Performance;
72use crate::dom::performance::performanceresourcetiming::InitiatorType;
73use crate::dom::promise::Promise;
74use crate::dom::reportingendpoint::{ReportingEndpoint, SendReportsToEndpoints};
75use crate::dom::reportingobserver::ReportingObserver;
76use crate::dom::trustedscripturl::TrustedScriptURL;
77use crate::dom::trustedtypepolicyfactory::TrustedTypePolicyFactory;
78use crate::dom::types::ImageBitmap;
79#[cfg(feature = "webgpu")]
80use crate::dom::webgpu::identityhub::IdentityHub;
81use crate::dom::window::{base64_atob, base64_btoa};
82use crate::dom::worker::TrustedWorkerAddress;
83use crate::dom::workerlocation::WorkerLocation;
84use crate::dom::workernavigator::WorkerNavigator;
85use crate::fetch::{CspViolationsProcessor, Fetch, load_whole_resource};
86use crate::messaging::{CommonScriptMsg, ScriptEventLoopReceiver, ScriptEventLoopSender};
87use crate::microtask::{Microtask, MicrotaskQueue, UserMicrotask};
88use crate::network_listener::{FetchResponseListener, ResourceTimingListener, submit_timing};
89use crate::realms::{InRealm, enter_realm};
90use crate::script_module::ScriptFetchOptions;
91use crate::script_runtime::{CanGc, IntroductionType, JSContext, JSContextHelper, Runtime};
92use crate::task::TaskCanceller;
93use crate::timers::{IsInterval, TimerCallback};
94use crate::unminify::unminify_js;
95
96pub(crate) fn prepare_workerscope_init(
97 global: &GlobalScope,
98 devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>,
99 worker_id: Option<WorkerId>,
100) -> WorkerGlobalScopeInit {
101 WorkerGlobalScopeInit {
102 resource_threads: global.resource_threads().clone(),
103 storage_threads: global.storage_threads().clone(),
104 mem_profiler_chan: global.mem_profiler_chan().clone(),
105 to_devtools_sender: global.devtools_chan().cloned(),
106 time_profiler_chan: global.time_profiler_chan().clone(),
107 from_devtools_sender: devtools_sender,
108 script_to_constellation_chan: global.script_to_constellation_chan().clone(),
109 script_to_embedder_chan: global.script_to_embedder_chan().clone(),
110 worker_id: worker_id.unwrap_or_else(|| WorkerId(Uuid::new_v4())),
111 pipeline_id: global.pipeline_id(),
112 origin: global.origin().immutable().clone(),
113 creation_url: global.creation_url().clone(),
114 inherited_secure_context: Some(global.is_secure_context()),
115 unminify_js: global.unminify_js(),
116 }
117}
118
119pub(crate) struct ScriptFetchContext {
120 scope: Trusted<WorkerGlobalScope>,
121 response: Option<Metadata>,
122 body_bytes: Vec<u8>,
123 url: ServoUrl,
124 worker: TrustedWorkerAddress,
125 policy_container: PolicyContainer,
126}
127
128impl ScriptFetchContext {
129 pub(crate) fn new(
130 scope: Trusted<WorkerGlobalScope>,
131 url: ServoUrl,
132 worker: TrustedWorkerAddress,
133 policy_container: PolicyContainer,
134 ) -> ScriptFetchContext {
135 ScriptFetchContext {
136 scope,
137 response: None,
138 body_bytes: Vec::new(),
139 url,
140 worker,
141 policy_container,
142 }
143 }
144}
145
146impl FetchResponseListener for ScriptFetchContext {
147 fn process_request_body(&mut self, _request_id: RequestId) {}
148
149 fn process_request_eof(&mut self, _request_id: RequestId) {}
150
151 fn process_response(
152 &mut self,
153 _request_id: RequestId,
154 metadata: Result<FetchMetadata, NetworkError>,
155 ) {
156 self.response = metadata.ok().map(|m| match m {
157 FetchMetadata::Unfiltered(m) => m,
158 FetchMetadata::Filtered { unsafe_, .. } => unsafe_,
159 });
160 }
161
162 fn process_response_chunk(&mut self, _request_id: RequestId, mut chunk: Vec<u8>) {
163 self.body_bytes.append(&mut chunk);
164 }
165
166 fn process_response_eof(
167 mut self,
168 _request_id: RequestId,
169 response: Result<ResourceFetchTiming, NetworkError>,
170 ) {
171 let scope = self.scope.root();
172
173 if response
174 .as_ref()
175 .inspect_err(|e| error!("error loading script {} ({:?})", self.url, e))
176 .is_err() ||
177 self.response.is_none()
178 {
179 scope.on_complete(None, self.worker.clone(), CanGc::note());
180 return;
181 }
182 let metadata = self.response.take().unwrap();
183
184 scope.set_url(metadata.final_url.clone());
189
190 scope
192 .initialize_policy_container_for_worker_global_scope(&metadata, &self.policy_container);
193 scope.set_endpoints_list(ReportingEndpoint::parse_reporting_endpoints_header(
194 &metadata.final_url.clone(),
195 &metadata.headers,
196 ));
197 scope
198 .upcast::<GlobalScope>()
199 .set_https_state(metadata.https_state);
200
201 if !metadata.status.is_success() {
208 scope.on_complete(None, self.worker.clone(), CanGc::note());
210 return;
211 }
212
213 let is_http_scheme = matches!(metadata.final_url.scheme(), "http" | "https");
216 let not_a_javascript_mime_type = !metadata.content_type.clone().is_some_and(|ct| {
218 let mime: Mime = ct.into_inner().into();
219 SCRIPT_JS_MIMES.contains(&mime.essence_str())
220 });
221
222 if is_http_scheme && not_a_javascript_mime_type {
223 scope.on_complete(None, self.worker.clone(), CanGc::note());
225 return;
226 }
227
228 let (source, _, _) = UTF_8.decode(&self.body_bytes);
230
231 scope.on_complete(Some(source), self.worker.clone(), CanGc::note());
236
237 if let Ok(response) = response {
238 submit_timing(&self, &response, CanGc::note());
239 }
240 }
241
242 fn process_csp_violations(
243 &mut self,
244 _request_id: RequestId,
245 violations: Vec<content_security_policy::Violation>,
246 ) {
247 let scope = self.scope.root();
248
249 if let Some(worker_scope) = scope.downcast::<DedicatedWorkerGlobalScope>() {
250 worker_scope.report_csp_violations(violations);
251 }
252 }
253}
254
255impl ResourceTimingListener for ScriptFetchContext {
256 fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
257 (InitiatorType::Other, self.url.clone())
258 }
259
260 fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
261 self.scope.root().global()
262 }
263}
264
265#[dom_struct]
267pub(crate) struct WorkerGlobalScope {
268 globalscope: GlobalScope,
269
270 #[conditional_malloc_size_of]
272 microtask_queue: Rc<MicrotaskQueue>,
273
274 worker_name: DOMString,
275 worker_type: WorkerType,
276
277 #[no_trace]
278 worker_id: WorkerId,
279 #[no_trace]
280 worker_url: DomRefCell<ServoUrl>,
281 #[conditional_malloc_size_of]
282 closing: Arc<AtomicBool>,
283 execution_ready: AtomicBool,
284 #[ignore_malloc_size_of = "Defined in js"]
285 runtime: DomRefCell<Option<Runtime>>,
286 location: MutNullableDom<WorkerLocation>,
287 navigator: MutNullableDom<WorkerNavigator>,
288 #[no_trace]
289 policy_container: DomRefCell<PolicyContainer>,
291
292 #[ignore_malloc_size_of = "Defined in ipc-channel"]
293 #[no_trace]
294 _devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>,
297
298 #[ignore_malloc_size_of = "Defined in crossbeam"]
299 #[no_trace]
300 devtools_receiver: Option<Receiver<DevtoolScriptControlMsg>>,
302
303 #[no_trace]
304 navigation_start: CrossProcessInstant,
305 performance: MutNullableDom<Performance>,
306 indexeddb: MutNullableDom<IDBFactory>,
307 trusted_types: MutNullableDom<TrustedTypePolicyFactory>,
308
309 #[no_trace]
312 timer_scheduler: RefCell<TimerScheduler>,
313
314 #[no_trace]
315 insecure_requests_policy: InsecureRequestsPolicy,
316
317 reporting_observer_list: DomRefCell<Vec<DomRoot<ReportingObserver>>>,
319
320 report_list: DomRefCell<Vec<Report>>,
322
323 #[no_trace]
325 endpoints_list: DomRefCell<Vec<ReportingEndpoint>>,
326}
327
328impl WorkerGlobalScope {
329 #[allow(clippy::too_many_arguments)]
330 pub(crate) fn new_inherited(
331 init: WorkerGlobalScopeInit,
332 worker_name: DOMString,
333 worker_type: WorkerType,
334 worker_url: ServoUrl,
335 runtime: Runtime,
336 devtools_receiver: Receiver<DevtoolScriptControlMsg>,
337 closing: Arc<AtomicBool>,
338 #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
339 insecure_requests_policy: InsecureRequestsPolicy,
340 font_context: Option<Arc<FontContext>>,
341 ) -> Self {
342 PipelineNamespace::auto_install();
344
345 let devtools_receiver = match init.from_devtools_sender {
346 Some(..) => Some(devtools_receiver),
347 None => None,
348 };
349
350 Self {
351 globalscope: GlobalScope::new_inherited(
352 init.pipeline_id,
353 init.to_devtools_sender,
354 init.mem_profiler_chan,
355 init.time_profiler_chan,
356 init.script_to_constellation_chan,
357 init.script_to_embedder_chan,
358 init.resource_threads,
359 init.storage_threads,
360 MutableOrigin::new(init.origin),
361 init.creation_url,
362 None,
363 #[cfg(feature = "webgpu")]
364 gpu_id_hub,
365 init.inherited_secure_context,
366 init.unminify_js,
367 font_context,
368 ),
369 microtask_queue: runtime.microtask_queue.clone(),
370 worker_id: init.worker_id,
371 worker_name,
372 worker_type,
373 worker_url: DomRefCell::new(worker_url),
374 closing,
375 execution_ready: AtomicBool::new(false),
376 runtime: DomRefCell::new(Some(runtime)),
377 location: Default::default(),
378 navigator: Default::default(),
379 policy_container: Default::default(),
380 devtools_receiver,
381 _devtools_sender: init.from_devtools_sender,
382 navigation_start: CrossProcessInstant::now(),
383 performance: Default::default(),
384 indexeddb: Default::default(),
385 timer_scheduler: RefCell::default(),
386 insecure_requests_policy,
387 trusted_types: Default::default(),
388 reporting_observer_list: Default::default(),
389 report_list: Default::default(),
390 endpoints_list: Default::default(),
391 }
392 }
393
394 pub(crate) fn enqueue_microtask(&self, job: Microtask) {
395 self.microtask_queue.enqueue(job, GlobalScope::get_cx());
396 }
397
398 pub(crate) fn perform_a_microtask_checkpoint(&self, can_gc: CanGc) {
400 if !self.is_closing() {
402 self.microtask_queue.checkpoint(
403 GlobalScope::get_cx(),
404 |_| Some(DomRoot::from_ref(&self.globalscope)),
405 vec![DomRoot::from_ref(&self.globalscope)],
406 can_gc,
407 );
408 }
409 }
410
411 pub(crate) fn insecure_requests_policy(&self) -> InsecureRequestsPolicy {
413 self.insecure_requests_policy
414 }
415
416 pub(crate) fn clear_js_runtime(&self) {
418 self.upcast::<GlobalScope>()
419 .remove_web_messaging_and_dedicated_workers_infra();
420
421 let runtime = self.runtime.borrow_mut().take();
423 drop(runtime);
424 }
425
426 pub(crate) fn runtime_handle(&self) -> ParentRuntime {
427 self.runtime
428 .borrow()
429 .as_ref()
430 .unwrap()
431 .prepare_for_new_child()
432 }
433
434 pub(crate) fn devtools_receiver(&self) -> Option<&Receiver<DevtoolScriptControlMsg>> {
435 self.devtools_receiver.as_ref()
436 }
437
438 #[expect(unsafe_code)]
439 pub(crate) fn get_cx(&self) -> JSContext {
440 unsafe { JSContext::from_ptr(js::rust::Runtime::get().unwrap().as_ptr()) }
441 }
442
443 pub(crate) fn is_closing(&self) -> bool {
444 self.closing.load(Ordering::SeqCst)
445 }
446
447 pub(crate) fn is_execution_ready(&self) -> bool {
448 self.execution_ready.load(Ordering::Relaxed)
449 }
450
451 pub(crate) fn get_url(&self) -> Ref<'_, ServoUrl> {
452 self.worker_url.borrow()
453 }
454
455 pub(crate) fn set_url(&self, url: ServoUrl) {
456 *self.worker_url.borrow_mut() = url;
457 }
458
459 pub(crate) fn worker_name(&self) -> DOMString {
460 self.worker_name.clone()
461 }
462
463 pub(crate) fn worker_id(&self) -> WorkerId {
464 self.worker_id
465 }
466
467 pub(crate) fn pipeline_id(&self) -> PipelineId {
468 self.globalscope.pipeline_id()
469 }
470
471 pub(crate) fn policy_container(&self) -> Ref<'_, PolicyContainer> {
472 self.policy_container.borrow()
473 }
474
475 pub(crate) fn set_csp_list(&self, csp_list: Option<CspList>) {
476 self.policy_container.borrow_mut().set_csp_list(csp_list);
477 }
478
479 pub(crate) fn set_referrer_policy(&self, referrer_policy: ReferrerPolicy) {
480 self.policy_container
481 .borrow_mut()
482 .set_referrer_policy(referrer_policy);
483 }
484
485 pub(crate) fn append_reporting_observer(&self, reporting_observer: DomRoot<ReportingObserver>) {
486 self.reporting_observer_list
487 .borrow_mut()
488 .push(reporting_observer);
489 }
490
491 pub(crate) fn remove_reporting_observer(&self, reporting_observer: &ReportingObserver) {
492 if let Some(index) = self
493 .reporting_observer_list
494 .borrow()
495 .iter()
496 .position(|observer| &**observer == reporting_observer)
497 {
498 self.reporting_observer_list.borrow_mut().remove(index);
499 }
500 }
501
502 pub(crate) fn registered_reporting_observers(&self) -> Vec<DomRoot<ReportingObserver>> {
503 self.reporting_observer_list.borrow().clone()
504 }
505
506 pub(crate) fn append_report(&self, report: Report) {
507 self.report_list.borrow_mut().push(report);
508 let trusted_worker = Trusted::new(self);
509 self.upcast::<GlobalScope>()
510 .task_manager()
511 .dom_manipulation_task_source()
512 .queue(task!(send_to_reporting_endpoints: move || {
513 let worker = trusted_worker.root();
514 let reports = std::mem::take(&mut *worker.report_list.borrow_mut());
515 worker.upcast::<GlobalScope>().send_reports_to_endpoints(
516 reports,
517 worker.endpoints_list.borrow().clone(),
518 );
519 }));
520 }
521
522 pub(crate) fn buffered_reports(&self) -> Vec<Report> {
523 self.report_list.borrow().clone()
524 }
525
526 pub(crate) fn set_endpoints_list(&self, endpoints: Option<Vec<ReportingEndpoint>>) {
527 if let Some(endpoints) = endpoints {
528 *self.endpoints_list.borrow_mut() = endpoints;
529 }
530 }
531
532 pub(crate) fn timer_scheduler(&self) -> RefMut<'_, TimerScheduler> {
534 self.timer_scheduler.borrow_mut()
535 }
536
537 pub(crate) fn shared_task_canceller(&self) -> TaskCanceller {
540 TaskCanceller {
541 cancelled: self.closing.clone(),
542 }
543 }
544
545 fn initialize_policy_container_for_worker_global_scope(
548 &self,
549 metadata: &Metadata,
550 parent_policy_container: &PolicyContainer,
551 ) {
552 if metadata.final_url.is_local_scheme() {
557 self.set_csp_list(parent_policy_container.csp_list.clone());
563 self.set_referrer_policy(parent_policy_container.get_referrer_policy());
564 return;
565 }
566 self.set_csp_list(parse_csp_list_from_metadata(&metadata.headers));
568 let referrer_policy = metadata
571 .headers
572 .as_ref()
573 .and_then(|headers| headers.typed_get::<ReferrerPolicyHeader>())
574 .into();
575 self.set_referrer_policy(referrer_policy);
576 }
577
578 #[expect(unsafe_code)]
580 fn on_complete(
581 &self,
582 script: Option<Cow<'_, str>>,
583 worker: TrustedWorkerAddress,
584 can_gc: CanGc,
585 ) {
586 let dedicated_worker_scope = self
587 .downcast::<DedicatedWorkerGlobalScope>()
588 .expect("Only DedicatedWorkerGlobalScope is supported for now");
589
590 let Some(script) = script else {
591 dedicated_worker_scope.forward_simple_error_at_worker(worker.clone());
594
595 return;
597 };
598
599 unsafe {
600 JS_AddInterruptCallback(*self.get_cx(), Some(interrupt_callback));
602 }
603
604 if self.is_closing() {
605 return;
606 }
607
608 {
609 let _ar = AutoWorkerReset::new(dedicated_worker_scope, worker);
610 let realm = enter_realm(self);
611 define_all_exposed_interfaces(
612 dedicated_worker_scope.upcast(),
613 InRealm::entered(&realm),
614 can_gc,
615 );
616 self.execution_ready.store(true, Ordering::Relaxed);
617 self.execute_script(DOMString::from(script), can_gc);
618 dedicated_worker_scope.fire_queued_messages(can_gc);
619 }
620 }
621}
622
623impl WorkerGlobalScopeMethods<crate::DomTypeHolder> for WorkerGlobalScope {
624 fn Self_(&self) -> DomRoot<WorkerGlobalScope> {
626 DomRoot::from_ref(self)
627 }
628
629 fn IndexedDB(&self) -> DomRoot<IDBFactory> {
631 self.indexeddb.or_init(|| {
632 let global_scope = self.upcast::<GlobalScope>();
633 IDBFactory::new(global_scope, CanGc::note())
634 })
635 }
636
637 fn Location(&self) -> DomRoot<WorkerLocation> {
639 self.location
640 .or_init(|| WorkerLocation::new(self, self.worker_url.borrow().clone(), CanGc::note()))
641 }
642
643 fn ImportScripts(
645 &self,
646 url_strings: Vec<TrustedScriptURLOrUSVString>,
647 can_gc: CanGc,
648 ) -> ErrorResult {
649 if self.worker_type == WorkerType::Module {
652 return Err(Error::Type(
653 "importScripts() is not allowed in module workers".to_string(),
654 ));
655 }
656
657 let mut urls = Vec::with_capacity(url_strings.len());
659 for url in url_strings {
661 let url = TrustedScriptURL::get_trusted_script_url_compliant_string(
665 self.upcast::<GlobalScope>(),
666 url,
667 "WorkerGlobalScope",
668 "importScripts",
669 can_gc,
670 )?;
671 let url = self.worker_url.borrow().join(&url.str());
672 match url {
673 Ok(url) => urls.push(url),
674 Err(_) => return Err(Error::Syntax(None)),
675 };
676 }
677
678 rooted!(in(*self.get_cx()) let mut rval = UndefinedValue());
679 for url in urls {
680 let global_scope = self.upcast::<GlobalScope>();
681 let request = NetRequestInit::new(
682 global_scope.webview_id(),
683 url.clone(),
684 global_scope.get_referrer(),
685 )
686 .destination(Destination::Script)
687 .credentials_mode(CredentialsMode::Include)
688 .parser_metadata(ParserMetadata::NotParserInserted)
689 .use_url_credentials(true)
690 .origin(global_scope.origin().immutable().clone())
691 .insecure_requests_policy(self.insecure_requests_policy())
692 .policy_container(global_scope.policy_container())
693 .has_trustworthy_ancestor_origin(
694 global_scope.has_trustworthy_ancestor_or_current_origin(),
695 )
696 .pipeline_id(Some(self.upcast::<GlobalScope>().pipeline_id()));
697
698 let (url, source) = match load_whole_resource(
699 request,
700 &global_scope.resource_threads().sender(),
701 global_scope,
702 &WorkerCspProcessor {
703 global_scope: DomRoot::from_ref(global_scope),
704 },
705 can_gc,
706 ) {
707 Err(_) => return Err(Error::Network),
708 Ok((metadata, bytes)) => {
709 if !metadata.status.is_success() {
712 return Err(Error::Network);
713 }
714
715 let not_a_javascript_mime_type =
717 !metadata.content_type.clone().is_some_and(|ct| {
718 let mime: Mime = ct.into_inner().into();
719 SCRIPT_JS_MIMES.contains(&mime.essence_str())
720 });
721 if not_a_javascript_mime_type {
722 return Err(Error::Network);
723 }
724
725 (metadata.final_url, String::from_utf8(bytes).unwrap())
726 },
727 };
728
729 let options = self
730 .runtime
731 .borrow()
732 .as_ref()
733 .unwrap()
734 .new_compile_options(url.as_str(), 1);
735 #[allow(unsafe_code)]
736 let mut cx =
737 unsafe { js::context::JSContext::from_ptr(js::rust::Runtime::get().unwrap()) };
738 let result = js::rust::evaluate_script(
739 &mut cx,
740 self.reflector().get_jsobject(),
741 &source,
742 rval.handle_mut(),
743 options,
744 );
745
746 maybe_resume_unwind();
747
748 match result {
749 Ok(_) => (),
750 Err(_) => {
751 if self.is_closing() {
752 println!("evaluate_script failed (terminated)");
755 } else {
756 println!("evaluate_script failed");
757 return Err(Error::JSFailed);
758 }
759 },
760 }
761 }
762
763 Ok(())
764 }
765
766 error_event_handler!(error, GetOnerror, SetOnerror);
768
769 event_handler!(languagechange, GetOnlanguagechange, SetOnlanguagechange);
771
772 event_handler!(offline, GetOnoffline, SetOnoffline);
774
775 event_handler!(online, GetOnonline, SetOnonline);
777
778 event_handler!(
780 rejectionhandled,
781 GetOnrejectionhandled,
782 SetOnrejectionhandled
783 );
784
785 event_handler!(
787 unhandledrejection,
788 GetOnunhandledrejection,
789 SetOnunhandledrejection
790 );
791
792 fn Navigator(&self) -> DomRoot<WorkerNavigator> {
794 self.navigator
795 .or_init(|| WorkerNavigator::new(self, CanGc::note()))
796 }
797
798 fn Crypto(&self) -> DomRoot<Crypto> {
800 self.upcast::<GlobalScope>().crypto(CanGc::note())
801 }
802
803 fn Btoa(&self, btoa: DOMString) -> Fallible<DOMString> {
805 base64_btoa(btoa)
806 }
807
808 fn Atob(&self, atob: DOMString) -> Fallible<DOMString> {
810 base64_atob(atob)
811 }
812
813 fn SetTimeout(
815 &self,
816 _cx: JSContext,
817 callback: TrustedScriptOrStringOrFunction,
818 timeout: i32,
819 args: Vec<HandleValue>,
820 can_gc: CanGc,
821 ) -> Fallible<i32> {
822 let callback = match callback {
823 TrustedScriptOrStringOrFunction::String(i) => {
824 TimerCallback::StringTimerCallback(TrustedScriptOrString::String(i))
825 },
826 TrustedScriptOrStringOrFunction::TrustedScript(i) => {
827 TimerCallback::StringTimerCallback(TrustedScriptOrString::TrustedScript(i))
828 },
829 TrustedScriptOrStringOrFunction::Function(i) => TimerCallback::FunctionTimerCallback(i),
830 };
831 self.upcast::<GlobalScope>().set_timeout_or_interval(
832 callback,
833 args,
834 Duration::from_millis(timeout.max(0) as u64),
835 IsInterval::NonInterval,
836 can_gc,
837 )
838 }
839
840 fn ClearTimeout(&self, handle: i32) {
842 self.upcast::<GlobalScope>()
843 .clear_timeout_or_interval(handle);
844 }
845
846 fn SetInterval(
848 &self,
849 _cx: JSContext,
850 callback: TrustedScriptOrStringOrFunction,
851 timeout: i32,
852 args: Vec<HandleValue>,
853 can_gc: CanGc,
854 ) -> Fallible<i32> {
855 let callback = match callback {
856 TrustedScriptOrStringOrFunction::String(i) => {
857 TimerCallback::StringTimerCallback(TrustedScriptOrString::String(i))
858 },
859 TrustedScriptOrStringOrFunction::TrustedScript(i) => {
860 TimerCallback::StringTimerCallback(TrustedScriptOrString::TrustedScript(i))
861 },
862 TrustedScriptOrStringOrFunction::Function(i) => TimerCallback::FunctionTimerCallback(i),
863 };
864 self.upcast::<GlobalScope>().set_timeout_or_interval(
865 callback,
866 args,
867 Duration::from_millis(timeout.max(0) as u64),
868 IsInterval::Interval,
869 can_gc,
870 )
871 }
872
873 fn ClearInterval(&self, handle: i32) {
875 self.ClearTimeout(handle);
876 }
877
878 fn QueueMicrotask(&self, callback: Rc<VoidFunction>) {
880 self.enqueue_microtask(Microtask::User(UserMicrotask {
881 callback,
882 pipeline: self.pipeline_id(),
883 }));
884 }
885
886 fn CreateImageBitmap(
888 &self,
889 image: ImageBitmapSource,
890 options: &ImageBitmapOptions,
891 can_gc: CanGc,
892 ) -> Rc<Promise> {
893 ImageBitmap::create_image_bitmap(self.upcast(), image, 0, 0, None, None, options, can_gc)
894 }
895
896 fn CreateImageBitmap_(
898 &self,
899 image: ImageBitmapSource,
900 sx: i32,
901 sy: i32,
902 sw: i32,
903 sh: i32,
904 options: &ImageBitmapOptions,
905 can_gc: CanGc,
906 ) -> Rc<Promise> {
907 ImageBitmap::create_image_bitmap(
908 self.upcast(),
909 image,
910 sx,
911 sy,
912 Some(sw),
913 Some(sh),
914 options,
915 can_gc,
916 )
917 }
918
919 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
920 fn Fetch(
922 &self,
923 input: RequestOrUSVString,
924 init: RootedTraceableBox<RequestInit>,
925 comp: InRealm,
926 can_gc: CanGc,
927 ) -> Rc<Promise> {
928 Fetch(self.upcast(), input, init, comp, can_gc)
929 }
930
931 fn Performance(&self) -> DomRoot<Performance> {
933 self.performance.or_init(|| {
934 let global_scope = self.upcast::<GlobalScope>();
935 Performance::new(global_scope, self.navigation_start, CanGc::note())
936 })
937 }
938
939 fn Origin(&self) -> USVString {
941 USVString(
942 self.upcast::<GlobalScope>()
943 .origin()
944 .immutable()
945 .ascii_serialization(),
946 )
947 }
948
949 fn IsSecureContext(&self) -> bool {
951 self.upcast::<GlobalScope>().is_secure_context()
952 }
953
954 fn StructuredClone(
956 &self,
957 cx: JSContext,
958 value: HandleValue,
959 options: RootedTraceableBox<StructuredSerializeOptions>,
960 can_gc: CanGc,
961 retval: MutableHandleValue,
962 ) -> Fallible<()> {
963 self.upcast::<GlobalScope>()
964 .structured_clone(cx, value, options, retval, can_gc)
965 }
966
967 fn TrustedTypes(&self, can_gc: CanGc) -> DomRoot<TrustedTypePolicyFactory> {
969 self.trusted_types.or_init(|| {
970 let global_scope = self.upcast::<GlobalScope>();
971 TrustedTypePolicyFactory::new(global_scope, can_gc)
972 })
973 }
974}
975
976impl WorkerGlobalScope {
977 pub(crate) fn execute_script(&self, source: DOMString, can_gc: CanGc) {
978 let global = self.upcast::<GlobalScope>();
979 let mut script = ScriptOrigin::external(
980 Rc::new(source),
981 self.worker_url.borrow().clone(),
982 ScriptFetchOptions::default_classic_script(global),
983 ScriptType::Classic,
984 global.unminified_js_dir(),
985 );
986 unminify_js(&mut script);
987
988 global.run_a_classic_script(&script, 1, Some(IntroductionType::WORKER), can_gc);
989 }
990
991 pub(crate) fn new_script_pair(&self) -> (ScriptEventLoopSender, ScriptEventLoopReceiver) {
992 let dedicated = self.downcast::<DedicatedWorkerGlobalScope>();
993 if let Some(dedicated) = dedicated {
994 dedicated.new_script_pair()
995 } else {
996 panic!("need to implement a sender for SharedWorker/ServiceWorker")
997 }
998 }
999
1000 pub(crate) fn process_event(&self, msg: CommonScriptMsg) -> bool {
1004 if self.is_closing() {
1005 return false;
1006 }
1007 match msg {
1008 CommonScriptMsg::Task(_, task, _, _) => task.run_box(),
1009 CommonScriptMsg::CollectReports(reports_chan) => {
1010 let cx = self.get_cx();
1011 perform_memory_report(|ops| {
1012 let reports = cx.get_reports(format!("url({})", self.get_url()), ops);
1013 reports_chan.send(ProcessReports::new(reports));
1014 });
1015 },
1016 CommonScriptMsg::ReportCspViolations(_, violations) => {
1017 self.upcast::<GlobalScope>()
1018 .report_csp_violations(violations, None, None);
1019 },
1020 }
1021 true
1022 }
1023
1024 pub(crate) fn close(&self) {
1025 self.closing.store(true, Ordering::SeqCst);
1026 self.upcast::<GlobalScope>()
1027 .task_manager()
1028 .cancel_all_tasks_and_ignore_future_tasks();
1029 }
1030}
1031
1032struct WorkerCspProcessor {
1033 global_scope: DomRoot<GlobalScope>,
1034}
1035
1036impl CspViolationsProcessor for WorkerCspProcessor {
1037 fn process_csp_violations(&self, violations: Vec<Violation>) {
1038 self.global_scope
1039 .report_csp_violations(violations, None, None);
1040 }
1041}