diff options
Diffstat (limited to 'components/net/storage_task.rs')
-rw-r--r-- | components/net/storage_task.rs | 74 |
1 files changed, 52 insertions, 22 deletions
diff --git a/components/net/storage_task.rs b/components/net/storage_task.rs index 25be0ff07bc..1b25d9d03e2 100644 --- a/components/net/storage_task.rs +++ b/components/net/storage_task.rs @@ -12,6 +12,8 @@ use url::Url; use util::str::DOMString; use util::task::spawn_named; +const QUOTA_SIZE_LIMIT: usize = 5 * 1024 * 1024; + pub trait StorageTaskFactory { fn new() -> Self; } @@ -29,8 +31,8 @@ impl StorageTaskFactory for StorageTask { struct StorageManager { port: IpcReceiver<StorageTaskMsg>, - session_data: HashMap<String, BTreeMap<DOMString, DOMString>>, - local_data: HashMap<String, BTreeMap<DOMString, DOMString>>, + session_data: HashMap<String, (usize, BTreeMap<DOMString, DOMString>)>, + local_data: HashMap<String, (usize, BTreeMap<DOMString, DOMString>)>, } impl StorageManager { @@ -76,7 +78,7 @@ impl StorageManager { } fn select_data(&self, storage_type: StorageType) - -> &HashMap<String, BTreeMap<DOMString, DOMString>> { + -> &HashMap<String, (usize, BTreeMap<DOMString, DOMString>)> { match storage_type { StorageType::Session => &self.session_data, StorageType::Local => &self.local_data @@ -84,7 +86,7 @@ impl StorageManager { } fn select_data_mut(&mut self, storage_type: StorageType) - -> &mut HashMap<String, BTreeMap<DOMString, DOMString>> { + -> &mut HashMap<String, (usize, BTreeMap<DOMString, DOMString>)> { match storage_type { StorageType::Session => &mut self.session_data, StorageType::Local => &mut self.local_data @@ -94,7 +96,7 @@ impl StorageManager { fn length(&self, sender: IpcSender<usize>, url: Url, storage_type: StorageType) { let origin = self.origin_as_string(url); let data = self.select_data(storage_type); - sender.send(data.get(&origin).map_or(0, |entry| entry.len())).unwrap(); + sender.send(data.get(&origin).map_or(0, |&(_, ref entry)| entry.len())).unwrap(); } fn key(&self, @@ -105,7 +107,7 @@ impl StorageManager { let origin = self.origin_as_string(url); let data = self.select_data(storage_type); sender.send(data.get(&origin) - .and_then(|entry| entry.keys().nth(index as usize)) + .and_then(|&(_, ref entry)| entry.keys().nth(index as usize)) .map(|key| key.clone())).unwrap(); } @@ -116,35 +118,59 @@ impl StorageManager { let origin = self.origin_as_string(url); let data = self.select_data(storage_type); let keys = data.get(&origin) - .map_or(vec![], |entry| entry.keys().cloned().collect()); + .map_or(vec![], |&(_, ref entry)| entry.keys().cloned().collect()); sender.send(keys).unwrap(); } - /// Sends Some(old_value) in case there was a previous value with the same key name but with different - /// value name, otherwise sends None + /// Sends Ok(changed, Some(old_value)) in case there was a previous + /// value with the same key name but with different value name + /// otherwise sends Err(()) to indicate that the operation would result in + /// exceeding the quota limit fn set_item(&mut self, - sender: IpcSender<(bool, Option<DOMString>)>, + sender: IpcSender<Result<(bool, Option<DOMString>), ()>>, url: Url, storage_type: StorageType, name: DOMString, value: DOMString) { let origin = self.origin_as_string(url); + + let current_total_size = { + let local_data = self.select_data(StorageType::Local); + let session_data = self.select_data(StorageType::Session); + let local_data_size = local_data.get(&origin).map_or(0, |&(total, _)| total); + let session_data_size = session_data.get(&origin).map_or(0, |&(total, _)| total); + local_data_size + session_data_size + }; + let data = self.select_data_mut(storage_type); if !data.contains_key(&origin) { - data.insert(origin.clone(), BTreeMap::new()); + data.insert(origin.clone(), (0, BTreeMap::new())); } - let (changed, old_value) = data.get_mut(&origin).map(|entry| { - entry.insert(name, value.clone()).map_or( - (true, None), + let message = data.get_mut(&origin).map(|&mut (ref mut total, ref mut entry)| { + let mut new_total_size = current_total_size + value.as_bytes().len(); + if let Some(old_value) = entry.get(&name) { + new_total_size -= old_value.as_bytes().len(); + } else { + new_total_size += name.as_bytes().len(); + } + + if new_total_size > QUOTA_SIZE_LIMIT { + return Err(()); + } + + let message = entry.insert(name.clone(), value.clone()).map_or( + Ok((true, None)), |old| if old == value { - (false, None) + Ok((false, None)) } else { - (true, Some(old)) - }) + Ok((true, Some(old))) + }); + *total = new_total_size; + message }).unwrap(); - sender.send((changed, old_value)).unwrap(); + sender.send(message).unwrap(); } fn request_item(&self, @@ -155,7 +181,7 @@ impl StorageManager { let origin = self.origin_as_string(url); let data = self.select_data(storage_type); sender.send(data.get(&origin) - .and_then(|entry| entry.get(&name)) + .and_then(|&(_, ref entry)| entry.get(&name)) .map(|value| value.to_string())).unwrap(); } @@ -167,8 +193,11 @@ impl StorageManager { name: DOMString) { let origin = self.origin_as_string(url); let data = self.select_data_mut(storage_type); - let old_value = data.get_mut(&origin).and_then(|entry| { - entry.remove(&name) + let old_value = data.get_mut(&origin).and_then(|&mut (ref mut total, ref mut entry)| { + entry.remove(&name).and_then(|old| { + *total -= name.as_bytes().len() + old.as_bytes().len(); + Some(old) + }) }); sender.send(old_value).unwrap(); } @@ -177,9 +206,10 @@ impl StorageManager { let origin = self.origin_as_string(url); let data = self.select_data_mut(storage_type); sender.send(data.get_mut(&origin) - .map_or(false, |entry| { + .map_or(false, |&mut (ref mut total, ref mut entry)| { if !entry.is_empty() { entry.clear(); + *total = 0; true } else { false |