script/dom/workers/
serviceworkerregistration.rs1use std::cell::Cell;
6
7use base::id::ServiceWorkerRegistrationId;
8use constellation_traits::{ScopeThings, WorkerScriptLoadOrigin};
9use devtools_traits::WorkerId;
10use dom_struct::dom_struct;
11use net_traits::request::Referrer;
12use servo_url::ServoUrl;
13use uuid::Uuid;
14
15use crate::dom::bindings::cell::DomRefCell;
16use crate::dom::bindings::codegen::Bindings::ServiceWorkerRegistrationBinding::{
17 ServiceWorkerRegistrationMethods, ServiceWorkerUpdateViaCache,
18};
19use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
20use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
21use crate::dom::bindings::str::{ByteString, USVString};
22use crate::dom::eventtarget::EventTarget;
23use crate::dom::globalscope::GlobalScope;
24use crate::dom::navigationpreloadmanager::NavigationPreloadManager;
25use crate::dom::serviceworker::ServiceWorker;
26use crate::dom::workerglobalscope::prepare_workerscope_init;
27use crate::script_runtime::CanGc;
28
29#[dom_struct]
30pub(crate) struct ServiceWorkerRegistration {
31 eventtarget: EventTarget,
32 active: DomRefCell<Option<Dom<ServiceWorker>>>,
33 installing: DomRefCell<Option<Dom<ServiceWorker>>>,
34 waiting: DomRefCell<Option<Dom<ServiceWorker>>>,
35 navigation_preload: MutNullableDom<NavigationPreloadManager>,
36 #[no_trace]
37 scope: ServoUrl,
38 navigation_preload_enabled: Cell<bool>,
39 navigation_preload_header_value: DomRefCell<Option<ByteString>>,
40 update_via_cache: ServiceWorkerUpdateViaCache,
41 uninstalling: Cell<bool>,
42 #[no_trace]
43 registration_id: ServiceWorkerRegistrationId,
44}
45
46impl ServiceWorkerRegistration {
47 fn new_inherited(
48 scope: ServoUrl,
49 registration_id: ServiceWorkerRegistrationId,
50 ) -> ServiceWorkerRegistration {
51 ServiceWorkerRegistration {
52 eventtarget: EventTarget::new_inherited(),
53 active: DomRefCell::new(None),
54 installing: DomRefCell::new(None),
55 waiting: DomRefCell::new(None),
56 navigation_preload: MutNullableDom::new(None),
57 scope,
58 navigation_preload_enabled: Cell::new(false),
59 navigation_preload_header_value: DomRefCell::new(None),
60 update_via_cache: ServiceWorkerUpdateViaCache::Imports,
61 uninstalling: Cell::new(false),
62 registration_id,
63 }
64 }
65
66 pub(crate) fn new(
67 global: &GlobalScope,
68 scope: ServoUrl,
69 registration_id: ServiceWorkerRegistrationId,
70 can_gc: CanGc,
71 ) -> DomRoot<ServiceWorkerRegistration> {
72 reflect_dom_object(
73 Box::new(ServiceWorkerRegistration::new_inherited(
74 scope,
75 registration_id,
76 )),
77 global,
78 can_gc,
79 )
80 }
81
82 pub(crate) fn is_active(&self) -> bool {
84 self.active.borrow().is_some()
85 }
86
87 pub(crate) fn set_installing(&self, worker: &ServiceWorker) {
88 *self.installing.borrow_mut() = Some(Dom::from_ref(worker));
89 }
90
91 pub(crate) fn get_navigation_preload_header_value(&self) -> Option<ByteString> {
92 self.navigation_preload_header_value.borrow().clone()
93 }
94
95 pub(crate) fn set_navigation_preload_header_value(&self, value: ByteString) {
96 let mut header_value = self.navigation_preload_header_value.borrow_mut();
97 *header_value = Some(value);
98 }
99
100 pub(crate) fn get_navigation_preload_enabled(&self) -> bool {
101 self.navigation_preload_enabled.get()
102 }
103
104 pub(crate) fn set_navigation_preload_enabled(&self, flag: bool) {
105 self.navigation_preload_enabled.set(flag)
106 }
107
108 pub(crate) fn get_uninstalling(&self) -> bool {
109 self.uninstalling.get()
110 }
111
112 pub(crate) fn set_uninstalling(&self, flag: bool) {
113 self.uninstalling.set(flag)
114 }
115
116 pub(crate) fn create_scope_things(global: &GlobalScope, script_url: ServoUrl) -> ScopeThings {
117 let worker_load_origin = WorkerScriptLoadOrigin {
118 referrer_url: match global.get_referrer() {
119 Referrer::Client(url) => Some(url),
120 Referrer::ReferrerUrl(url) => Some(url),
121 _ => None,
122 },
123 referrer_policy: global.get_referrer_policy(),
124 pipeline_id: global.pipeline_id(),
125 };
126
127 let worker_id = WorkerId(Uuid::new_v4());
128 let devtools_chan = global.devtools_chan().cloned();
129 let init = prepare_workerscope_init(global, None, None);
130 ScopeThings {
131 script_url,
132 init,
133 worker_load_origin,
134 devtools_chan,
135 worker_id,
136 }
137 }
138
139 pub(crate) fn get_newest_worker(&self) -> Option<DomRoot<ServiceWorker>> {
141 let installing = self.installing.borrow();
142 let waiting = self.waiting.borrow();
143 let active = self.active.borrow();
144 installing
145 .as_ref()
146 .map(|sw| DomRoot::from_ref(&**sw))
147 .or_else(|| waiting.as_ref().map(|sw| DomRoot::from_ref(&**sw)))
148 .or_else(|| active.as_ref().map(|sw| DomRoot::from_ref(&**sw)))
149 }
150}
151
152pub(crate) fn longest_prefix_match(stored_scope: &ServoUrl, potential_match: &ServoUrl) -> bool {
153 if stored_scope.origin() != potential_match.origin() {
154 return false;
155 }
156 let scope_chars = stored_scope.path().chars();
157 let matching_chars = potential_match.path().chars();
158 if scope_chars.count() > matching_chars.count() {
159 return false;
160 }
161
162 stored_scope
163 .path()
164 .chars()
165 .zip(potential_match.path().chars())
166 .all(|(scope, matched)| scope == matched)
167}
168
169impl ServiceWorkerRegistrationMethods<crate::DomTypeHolder> for ServiceWorkerRegistration {
170 fn GetInstalling(&self) -> Option<DomRoot<ServiceWorker>> {
172 self.installing
173 .borrow()
174 .as_ref()
175 .map(|sw| DomRoot::from_ref(&**sw))
176 }
177
178 fn GetActive(&self) -> Option<DomRoot<ServiceWorker>> {
180 self.active
181 .borrow()
182 .as_ref()
183 .map(|sw| DomRoot::from_ref(&**sw))
184 }
185
186 fn GetWaiting(&self) -> Option<DomRoot<ServiceWorker>> {
188 self.waiting
189 .borrow()
190 .as_ref()
191 .map(|sw| DomRoot::from_ref(&**sw))
192 }
193
194 fn Scope(&self) -> USVString {
196 USVString(self.scope.as_str().to_owned())
197 }
198
199 fn UpdateViaCache(&self) -> ServiceWorkerUpdateViaCache {
201 self.update_via_cache
202 }
203
204 fn NavigationPreload(&self) -> DomRoot<NavigationPreloadManager> {
206 self.navigation_preload
207 .or_init(|| NavigationPreloadManager::new(&self.global(), self, CanGc::note()))
208 }
209}