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