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