script/dom/
workerglobalscope.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use 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::id::{PipelineId, PipelineNamespace};
14use constellation_traits::WorkerGlobalScopeInit;
15use content_security_policy::CspList;
16use crossbeam_channel::Receiver;
17use devtools_traits::{DevtoolScriptControlMsg, WorkerId};
18use dom_struct::dom_struct;
19use fonts::FontContext;
20use ipc_channel::ipc::IpcSender;
21use js::jsval::UndefinedValue;
22use js::panic::maybe_resume_unwind;
23use js::rust::{HandleValue, MutableHandleValue, ParentRuntime};
24use net_traits::policy_container::PolicyContainer;
25use net_traits::request::{
26    CredentialsMode, Destination, InsecureRequestsPolicy, ParserMetadata,
27    RequestBuilder as NetRequestInit,
28};
29use net_traits::{IpcSend, ReferrerPolicy};
30use profile_traits::mem::{ProcessReports, perform_memory_report};
31use servo_url::{MutableOrigin, ServoUrl};
32use timers::TimerScheduler;
33use uuid::Uuid;
34
35use super::bindings::codegen::Bindings::MessagePortBinding::StructuredSerializeOptions;
36use crate::dom::bindings::cell::{DomRefCell, Ref};
37use crate::dom::bindings::codegen::Bindings::ImageBitmapBinding::{
38    ImageBitmapOptions, ImageBitmapSource,
39};
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, report_pending_exception};
50use crate::dom::bindings::inheritance::Castable;
51use crate::dom::bindings::refcounted::Trusted;
52use crate::dom::bindings::reflector::DomObject;
53use crate::dom::bindings::root::{DomRoot, MutNullableDom};
54use crate::dom::bindings::settings_stack::AutoEntryScript;
55use crate::dom::bindings::str::{DOMString, USVString};
56use crate::dom::bindings::trace::RootedTraceableBox;
57use crate::dom::crypto::Crypto;
58use crate::dom::csp::{GlobalCspReporting, Violation};
59use crate::dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope;
60use crate::dom::globalscope::GlobalScope;
61use crate::dom::idbfactory::IDBFactory;
62use crate::dom::performance::Performance;
63use crate::dom::promise::Promise;
64use crate::dom::reportingendpoint::{ReportingEndpoint, SendReportsToEndpoints};
65use crate::dom::reportingobserver::ReportingObserver;
66use crate::dom::trustedscripturl::TrustedScriptURL;
67use crate::dom::trustedtypepolicyfactory::TrustedTypePolicyFactory;
68use crate::dom::types::ImageBitmap;
69#[cfg(feature = "webgpu")]
70use crate::dom::webgpu::identityhub::IdentityHub;
71use crate::dom::window::{base64_atob, base64_btoa};
72use crate::dom::workerlocation::WorkerLocation;
73use crate::dom::workernavigator::WorkerNavigator;
74use crate::fetch::{CspViolationsProcessor, Fetch, load_whole_resource};
75use crate::messaging::{CommonScriptMsg, ScriptEventLoopReceiver, ScriptEventLoopSender};
76use crate::realms::{InRealm, enter_realm};
77use crate::script_runtime::{CanGc, IntroductionType, JSContext, JSContextHelper, Runtime};
78use crate::task::TaskCanceller;
79use crate::timers::{IsInterval, TimerCallback};
80
81pub(crate) fn prepare_workerscope_init(
82    global: &GlobalScope,
83    devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>,
84    worker_id: Option<WorkerId>,
85) -> WorkerGlobalScopeInit {
86    WorkerGlobalScopeInit {
87        resource_threads: global.resource_threads().clone(),
88        mem_profiler_chan: global.mem_profiler_chan().clone(),
89        to_devtools_sender: global.devtools_chan().cloned(),
90        time_profiler_chan: global.time_profiler_chan().clone(),
91        from_devtools_sender: devtools_sender,
92        script_to_constellation_chan: global.script_to_constellation_chan().clone(),
93        script_to_embedder_chan: global.script_to_embedder_chan().clone(),
94        worker_id: worker_id.unwrap_or_else(|| WorkerId(Uuid::new_v4())),
95        pipeline_id: global.pipeline_id(),
96        origin: global.origin().immutable().clone(),
97        creation_url: global.creation_url().clone(),
98        inherited_secure_context: Some(global.is_secure_context()),
99    }
100}
101
102// https://html.spec.whatwg.org/multipage/#the-workerglobalscope-common-interface
103#[dom_struct]
104pub(crate) struct WorkerGlobalScope {
105    globalscope: GlobalScope,
106
107    worker_name: DOMString,
108    worker_type: WorkerType,
109
110    #[no_trace]
111    worker_id: WorkerId,
112    #[no_trace]
113    worker_url: DomRefCell<ServoUrl>,
114    #[ignore_malloc_size_of = "Arc"]
115    closing: Arc<AtomicBool>,
116    #[ignore_malloc_size_of = "Defined in js"]
117    runtime: DomRefCell<Option<Runtime>>,
118    location: MutNullableDom<WorkerLocation>,
119    navigator: MutNullableDom<WorkerNavigator>,
120    #[no_trace]
121    /// <https://html.spec.whatwg.org/multipage/#the-workerglobalscope-common-interface:policy-container>
122    policy_container: DomRefCell<PolicyContainer>,
123
124    #[ignore_malloc_size_of = "Defined in ipc-channel"]
125    #[no_trace]
126    /// A `Sender` for sending messages to devtools. This is unused but is stored here to
127    /// keep the channel alive.
128    _devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>,
129
130    #[ignore_malloc_size_of = "Defined in crossbeam"]
131    #[no_trace]
132    /// A `Receiver` for receiving messages from devtools.
133    devtools_receiver: Option<Receiver<DevtoolScriptControlMsg>>,
134
135    #[no_trace]
136    navigation_start: CrossProcessInstant,
137    performance: MutNullableDom<Performance>,
138    indexeddb: MutNullableDom<IDBFactory>,
139    trusted_types: MutNullableDom<TrustedTypePolicyFactory>,
140
141    /// A [`TimerScheduler`] used to schedule timers for this [`WorkerGlobalScope`].
142    /// Timers are handled in the service worker event loop.
143    #[no_trace]
144    timer_scheduler: RefCell<TimerScheduler>,
145
146    #[no_trace]
147    insecure_requests_policy: InsecureRequestsPolicy,
148
149    /// <https://w3c.github.io/reporting/#windoworworkerglobalscope-registered-reporting-observer-list>
150    reporting_observer_list: DomRefCell<Vec<DomRoot<ReportingObserver>>>,
151
152    /// <https://w3c.github.io/reporting/#windoworworkerglobalscope-reports>
153    report_list: DomRefCell<Vec<Report>>,
154
155    /// <https://w3c.github.io/reporting/#windoworworkerglobalscope-endpoints>
156    #[no_trace]
157    endpoints_list: DomRefCell<Vec<ReportingEndpoint>>,
158}
159
160impl WorkerGlobalScope {
161    #[allow(clippy::too_many_arguments)]
162    pub(crate) fn new_inherited(
163        init: WorkerGlobalScopeInit,
164        worker_name: DOMString,
165        worker_type: WorkerType,
166        worker_url: ServoUrl,
167        runtime: Runtime,
168        devtools_receiver: Receiver<DevtoolScriptControlMsg>,
169        closing: Arc<AtomicBool>,
170        #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
171        insecure_requests_policy: InsecureRequestsPolicy,
172        font_context: Option<Arc<FontContext>>,
173    ) -> Self {
174        // Install a pipeline-namespace in the current thread.
175        PipelineNamespace::auto_install();
176
177        let devtools_receiver = match init.from_devtools_sender {
178            Some(..) => Some(devtools_receiver),
179            None => None,
180        };
181
182        Self {
183            globalscope: GlobalScope::new_inherited(
184                init.pipeline_id,
185                init.to_devtools_sender,
186                init.mem_profiler_chan,
187                init.time_profiler_chan,
188                init.script_to_constellation_chan,
189                init.script_to_embedder_chan,
190                init.resource_threads,
191                MutableOrigin::new(init.origin),
192                init.creation_url,
193                None,
194                runtime.microtask_queue.clone(),
195                #[cfg(feature = "webgpu")]
196                gpu_id_hub,
197                init.inherited_secure_context,
198                false,
199                font_context,
200            ),
201            worker_id: init.worker_id,
202            worker_name,
203            worker_type,
204            worker_url: DomRefCell::new(worker_url),
205            closing,
206            runtime: DomRefCell::new(Some(runtime)),
207            location: Default::default(),
208            navigator: Default::default(),
209            policy_container: Default::default(),
210            devtools_receiver,
211            _devtools_sender: init.from_devtools_sender,
212            navigation_start: CrossProcessInstant::now(),
213            performance: Default::default(),
214            indexeddb: Default::default(),
215            timer_scheduler: RefCell::default(),
216            insecure_requests_policy,
217            trusted_types: Default::default(),
218            reporting_observer_list: Default::default(),
219            report_list: Default::default(),
220            endpoints_list: Default::default(),
221        }
222    }
223
224    /// Returns a policy value that should be used by fetches initiated by this worker.
225    pub(crate) fn insecure_requests_policy(&self) -> InsecureRequestsPolicy {
226        self.insecure_requests_policy
227    }
228
229    /// Clear various items when the worker event-loop shuts-down.
230    pub(crate) fn clear_js_runtime(&self) {
231        self.upcast::<GlobalScope>()
232            .remove_web_messaging_and_dedicated_workers_infra();
233
234        // Drop the runtime.
235        let runtime = self.runtime.borrow_mut().take();
236        drop(runtime);
237    }
238
239    pub(crate) fn runtime_handle(&self) -> ParentRuntime {
240        self.runtime
241            .borrow()
242            .as_ref()
243            .unwrap()
244            .prepare_for_new_child()
245    }
246
247    pub(crate) fn devtools_receiver(&self) -> Option<&Receiver<DevtoolScriptControlMsg>> {
248        self.devtools_receiver.as_ref()
249    }
250
251    #[allow(unsafe_code)]
252    pub(crate) fn get_cx(&self) -> JSContext {
253        unsafe { JSContext::from_ptr(self.runtime.borrow().as_ref().unwrap().cx()) }
254    }
255
256    pub(crate) fn is_closing(&self) -> bool {
257        self.closing.load(Ordering::SeqCst)
258    }
259
260    pub(crate) fn get_url(&self) -> Ref<'_, ServoUrl> {
261        self.worker_url.borrow()
262    }
263
264    pub(crate) fn set_url(&self, url: ServoUrl) {
265        *self.worker_url.borrow_mut() = url;
266    }
267
268    pub(crate) fn get_worker_id(&self) -> WorkerId {
269        self.worker_id
270    }
271
272    pub(crate) fn pipeline_id(&self) -> PipelineId {
273        self.globalscope.pipeline_id()
274    }
275
276    pub(crate) fn policy_container(&self) -> Ref<'_, PolicyContainer> {
277        self.policy_container.borrow()
278    }
279
280    pub(crate) fn set_csp_list(&self, csp_list: Option<CspList>) {
281        self.policy_container.borrow_mut().set_csp_list(csp_list);
282    }
283
284    pub(crate) fn set_referrer_policy(&self, referrer_policy: ReferrerPolicy) {
285        self.policy_container
286            .borrow_mut()
287            .set_referrer_policy(referrer_policy);
288    }
289
290    pub(crate) fn append_reporting_observer(&self, reporting_observer: DomRoot<ReportingObserver>) {
291        self.reporting_observer_list
292            .borrow_mut()
293            .push(reporting_observer);
294    }
295
296    pub(crate) fn remove_reporting_observer(&self, reporting_observer: &ReportingObserver) {
297        if let Some(index) = self
298            .reporting_observer_list
299            .borrow()
300            .iter()
301            .position(|observer| &**observer == reporting_observer)
302        {
303            self.reporting_observer_list.borrow_mut().remove(index);
304        }
305    }
306
307    pub(crate) fn registered_reporting_observers(&self) -> Vec<DomRoot<ReportingObserver>> {
308        self.reporting_observer_list.borrow().clone()
309    }
310
311    pub(crate) fn append_report(&self, report: Report) {
312        self.report_list.borrow_mut().push(report);
313        let trusted_worker = Trusted::new(self);
314        self.upcast::<GlobalScope>()
315            .task_manager()
316            .dom_manipulation_task_source()
317            .queue(task!(send_to_reporting_endpoints: move || {
318                let worker = trusted_worker.root();
319                let reports = std::mem::take(&mut *worker.report_list.borrow_mut());
320                worker.upcast::<GlobalScope>().send_reports_to_endpoints(
321                    reports,
322                    worker.endpoints_list.borrow().clone(),
323                );
324            }));
325    }
326
327    pub(crate) fn buffered_reports(&self) -> Vec<Report> {
328        self.report_list.borrow().clone()
329    }
330
331    pub(crate) fn set_endpoints_list(&self, endpoints: Option<Vec<ReportingEndpoint>>) {
332        if let Some(endpoints) = endpoints {
333            *self.endpoints_list.borrow_mut() = endpoints;
334        }
335    }
336
337    /// Get a mutable reference to the [`TimerScheduler`] for this [`ServiceWorkerGlobalScope`].
338    pub(crate) fn timer_scheduler(&self) -> RefMut<'_, TimerScheduler> {
339        self.timer_scheduler.borrow_mut()
340    }
341
342    /// Return a copy to the shared task canceller that is used to cancel all tasks
343    /// when this worker is closing.
344    pub(crate) fn shared_task_canceller(&self) -> TaskCanceller {
345        TaskCanceller {
346            cancelled: self.closing.clone(),
347        }
348    }
349}
350
351impl WorkerGlobalScopeMethods<crate::DomTypeHolder> for WorkerGlobalScope {
352    // https://html.spec.whatwg.org/multipage/#dom-workerglobalscope-self
353    fn Self_(&self) -> DomRoot<WorkerGlobalScope> {
354        DomRoot::from_ref(self)
355    }
356
357    // https://w3c.github.io/IndexedDB/#factory-interface
358    fn IndexedDB(&self) -> DomRoot<IDBFactory> {
359        self.indexeddb.or_init(|| {
360            let global_scope = self.upcast::<GlobalScope>();
361            IDBFactory::new(global_scope, CanGc::note())
362        })
363    }
364
365    // https://html.spec.whatwg.org/multipage/#dom-workerglobalscope-location
366    fn Location(&self) -> DomRoot<WorkerLocation> {
367        self.location
368            .or_init(|| WorkerLocation::new(self, self.worker_url.borrow().clone(), CanGc::note()))
369    }
370
371    // https://html.spec.whatwg.org/multipage/#handler-workerglobalscope-onerror
372    error_event_handler!(error, GetOnerror, SetOnerror);
373
374    // https://html.spec.whatwg.org/multipage/#dom-workerglobalscope-importscripts
375    fn ImportScripts(
376        &self,
377        url_strings: Vec<TrustedScriptURLOrUSVString>,
378        can_gc: CanGc,
379    ) -> ErrorResult {
380        // Step 1: Let urlStrings be « ».
381        let mut urls = Vec::with_capacity(url_strings.len());
382        // Step 2: For each url of urls:
383        for url in url_strings {
384            // Step 3: Append the result of invoking the Get Trusted Type compliant string algorithm
385            // with TrustedScriptURL, this's relevant global object, url, "WorkerGlobalScope importScripts",
386            // and "script" to urlStrings.
387            let url = TrustedScriptURL::get_trusted_script_url_compliant_string(
388                self.upcast::<GlobalScope>(),
389                url,
390                "WorkerGlobalScope",
391                "importScripts",
392                can_gc,
393            )?;
394            let url = self.worker_url.borrow().join(&url);
395            match url {
396                Ok(url) => urls.push(url),
397                Err(_) => return Err(Error::Syntax(None)),
398            };
399        }
400
401        rooted!(in(self.runtime.borrow().as_ref().unwrap().cx()) let mut rval = UndefinedValue());
402        for url in urls {
403            let global_scope = self.upcast::<GlobalScope>();
404            let request = NetRequestInit::new(
405                global_scope.webview_id(),
406                url.clone(),
407                global_scope.get_referrer(),
408            )
409            .destination(Destination::Script)
410            .credentials_mode(CredentialsMode::Include)
411            .parser_metadata(ParserMetadata::NotParserInserted)
412            .use_url_credentials(true)
413            .origin(global_scope.origin().immutable().clone())
414            .insecure_requests_policy(self.insecure_requests_policy())
415            .policy_container(global_scope.policy_container())
416            .has_trustworthy_ancestor_origin(
417                global_scope.has_trustworthy_ancestor_or_current_origin(),
418            )
419            .pipeline_id(Some(self.upcast::<GlobalScope>().pipeline_id()));
420
421            let (url, source) = match load_whole_resource(
422                request,
423                &global_scope.resource_threads().sender(),
424                global_scope,
425                &WorkerCspProcessor {
426                    global_scope: DomRoot::from_ref(global_scope),
427                },
428                can_gc,
429            ) {
430                Err(_) => return Err(Error::Network),
431                Ok((metadata, bytes)) => (metadata.final_url, String::from_utf8(bytes).unwrap()),
432            };
433
434            let options = self
435                .runtime
436                .borrow()
437                .as_ref()
438                .unwrap()
439                .new_compile_options(url.as_str(), 1);
440            let result = self.runtime.borrow().as_ref().unwrap().evaluate_script(
441                self.reflector().get_jsobject(),
442                &source,
443                rval.handle_mut(),
444                options,
445            );
446
447            maybe_resume_unwind();
448
449            match result {
450                Ok(_) => (),
451                Err(_) => {
452                    if self.is_closing() {
453                        // Don't return JSFailed as we might not have
454                        // any pending exceptions.
455                        println!("evaluate_script failed (terminated)");
456                    } else {
457                        println!("evaluate_script failed");
458                        return Err(Error::JSFailed);
459                    }
460                },
461            }
462        }
463
464        Ok(())
465    }
466
467    // https://html.spec.whatwg.org/multipage/#dom-worker-navigator
468    fn Navigator(&self) -> DomRoot<WorkerNavigator> {
469        self.navigator
470            .or_init(|| WorkerNavigator::new(self, CanGc::note()))
471    }
472
473    // https://html.spec.whatwg.org/multipage/#dfn-Crypto
474    fn Crypto(&self) -> DomRoot<Crypto> {
475        self.upcast::<GlobalScope>().crypto(CanGc::note())
476    }
477
478    // https://html.spec.whatwg.org/multipage/#dom-windowbase64-btoa
479    fn Btoa(&self, btoa: DOMString) -> Fallible<DOMString> {
480        base64_btoa(btoa)
481    }
482
483    // https://html.spec.whatwg.org/multipage/#dom-windowbase64-atob
484    fn Atob(&self, atob: DOMString) -> Fallible<DOMString> {
485        base64_atob(atob)
486    }
487
488    // https://html.spec.whatwg.org/multipage/#dom-windowtimers-settimeout
489    fn SetTimeout(
490        &self,
491        _cx: JSContext,
492        callback: TrustedScriptOrStringOrFunction,
493        timeout: i32,
494        args: Vec<HandleValue>,
495        can_gc: CanGc,
496    ) -> Fallible<i32> {
497        let callback = match callback {
498            TrustedScriptOrStringOrFunction::String(i) => {
499                TimerCallback::StringTimerCallback(TrustedScriptOrString::String(i))
500            },
501            TrustedScriptOrStringOrFunction::TrustedScript(i) => {
502                TimerCallback::StringTimerCallback(TrustedScriptOrString::TrustedScript(i))
503            },
504            TrustedScriptOrStringOrFunction::Function(i) => TimerCallback::FunctionTimerCallback(i),
505        };
506        self.upcast::<GlobalScope>().set_timeout_or_interval(
507            callback,
508            args,
509            Duration::from_millis(timeout.max(0) as u64),
510            IsInterval::NonInterval,
511            can_gc,
512        )
513    }
514
515    // https://html.spec.whatwg.org/multipage/#dom-windowtimers-cleartimeout
516    fn ClearTimeout(&self, handle: i32) {
517        self.upcast::<GlobalScope>()
518            .clear_timeout_or_interval(handle);
519    }
520
521    // https://html.spec.whatwg.org/multipage/#dom-windowtimers-setinterval
522    fn SetInterval(
523        &self,
524        _cx: JSContext,
525        callback: TrustedScriptOrStringOrFunction,
526        timeout: i32,
527        args: Vec<HandleValue>,
528        can_gc: CanGc,
529    ) -> Fallible<i32> {
530        let callback = match callback {
531            TrustedScriptOrStringOrFunction::String(i) => {
532                TimerCallback::StringTimerCallback(TrustedScriptOrString::String(i))
533            },
534            TrustedScriptOrStringOrFunction::TrustedScript(i) => {
535                TimerCallback::StringTimerCallback(TrustedScriptOrString::TrustedScript(i))
536            },
537            TrustedScriptOrStringOrFunction::Function(i) => TimerCallback::FunctionTimerCallback(i),
538        };
539        self.upcast::<GlobalScope>().set_timeout_or_interval(
540            callback,
541            args,
542            Duration::from_millis(timeout.max(0) as u64),
543            IsInterval::Interval,
544            can_gc,
545        )
546    }
547
548    // https://html.spec.whatwg.org/multipage/#dom-windowtimers-clearinterval
549    fn ClearInterval(&self, handle: i32) {
550        self.ClearTimeout(handle);
551    }
552
553    // https://html.spec.whatwg.org/multipage/#dom-queuemicrotask
554    fn QueueMicrotask(&self, callback: Rc<VoidFunction>) {
555        self.upcast::<GlobalScope>()
556            .queue_function_as_microtask(callback);
557    }
558
559    /// <https://html.spec.whatwg.org/multipage/#dom-createimagebitmap>
560    fn CreateImageBitmap(
561        &self,
562        image: ImageBitmapSource,
563        options: &ImageBitmapOptions,
564        can_gc: CanGc,
565    ) -> Rc<Promise> {
566        ImageBitmap::create_image_bitmap(self.upcast(), image, 0, 0, None, None, options, can_gc)
567    }
568
569    /// <https://html.spec.whatwg.org/multipage/#dom-createimagebitmap>
570    fn CreateImageBitmap_(
571        &self,
572        image: ImageBitmapSource,
573        sx: i32,
574        sy: i32,
575        sw: i32,
576        sh: i32,
577        options: &ImageBitmapOptions,
578        can_gc: CanGc,
579    ) -> Rc<Promise> {
580        ImageBitmap::create_image_bitmap(
581            self.upcast(),
582            image,
583            sx,
584            sy,
585            Some(sw),
586            Some(sh),
587            options,
588            can_gc,
589        )
590    }
591
592    #[cfg_attr(crown, allow(crown::unrooted_must_root))]
593    // https://fetch.spec.whatwg.org/#fetch-method
594    fn Fetch(
595        &self,
596        input: RequestOrUSVString,
597        init: RootedTraceableBox<RequestInit>,
598        comp: InRealm,
599        can_gc: CanGc,
600    ) -> Rc<Promise> {
601        Fetch(self.upcast(), input, init, comp, can_gc)
602    }
603
604    // https://w3c.github.io/hr-time/#the-performance-attribute
605    fn Performance(&self) -> DomRoot<Performance> {
606        self.performance.or_init(|| {
607            let global_scope = self.upcast::<GlobalScope>();
608            Performance::new(global_scope, self.navigation_start, CanGc::note())
609        })
610    }
611
612    // https://html.spec.whatwg.org/multipage/#dom-origin
613    fn Origin(&self) -> USVString {
614        USVString(
615            self.upcast::<GlobalScope>()
616                .origin()
617                .immutable()
618                .ascii_serialization(),
619        )
620    }
621
622    // https://w3c.github.io/webappsec-secure-contexts/#dom-windoworworkerglobalscope-issecurecontext
623    fn IsSecureContext(&self) -> bool {
624        self.upcast::<GlobalScope>().is_secure_context()
625    }
626
627    /// <https://html.spec.whatwg.org/multipage/#dom-structuredclone>
628    fn StructuredClone(
629        &self,
630        cx: JSContext,
631        value: HandleValue,
632        options: RootedTraceableBox<StructuredSerializeOptions>,
633        retval: MutableHandleValue,
634    ) -> Fallible<()> {
635        self.upcast::<GlobalScope>()
636            .structured_clone(cx, value, options, retval)
637    }
638
639    /// <https://www.w3.org/TR/trusted-types/#dom-windoworworkerglobalscope-trustedtypes>
640    fn TrustedTypes(&self, can_gc: CanGc) -> DomRoot<TrustedTypePolicyFactory> {
641        self.trusted_types.or_init(|| {
642            let global_scope = self.upcast::<GlobalScope>();
643            TrustedTypePolicyFactory::new(global_scope, can_gc)
644        })
645    }
646}
647
648impl WorkerGlobalScope {
649    #[allow(unsafe_code)]
650    pub(crate) fn execute_script(&self, source: DOMString, can_gc: CanGc) {
651        let _aes = AutoEntryScript::new(self.upcast());
652        let cx = self.runtime.borrow().as_ref().unwrap().cx();
653        rooted!(in(cx) let mut rval = UndefinedValue());
654        let mut options = self
655            .runtime
656            .borrow()
657            .as_ref()
658            .unwrap()
659            .new_compile_options(self.worker_url.borrow().as_str(), 1);
660        options.set_introduction_type(IntroductionType::WORKER);
661        match self.runtime.borrow().as_ref().unwrap().evaluate_script(
662            self.reflector().get_jsobject(),
663            &source,
664            rval.handle_mut(),
665            options,
666        ) {
667            Ok(_) => (),
668            Err(_) => {
669                if self.is_closing() {
670                    println!("evaluate_script failed (terminated)");
671                } else {
672                    // TODO: An error needs to be dispatched to the parent.
673                    // https://github.com/servo/servo/issues/6422
674                    println!("evaluate_script failed");
675                    unsafe {
676                        let ar = enter_realm(self);
677                        report_pending_exception(
678                            JSContext::from_ptr(cx),
679                            true,
680                            InRealm::Entered(&ar),
681                            can_gc,
682                        );
683                    }
684                }
685            },
686        }
687    }
688
689    pub(crate) fn new_script_pair(&self) -> (ScriptEventLoopSender, ScriptEventLoopReceiver) {
690        let dedicated = self.downcast::<DedicatedWorkerGlobalScope>();
691        if let Some(dedicated) = dedicated {
692            dedicated.new_script_pair()
693        } else {
694            panic!("need to implement a sender for SharedWorker/ServiceWorker")
695        }
696    }
697
698    /// Process a single event as if it were the next event
699    /// in the queue for this worker event-loop.
700    /// Returns a boolean indicating whether further events should be processed.
701    #[allow(unsafe_code)]
702    pub(crate) fn process_event(&self, msg: CommonScriptMsg) -> bool {
703        if self.is_closing() {
704            return false;
705        }
706        match msg {
707            CommonScriptMsg::Task(_, task, _, _) => task.run_box(),
708            CommonScriptMsg::CollectReports(reports_chan) => {
709                let cx = self.get_cx();
710                perform_memory_report(|ops| {
711                    let reports = cx.get_reports(format!("url({})", self.get_url()), ops);
712                    reports_chan.send(ProcessReports::new(reports));
713                });
714            },
715            CommonScriptMsg::ReportCspViolations(_, violations) => {
716                self.upcast::<GlobalScope>()
717                    .report_csp_violations(violations, None, None);
718            },
719        }
720        true
721    }
722
723    pub(crate) fn close(&self) {
724        self.closing.store(true, Ordering::SeqCst);
725        self.upcast::<GlobalScope>()
726            .task_manager()
727            .cancel_all_tasks_and_ignore_future_tasks();
728    }
729}
730
731struct WorkerCspProcessor {
732    global_scope: DomRoot<GlobalScope>,
733}
734
735impl CspViolationsProcessor for WorkerCspProcessor {
736    fn process_csp_violations(&self, violations: Vec<Violation>) {
737        self.global_scope
738            .report_csp_violations(violations, None, None);
739    }
740}