script/dom/
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 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
67 pub(crate) fn new(
68 global: &GlobalScope,
69 scope: ServoUrl,
70 registration_id: ServiceWorkerRegistrationId,
71 can_gc: CanGc,
72 ) -> DomRoot<ServiceWorkerRegistration> {
73 reflect_dom_object(
74 Box::new(ServiceWorkerRegistration::new_inherited(
75 scope,
76 registration_id,
77 )),
78 global,
79 can_gc,
80 )
81 }
82
83 pub(crate) fn is_active(&self) -> bool {
85 self.active.borrow().is_some()
86 }
87
88 pub(crate) fn set_installing(&self, worker: &ServiceWorker) {
89 *self.installing.borrow_mut() = Some(Dom::from_ref(worker));
90 }
91
92 pub(crate) fn get_navigation_preload_header_value(&self) -> Option<ByteString> {
93 self.navigation_preload_header_value.borrow().clone()
94 }
95
96 pub(crate) fn set_navigation_preload_header_value(&self, value: ByteString) {
97 let mut header_value = self.navigation_preload_header_value.borrow_mut();
98 *header_value = Some(value);
99 }
100
101 pub(crate) fn get_navigation_preload_enabled(&self) -> bool {
102 self.navigation_preload_enabled.get()
103 }
104
105 pub(crate) fn set_navigation_preload_enabled(&self, flag: bool) {
106 self.navigation_preload_enabled.set(flag)
107 }
108
109 pub(crate) fn get_uninstalling(&self) -> bool {
110 self.uninstalling.get()
111 }
112
113 pub(crate) fn set_uninstalling(&self, flag: bool) {
114 self.uninstalling.set(flag)
115 }
116
117 pub(crate) fn create_scope_things(global: &GlobalScope, script_url: ServoUrl) -> ScopeThings {
118 let worker_load_origin = WorkerScriptLoadOrigin {
119 referrer_url: match global.get_referrer() {
120 Referrer::Client(url) => Some(url),
121 Referrer::ReferrerUrl(url) => Some(url),
122 _ => None,
123 },
124 referrer_policy: global.get_referrer_policy(),
125 pipeline_id: global.pipeline_id(),
126 };
127
128 let worker_id = WorkerId(Uuid::new_v4());
129 let devtools_chan = global.devtools_chan().cloned();
130 let init = prepare_workerscope_init(global, None, None);
131 ScopeThings {
132 script_url,
133 init,
134 worker_load_origin,
135 devtools_chan,
136 worker_id,
137 }
138 }
139
140 pub(crate) fn get_newest_worker(&self) -> Option<DomRoot<ServiceWorker>> {
142 let installing = self.installing.borrow();
143 let waiting = self.waiting.borrow();
144 let active = self.active.borrow();
145 installing
146 .as_ref()
147 .map(|sw| DomRoot::from_ref(&**sw))
148 .or_else(|| waiting.as_ref().map(|sw| DomRoot::from_ref(&**sw)))
149 .or_else(|| active.as_ref().map(|sw| DomRoot::from_ref(&**sw)))
150 }
151}
152
153pub(crate) fn longest_prefix_match(stored_scope: &ServoUrl, potential_match: &ServoUrl) -> bool {
154 if stored_scope.origin() != potential_match.origin() {
155 return false;
156 }
157 let scope_chars = stored_scope.path().chars();
158 let matching_chars = potential_match.path().chars();
159 if scope_chars.count() > matching_chars.count() {
160 return false;
161 }
162
163 stored_scope
164 .path()
165 .chars()
166 .zip(potential_match.path().chars())
167 .all(|(scope, matched)| scope == matched)
168}
169
170impl ServiceWorkerRegistrationMethods<crate::DomTypeHolder> for ServiceWorkerRegistration {
171 fn GetInstalling(&self) -> Option<DomRoot<ServiceWorker>> {
173 self.installing
174 .borrow()
175 .as_ref()
176 .map(|sw| DomRoot::from_ref(&**sw))
177 }
178
179 fn GetActive(&self) -> Option<DomRoot<ServiceWorker>> {
181 self.active
182 .borrow()
183 .as_ref()
184 .map(|sw| DomRoot::from_ref(&**sw))
185 }
186
187 fn GetWaiting(&self) -> Option<DomRoot<ServiceWorker>> {
189 self.waiting
190 .borrow()
191 .as_ref()
192 .map(|sw| DomRoot::from_ref(&**sw))
193 }
194
195 fn Scope(&self) -> USVString {
197 USVString(self.scope.as_str().to_owned())
198 }
199
200 fn UpdateViaCache(&self) -> ServiceWorkerUpdateViaCache {
202 self.update_via_cache
203 }
204
205 fn NavigationPreload(&self) -> DomRoot<NavigationPreloadManager> {
207 self.navigation_preload
208 .or_init(|| NavigationPreloadManager::new(&self.global(), self, CanGc::note()))
209 }
210}