1use std::borrow::ToOwned;
6use std::collections::{BTreeMap, HashMap};
7use std::path::PathBuf;
8use std::thread;
9
10use base::generic_channel::{self, GenericReceiver, GenericSender};
11use base::id::WebViewId;
12use malloc_size_of::MallocSizeOf;
13use net_traits::storage_thread::{StorageThreadMsg, StorageType};
14use profile_traits::mem::{
15 ProcessReports, ProfilerChan as MemProfilerChan, Report, ReportKind, perform_memory_report,
16};
17use profile_traits::path;
18use servo_url::ServoUrl;
19
20use crate::resource_thread;
21
22const QUOTA_SIZE_LIMIT: usize = 5 * 1024 * 1024;
23
24pub trait StorageThreadFactory {
25 fn new(config_dir: Option<PathBuf>, mem_profiler_chan: MemProfilerChan) -> Self;
26}
27
28impl StorageThreadFactory for GenericSender<StorageThreadMsg> {
29 fn new(
31 config_dir: Option<PathBuf>,
32 mem_profiler_chan: MemProfilerChan,
33 ) -> GenericSender<StorageThreadMsg> {
34 let (chan, port) = generic_channel::channel().unwrap();
35 let chan2 = chan.clone();
36 thread::Builder::new()
37 .name("StorageManager".to_owned())
38 .spawn(move || {
39 mem_profiler_chan.run_with_memory_reporting(
40 || StorageManager::new(port, config_dir).start(),
41 String::from("storage-reporter"),
42 chan2,
43 StorageThreadMsg::CollectMemoryReport,
44 );
45 })
46 .expect("Thread spawning failed");
47 chan
48 }
49}
50
51type OriginEntry = (usize, BTreeMap<String, String>);
52
53struct StorageManager {
54 port: GenericReceiver<StorageThreadMsg>,
55 session_data: HashMap<WebViewId, HashMap<String, OriginEntry>>,
56 local_data: HashMap<String, OriginEntry>,
57 config_dir: Option<PathBuf>,
58}
59
60impl StorageManager {
61 fn new(port: GenericReceiver<StorageThreadMsg>, config_dir: Option<PathBuf>) -> StorageManager {
62 let mut local_data = HashMap::new();
63 if let Some(ref config_dir) = config_dir {
64 resource_thread::read_json_from_file(&mut local_data, config_dir, "local_data.json");
65 }
66 StorageManager {
67 port,
68 session_data: HashMap::new(),
69 local_data,
70 config_dir,
71 }
72 }
73}
74
75impl StorageManager {
76 fn start(&mut self) {
77 loop {
78 match self.port.recv().unwrap() {
79 StorageThreadMsg::Length(sender, storage_type, webview_id, url) => {
80 self.length(sender, storage_type, webview_id, url)
81 },
82 StorageThreadMsg::Key(sender, storage_type, webview_id, url, index) => {
83 self.key(sender, storage_type, webview_id, url, index)
84 },
85 StorageThreadMsg::Keys(sender, storage_type, webview_id, url) => {
86 self.keys(sender, storage_type, webview_id, url)
87 },
88 StorageThreadMsg::SetItem(sender, storage_type, webview_id, url, name, value) => {
89 self.set_item(sender, storage_type, webview_id, url, name, value);
90 self.save_state()
91 },
92 StorageThreadMsg::GetItem(sender, storage_type, webview_id, url, name) => {
93 self.request_item(sender, storage_type, webview_id, url, name)
94 },
95 StorageThreadMsg::RemoveItem(sender, storage_type, webview_id, url, name) => {
96 self.remove_item(sender, storage_type, webview_id, url, name);
97 self.save_state()
98 },
99 StorageThreadMsg::Clear(sender, storage_type, webview_id, url) => {
100 self.clear(sender, storage_type, webview_id, url);
101 self.save_state()
102 },
103 StorageThreadMsg::Clone {
104 sender,
105 src: src_webview_id,
106 dest: dest_webview_id,
107 } => {
108 self.clone(src_webview_id, dest_webview_id);
109 let _ = sender.send(());
110 },
111 StorageThreadMsg::CollectMemoryReport(sender) => {
112 let reports = self.collect_memory_reports();
113 sender.send(ProcessReports::new(reports));
114 },
115 StorageThreadMsg::Exit(sender) => {
116 let _ = sender.send(());
118 break;
119 },
120 }
121 }
122 }
123
124 fn collect_memory_reports(&self) -> Vec<Report> {
125 let mut reports = vec![];
126 perform_memory_report(|ops| {
127 reports.push(Report {
128 path: path!["storage", "local"],
129 kind: ReportKind::ExplicitJemallocHeapSize,
130 size: self.local_data.size_of(ops),
131 });
132
133 reports.push(Report {
134 path: path!["storage", "session"],
135 kind: ReportKind::ExplicitJemallocHeapSize,
136 size: self.session_data.size_of(ops),
137 });
138 });
139 reports
140 }
141
142 fn save_state(&self) {
143 if let Some(ref config_dir) = self.config_dir {
144 resource_thread::write_json_to_file(&self.local_data, config_dir, "local_data.json");
145 }
146 }
147
148 fn select_data(
149 &self,
150 storage_type: StorageType,
151 webview_id: WebViewId,
152 origin: &str,
153 ) -> Option<&OriginEntry> {
154 match storage_type {
155 StorageType::Session => self
156 .session_data
157 .get(&webview_id)
158 .and_then(|origin_map| origin_map.get(origin)),
159 StorageType::Local => self.local_data.get(origin),
160 }
161 }
162
163 fn select_data_mut(
164 &mut self,
165 storage_type: StorageType,
166 webview_id: WebViewId,
167 origin: &str,
168 ) -> Option<&mut OriginEntry> {
169 match storage_type {
170 StorageType::Session => self
171 .session_data
172 .get_mut(&webview_id)
173 .and_then(|origin_map| origin_map.get_mut(origin)),
174 StorageType::Local => self.local_data.get_mut(origin),
175 }
176 }
177
178 fn ensure_data_mut(
179 &mut self,
180 storage_type: StorageType,
181 webview_id: WebViewId,
182 origin: &str,
183 ) -> &mut OriginEntry {
184 match storage_type {
185 StorageType::Session => self
186 .session_data
187 .entry(webview_id)
188 .or_default()
189 .entry(origin.to_string())
190 .or_default(),
191 StorageType::Local => self.local_data.entry(origin.to_string()).or_default(),
192 }
193 }
194
195 fn length(
196 &self,
197 sender: GenericSender<usize>,
198 storage_type: StorageType,
199 webview_id: WebViewId,
200 url: ServoUrl,
201 ) {
202 let origin = self.origin_as_string(url);
203 let data = self.select_data(storage_type, webview_id, &origin);
204 sender
205 .send(data.map_or(0, |(_, entry)| entry.len()))
206 .unwrap();
207 }
208
209 fn key(
210 &self,
211 sender: GenericSender<Option<String>>,
212 storage_type: StorageType,
213 webview_id: WebViewId,
214 url: ServoUrl,
215 index: u32,
216 ) {
217 let origin = self.origin_as_string(url);
218 let data = self.select_data(storage_type, webview_id, &origin);
219 let key = data
220 .and_then(|(_, entry)| entry.keys().nth(index as usize))
221 .cloned();
222 sender.send(key).unwrap();
223 }
224
225 fn keys(
226 &self,
227 sender: GenericSender<Vec<String>>,
228 storage_type: StorageType,
229 webview_id: WebViewId,
230 url: ServoUrl,
231 ) {
232 let origin = self.origin_as_string(url);
233 let data = self.select_data(storage_type, webview_id, &origin);
234 let keys = data.map_or(vec![], |(_, entry)| entry.keys().cloned().collect());
235
236 sender.send(keys).unwrap();
237 }
238
239 fn set_item(
244 &mut self,
245 sender: GenericSender<Result<(bool, Option<String>), ()>>,
246 storage_type: StorageType,
247 webview_id: WebViewId,
248 url: ServoUrl,
249 name: String,
250 value: String,
251 ) {
252 let origin = self.origin_as_string(url);
253
254 let (this_storage_size, other_storage_size) = {
255 let local_data = self.select_data(StorageType::Local, webview_id, &origin);
256 let session_data = self.select_data(StorageType::Session, webview_id, &origin);
257 let local_data_size = local_data.map_or(0, |&(total, _)| total);
258 let session_data_size = session_data.map_or(0, |&(total, _)| total);
259 match storage_type {
260 StorageType::Local => (local_data_size, session_data_size),
261 StorageType::Session => (session_data_size, local_data_size),
262 }
263 };
264
265 let &mut (ref mut total, ref mut entry) =
266 self.ensure_data_mut(storage_type, webview_id, &origin);
267
268 let mut new_total_size = this_storage_size + value.len();
269 if let Some(old_value) = entry.get(&name) {
270 new_total_size -= old_value.len();
271 } else {
272 new_total_size += name.len();
273 }
274
275 let message = if (new_total_size + other_storage_size) > QUOTA_SIZE_LIMIT {
276 Err(())
277 } else {
278 *total = new_total_size;
279 entry
280 .insert(name.clone(), value.clone())
281 .map_or(Ok((true, None)), |old| {
282 if old == value {
283 Ok((false, None))
284 } else {
285 Ok((true, Some(old)))
286 }
287 })
288 };
289 sender.send(message).unwrap();
290 }
291
292 fn request_item(
293 &self,
294 sender: GenericSender<Option<String>>,
295 storage_type: StorageType,
296 webview_id: WebViewId,
297 url: ServoUrl,
298 name: String,
299 ) {
300 let origin = self.origin_as_string(url);
301 let data = self.select_data(storage_type, webview_id, &origin);
302 sender
303 .send(data.and_then(|(_, entry)| entry.get(&name)).cloned())
304 .unwrap();
305 }
306
307 fn remove_item(
309 &mut self,
310 sender: GenericSender<Option<String>>,
311 storage_type: StorageType,
312 webview_id: WebViewId,
313 url: ServoUrl,
314 name: String,
315 ) {
316 let origin = self.origin_as_string(url);
317 let data = self.select_data_mut(storage_type, webview_id, &origin);
318 let old_value = data.and_then(|&mut (ref mut total, ref mut entry)| {
319 entry.remove(&name).inspect(|old| {
320 *total -= name.len() + old.len();
321 })
322 });
323 sender.send(old_value).unwrap();
324 }
325
326 fn clear(
327 &mut self,
328 sender: GenericSender<bool>,
329 storage_type: StorageType,
330 webview_id: WebViewId,
331 url: ServoUrl,
332 ) {
333 let origin = self.origin_as_string(url);
334 let data = self.select_data_mut(storage_type, webview_id, &origin);
335 sender
336 .send(data.is_some_and(|&mut (ref mut total, ref mut entry)| {
337 if !entry.is_empty() {
338 entry.clear();
339 *total = 0;
340 true
341 } else {
342 false
343 }
344 }))
345 .unwrap();
346 }
347
348 fn clone(&mut self, src_webview_id: WebViewId, dest_webview_id: WebViewId) {
349 let Some(src_origin_entries) = self.session_data.get(&src_webview_id) else {
350 return;
351 };
352
353 let dest_origin_entries = src_origin_entries.clone();
354 self.session_data
355 .insert(dest_webview_id, dest_origin_entries);
356 }
357
358 fn origin_as_string(&self, url: ServoUrl) -> String {
359 url.origin().ascii_serialization()
360 }
361}