diff options
-rw-r--r-- | components/net/filemanager_thread.rs | 84 | ||||
-rw-r--r-- | components/net_traits/blob_url_store.rs | 8 | ||||
-rw-r--r-- | components/net_traits/filemanager_thread.rs | 10 | ||||
-rw-r--r-- | components/script/dom/bindings/trace.rs | 2 | ||||
-rw-r--r-- | components/script/dom/blob.rs | 9 | ||||
-rw-r--r-- | tests/unit/net/filemanager_thread.rs | 55 | ||||
-rw-r--r-- | tests/unit/net/test.txt | 1 |
7 files changed, 98 insertions, 71 deletions
diff --git a/components/net/filemanager_thread.rs b/components/net/filemanager_thread.rs index 9c741d00d49..5b18b332fdc 100644 --- a/components/net/filemanager_thread.rs +++ b/components/net/filemanager_thread.rs @@ -8,7 +8,7 @@ use mime_classifier::MIMEClassifier; use mime_guess::guess_mime_type_opt; use net_traits::blob_url_store::{BlobURLStoreEntry, BlobURLStoreError}; use net_traits::filemanager_thread::{FileManagerThreadMsg, FileManagerResult}; -use net_traits::filemanager_thread::{SelectedFile, FileManagerThreadError}; +use net_traits::filemanager_thread::{SelectedFile, FileManagerThreadError, SelectedFileId}; use std::collections::HashMap; use std::fs::File; use std::io::Read; @@ -18,13 +18,6 @@ use url::Origin; use util::thread::spawn_named; use uuid::Uuid; -pub struct FileManager { - receiver: IpcReceiver<FileManagerThreadMsg>, - idmap: HashMap<Uuid, PathBuf>, - classifier: Arc<MIMEClassifier>, - blob_url_store: Arc<RwLock<BlobURLStore>>, -} - pub trait FileManagerThreadFactory { fn new() -> Self; } @@ -42,6 +35,12 @@ impl FileManagerThreadFactory for IpcSender<FileManagerThreadMsg> { } } +struct FileManager { + receiver: IpcReceiver<FileManagerThreadMsg>, + idmap: HashMap<Uuid, PathBuf>, + classifier: Arc<MIMEClassifier>, + blob_url_store: Arc<RwLock<BlobURLStore>>, +} impl FileManager { fn new(recv: IpcReceiver<FileManagerThreadMsg>) -> FileManager { @@ -59,7 +58,12 @@ impl FileManager { match self.receiver.recv().unwrap() { FileManagerThreadMsg::SelectFile(sender) => self.select_file(sender), FileManagerThreadMsg::SelectFiles(sender) => self.select_files(sender), - FileManagerThreadMsg::ReadFile(sender, id) => self.read_file(sender, id), + FileManagerThreadMsg::ReadFile(sender, id) => { + match self.try_read_file(id) { + Ok(buffer) => { let _ = sender.send(Ok(buffer)); } + Err(_) => { let _ = sender.send(Err(FileManagerThreadError::ReadFileError)); } + } + } FileManagerThreadMsg::DeleteFileID(id) => self.delete_fileid(id), FileManagerThreadMsg::LoadBlob(load_data, consumer) => { blob_loader::load(load_data, consumer, @@ -67,7 +71,7 @@ impl FileManager { self.classifier.clone()); }, FileManagerThreadMsg::Exit => break, - } + }; } } } @@ -75,31 +79,25 @@ impl FileManager { impl FileManager { fn select_file(&mut self, sender: IpcSender<FileManagerResult<SelectedFile>>) { // TODO: Pull the dialog UI in and get selected - let selected_path = Path::new(""); + // XXX: "test.txt" is "tests/unit/net/test.txt", for temporary testing purpose + let selected_path = Path::new("test.txt"); match self.create_entry(selected_path) { - Some(triple) => { - let _ = sender.send(Ok(triple)); - }, - None => { - let _ = sender.send(Err(FileManagerThreadError::InvalidSelection)); - } - } + Some(triple) => { let _ = sender.send(Ok(triple)); } + None => { let _ = sender.send(Err(FileManagerThreadError::InvalidSelection)); } + }; } fn select_files(&mut self, sender: IpcSender<FileManagerResult<Vec<SelectedFile>>>) { - let selected_paths = vec![Path::new("")]; + let selected_paths = vec![Path::new("test.txt")]; let mut replies = vec![]; for path in selected_paths { match self.create_entry(path) { Some(triple) => replies.push(triple), - None => { - let _ = sender.send(Err(FileManagerThreadError::InvalidSelection)); - return; - } - } + None => { let _ = sender.send(Err(FileManagerThreadError::InvalidSelection)); } + }; } let _ = sender.send(Ok(replies)); @@ -128,7 +126,7 @@ impl FileManager { let filename_path = Path::new(filename); let mime = guess_mime_type_opt(filename_path); Some(SelectedFile { - id: id, + id: SelectedFileId(id.simple().to_string()), filename: filename_path.to_path_buf(), modified: epoch, type_string: match mime { @@ -144,30 +142,24 @@ impl FileManager { } } - fn read_file(&mut self, sender: IpcSender<FileManagerResult<Vec<u8>>>, id: Uuid) { - match self.idmap.get(&id).and_then(|filepath| { - let mut buffer = vec![]; - match File::open(&filepath) { - Ok(mut handler) => { - match handler.read_to_end(&mut buffer) { - Ok(_) => Some(buffer), - Err(_) => None, - } - }, - Err(_) => None, - } - }) { - Some(buffer) => { - let _ = sender.send(Ok(buffer)); + fn try_read_file(&mut self, id: SelectedFileId) -> Result<Vec<u8>, ()> { + let id = try!(Uuid::parse_str(&id.0).map_err(|_| ())); + + match self.idmap.get(&id) { + Some(filepath) => { + let mut buffer = vec![]; + let mut handler = try!(File::open(&filepath).map_err(|_| ())); + try!(handler.read_to_end(&mut buffer).map_err(|_| ())); + Ok(buffer) }, - None => { - let _ = sender.send(Err(FileManagerThreadError::ReadFileError)); - } - }; + None => Err(()) + } } - fn delete_fileid(&mut self, id: Uuid) { - self.idmap.remove(&id); + fn delete_fileid(&mut self, id: SelectedFileId) { + if let Ok(id) = Uuid::parse_str(&id.0) { + self.idmap.remove(&id); + } } } diff --git a/components/net_traits/blob_url_store.rs b/components/net_traits/blob_url_store.rs index 85fa81aa341..71d8c11b2de 100644 --- a/components/net_traits/blob_url_store.rs +++ b/components/net_traits/blob_url_store.rs @@ -2,7 +2,6 @@ * 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 ipc_channel::ipc::IpcSender; use std::str::FromStr; use url::Url; use uuid::Uuid; @@ -29,13 +28,6 @@ pub struct BlobURLStoreEntry { pub bytes: Vec<u8>, } -/// Message-passing style interface between store and loader -#[derive(Serialize, Deserialize)] -pub enum BlobURLStoreMsg { - /// Request for an blob entry identified by uuid - Request(Uuid, IpcSender<Result<BlobURLStoreEntry, BlobURLStoreError>>), -} - /// Parse URL as Blob URL scheme's definition /// https://w3c.github.io/FileAPI/#DefinitionOfScheme pub fn parse_blob_url(url: &Url) -> Option<(Uuid, Option<&str>)> { diff --git a/components/net_traits/filemanager_thread.rs b/components/net_traits/filemanager_thread.rs index 07a6180834f..3182161c9eb 100644 --- a/components/net_traits/filemanager_thread.rs +++ b/components/net_traits/filemanager_thread.rs @@ -5,11 +5,13 @@ use ipc_channel::ipc::IpcSender; use std::path::PathBuf; use super::{LoadConsumer, LoadData}; -use uuid::Uuid; + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct SelectedFileId(pub String); #[derive(Debug, Deserialize, Serialize)] pub struct SelectedFile { - pub id: Uuid, + pub id: SelectedFileId, pub filename: PathBuf, pub modified: u64, // https://w3c.github.io/FileAPI/#dfn-type @@ -25,10 +27,10 @@ pub enum FileManagerThreadMsg { SelectFiles(IpcSender<FileManagerResult<Vec<SelectedFile>>>), /// Read file, return the bytes - ReadFile(IpcSender<FileManagerResult<Vec<u8>>>, Uuid), + ReadFile(IpcSender<FileManagerResult<Vec<u8>>>, SelectedFileId), /// Delete the FileID entry - DeleteFileID(Uuid), + DeleteFileID(SelectedFileId), /// Load resource by Blob URL LoadBlob(LoadData, LoadConsumer), diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index f33a8834a08..2a9f0e52134 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -57,6 +57,7 @@ use js::rust::Runtime; use layout_interface::LayoutRPC; use libc; use msg::constellation_msg::{FrameType, PipelineId, SubpageId, WindowSizeData, WindowSizeType, ReferrerPolicy}; +use net_traits::filemanager_thread::SelectedFileId; use net_traits::image::base::{Image, ImageMetadata}; use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread}; use net_traits::response::HttpsState; @@ -324,6 +325,7 @@ no_jsmanaged_fields!(USVString); no_jsmanaged_fields!(ReferrerPolicy); no_jsmanaged_fields!(ResourceThreads); no_jsmanaged_fields!(SystemTime); +no_jsmanaged_fields!(SelectedFileId); impl JSTraceable for Box<ScriptChan + Send> { #[inline] diff --git a/components/script/dom/blob.rs b/components/script/dom/blob.rs index b89aa3b9ac2..d8beec236a8 100644 --- a/components/script/dom/blob.rs +++ b/components/script/dom/blob.rs @@ -14,14 +14,13 @@ use dom::bindings::str::DOMString; use encoding::all::UTF_8; use encoding::types::{EncoderTrap, Encoding}; use ipc_channel::ipc; -use net_traits::filemanager_thread::FileManagerThreadMsg; +use net_traits::filemanager_thread::{FileManagerThreadMsg, SelectedFileId}; use num_traits::ToPrimitive; use std::ascii::AsciiExt; use std::borrow::ToOwned; use std::cell::Cell; use std::cmp::{max, min}; use std::sync::Arc; -use uuid::Uuid; #[derive(Clone, JSTraceable)] pub struct DataSlice { @@ -95,7 +94,7 @@ impl DataSlice { #[derive(Clone, JSTraceable)] pub enum BlobImpl { /// File-based, cached backend - File(Uuid, DOMRefCell<Option<DataSlice>>), + File(SelectedFileId, DOMRefCell<Option<DataSlice>>), /// Memory-based backend Memory(DataSlice), } @@ -107,7 +106,7 @@ impl BlobImpl { } /// Construct file-backed BlobImpl from File ID - pub fn new_from_file(file_id: Uuid) -> BlobImpl { + pub fn new_from_file(file_id: SelectedFileId) -> BlobImpl { BlobImpl::File(file_id, DOMRefCell::new(None)) } @@ -184,7 +183,7 @@ impl Blob { } } -fn read_file(global: GlobalRef, id: Uuid) -> Result<DataSlice, ()> { +fn read_file(global: GlobalRef, id: SelectedFileId) -> Result<DataSlice, ()> { let file_manager = global.filemanager_thread(); let (chan, recv) = ipc::channel().map_err(|_|())?; let _ = file_manager.send(FileManagerThreadMsg::ReadFile(chan, id)); diff --git a/tests/unit/net/filemanager_thread.rs b/tests/unit/net/filemanager_thread.rs index eb4ce535007..fe03bdc401e 100644 --- a/tests/unit/net/filemanager_thread.rs +++ b/tests/unit/net/filemanager_thread.rs @@ -5,18 +5,60 @@ use ipc_channel::ipc::{self, IpcSender}; use net::filemanager_thread::FileManagerThreadFactory; use net_traits::filemanager_thread::{FileManagerThreadMsg, FileManagerThreadError}; +use std::fs::File; +use std::io::Read; +use std::path::PathBuf; #[test] fn test_filemanager() { let chan: IpcSender<FileManagerThreadMsg> = FileManagerThreadFactory::new(); + // Try to open a dummy file "tests/unit/net/test.txt" in tree + let mut handler = File::open("test.txt").expect("test.txt is stolen"); + let mut test_file_content = vec![]; + + handler.read_to_end(&mut test_file_content) + .expect("Read tests/unit/net/test.txt error"); + + { + // Try to select a dummy file "tests/unit/net/test.txt" let (tx, rx) = ipc::channel().unwrap(); - let _ = chan.send(FileManagerThreadMsg::SelectFile(tx)); + chan.send(FileManagerThreadMsg::SelectFile(tx)).unwrap(); + let selected = rx.recv().expect("File manager channel is broken") + .expect("The file manager failed to find test.txt"); + + // Expecting attributes conforming the spec + assert!(selected.filename == PathBuf::from("test.txt")); + assert!(selected.type_string == "text/plain".to_string()); + + // Test by reading, expecting same content + { + let (tx2, rx2) = ipc::channel().unwrap(); + chan.send(FileManagerThreadMsg::ReadFile(tx2, selected.id.clone())).unwrap(); + + let msg = rx2.recv().expect("File manager channel is broken"); - match rx.recv().unwrap() { - Err(FileManagerThreadError::InvalidSelection) => {}, - _ => assert!(false, "Should be an invalid selection before dialog is implemented"), + let vec = msg.expect("File manager reading failure is unexpected"); + assert!(test_file_content == vec, "Read content differs"); + } + + // Delete the id + chan.send(FileManagerThreadMsg::DeleteFileID(selected.id.clone())).unwrap(); + + // Test by reading again, expecting read error because we invalidated the id + { + let (tx2, rx2) = ipc::channel().unwrap(); + chan.send(FileManagerThreadMsg::ReadFile(tx2, selected.id.clone())).unwrap(); + + let msg = rx2.recv().expect("File manager channel is broken"); + + match msg { + Err(FileManagerThreadError::ReadFileError) => {}, + other => { + assert!(false, "Get unexpected response after deleting the id: {:?}", other); + } + } } } @@ -26,9 +68,6 @@ fn test_filemanager() { let (tx, rx) = ipc::channel().unwrap(); let _ = chan.send(FileManagerThreadMsg::SelectFile(tx)); - match rx.try_recv() { - Ok(_) => assert!(false, "The thread should not response fine after exited"), - Err(_) => {}, - } + assert!(rx.try_recv().is_err(), "The thread should not respond normally after exited"); } } diff --git a/tests/unit/net/test.txt b/tests/unit/net/test.txt new file mode 100644 index 00000000000..75bdfe4ef1c --- /dev/null +++ b/tests/unit/net/test.txt @@ -0,0 +1 @@ +hello, servo
\ No newline at end of file |