diff options
Diffstat (limited to 'components/net')
-rw-r--r-- | components/net/lib.rs | 1 | ||||
-rw-r--r-- | components/net/storage_task.rs | 165 |
2 files changed, 166 insertions, 0 deletions
diff --git a/components/net/lib.rs b/components/net/lib.rs index 99a1c0cf9d3..d3b1d5bfd95 100644 --- a/components/net/lib.rs +++ b/components/net/lib.rs @@ -37,6 +37,7 @@ pub mod data_loader; pub mod image_cache_task; pub mod local_image_cache; pub mod resource_task; +pub mod storage_task; mod sniffer_task; /// An implementation of the [Fetch spec](http://fetch.spec.whatwg.org/) diff --git a/components/net/storage_task.rs b/components/net/storage_task.rs new file mode 100644 index 00000000000..73e721c9255 --- /dev/null +++ b/components/net/storage_task.rs @@ -0,0 +1,165 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use std::comm::{channel, Receiver, Sender}; +use std::collections::HashMap; +use std::collections::TreeMap; +use url::Url; + +use servo_util::str::DOMString; +use servo_util::task::spawn_named; + +/// Request operations on the storage data associated with a particular url +pub enum StorageTaskMsg { + /// gets the number of key/value pairs present in the associated storage data + Length(Sender<u32>, Url), + + /// gets the name of the key at the specified index in the associated storage data + Key(Sender<Option<DOMString>>, Url, u32), + + /// gets the value associated with the given key in the associated storage data + GetItem(Sender<Option<DOMString>>, Url, DOMString), + + /// sets the value of the given key in the associated storage data + /// TODO throw QuotaExceededError in case of error + SetItem(Sender<bool>, Url, DOMString, DOMString), + + /// removes the key/value pair for the given key in the associated storage data + RemoveItem(Sender<bool>, Url, DOMString), + + /// clears the associated storage data by removing all the key/value pairs + Clear(Sender<bool>, Url), + + /// shut down this task + Exit +} + +/// Handle to a storage task +pub type StorageTask = Sender<StorageTaskMsg>; + +pub trait StorageTaskFactory { + fn new() -> StorageTask; +} + +impl StorageTaskFactory for StorageTask { + /// Create a StorageTask + fn new() -> StorageTask { + let (chan, port) = channel(); + spawn_named("StorageManager", proc() { + StorageManager::new(port).start(); + }); + chan + } +} + +struct StorageManager { + port: Receiver<StorageTaskMsg>, + data: HashMap<String, TreeMap<DOMString, DOMString>>, +} + +impl StorageManager { + fn new(port: Receiver<StorageTaskMsg>) -> StorageManager { + StorageManager { + port: port, + data: HashMap::new(), + } + } +} + +impl StorageManager { + fn start(&mut self) { + loop { + match self.port.recv() { + Length(sender, url) => { + self.length(sender, url) + } + Key(sender, url, index) => { + self.key(sender, url, index) + } + SetItem(sender, url, name, value) => { + self.set_item(sender, url, name, value) + } + GetItem(sender, url, name) => { + self.get_item(sender, url, name) + } + RemoveItem(sender, url, name) => { + self.remove_item(sender, url, name) + } + Clear(sender, url) => { + self.clear(sender, url) + } + Exit => { + break + } + } + } + } + + fn length(&self, sender: Sender<u32>, url: Url) { + let origin = self.get_origin_as_string(url); + sender.send(self.data.get(&origin).map_or(0u, |entry| entry.len()) as u32); + } + + fn key(&self, sender: Sender<Option<DOMString>>, url: Url, index: u32) { + let origin = self.get_origin_as_string(url); + sender.send(self.data.get(&origin) + .and_then(|entry| entry.keys().nth(index as uint)) + .map(|key| key.clone())); + } + + fn set_item(&mut self, sender: Sender<bool>, url: Url, name: DOMString, value: DOMString) { + let origin = self.get_origin_as_string(url); + if !self.data.contains_key(&origin) { + self.data.insert(origin.clone(), TreeMap::new()); + } + + let updated = self.data.get_mut(&origin).map(|entry| { + if entry.get(&origin).map_or(true, |item| item.as_slice() != value.as_slice()) { + entry.insert(name.clone(), value.clone()); + true + } else { + false + } + }).unwrap(); + + sender.send(updated); + } + + fn get_item(&self, sender: Sender<Option<DOMString>>, url: Url, name: DOMString) { + let origin = self.get_origin_as_string(url); + sender.send(self.data.get(&origin) + .and_then(|entry| entry.get(&name)) + .map(|value| value.to_string())); + } + + fn remove_item(&mut self, sender: Sender<bool>, url: Url, name: DOMString) { + let origin = self.get_origin_as_string(url); + sender.send(self.data.get_mut(&origin) + .map_or(false, |entry| entry.remove(&name).is_some())); + } + + fn clear(&mut self, sender: Sender<bool>, url: Url) { + let origin = self.get_origin_as_string(url); + sender.send(self.data.get_mut(&origin) + .map_or(false, |entry| { + if !entry.is_empty() { + entry.clear(); + true + } else { + false + }})); + } + + fn get_origin_as_string(&self, url: Url) -> String { + let mut origin = "".to_string(); + origin.push_str(url.scheme.as_slice()); + origin.push_str("://"); + url.domain().map(|domain| origin.push_str(domain.as_slice())); + url.port().map(|port| { + origin.push_str(":"); + origin.push_str(port.to_string().as_slice()); + }); + origin.push_str("/"); + origin + } +} |