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