diff options
author | Zhen Zhang <izgzhen@gmail.com> | 2016-07-24 11:37:34 +0200 |
---|---|---|
committer | Zhen Zhang <izgzhen@gmail.com> | 2016-07-25 19:39:16 +0200 |
commit | 9c8ebd3ce1f48f2aff811d6f3eedd7a3f3b8f553 (patch) | |
tree | 624d686a08f6dd9c208366062670581c490c8383 /components/net/filemanager_thread.rs | |
parent | 2de3b119a961942943280fa280c50a7a814de583 (diff) | |
download | servo-9c8ebd3ce1f48f2aff811d6f3eedd7a3f3b8f553.tar.gz servo-9c8ebd3ce1f48f2aff811d6f3eedd7a3f3b8f553.zip |
Chunked ReadFile from file manager
Diffstat (limited to 'components/net/filemanager_thread.rs')
-rw-r--r-- | components/net/filemanager_thread.rs | 106 |
1 files changed, 74 insertions, 32 deletions
diff --git a/components/net/filemanager_thread.rs b/components/net/filemanager_thread.rs index 3b824759624..4b1734613f3 100644 --- a/components/net/filemanager_thread.rs +++ b/components/net/filemanager_thread.rs @@ -6,7 +6,8 @@ use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use mime_guess::guess_mime_type_opt; use net_traits::blob_url_store::{BlobBuf, BlobURLStoreError}; use net_traits::filemanager_thread::{FileManagerThreadMsg, FileManagerResult, FilterPattern, FileOrigin}; -use net_traits::filemanager_thread::{SelectedFile, RelativePos, FileManagerThreadError, SelectedFileId}; +use net_traits::filemanager_thread::{SelectedFile, RelativePos, FileManagerThreadError}; +use net_traits::filemanager_thread::{SelectedFileId, ReadFileProgress}; use std::collections::HashMap; use std::fs::File; use std::io::{Read, Seek, SeekFrom}; @@ -156,11 +157,8 @@ impl<UI: 'static + UIProvider> FileManager<UI> { } FileManagerThreadMsg::ReadFile(sender, id, check_url_validity, origin) => { spawn_named("read file".to_owned(), move || { - match store.try_read_file(id, check_url_validity, origin) { - Ok(buffer) => { let _ = sender.send(Ok(buffer)); } - Err(e) => { - let _ = sender.send(Err(FileManagerThreadError::BlobURLStoreError(e))); - } + if let Err(e) = store.try_read_file(sender.clone(), id, check_url_validity, origin) { + let _ = sender.send(Err(FileManagerThreadError::BlobURLStoreError(e))); } }) } @@ -370,8 +368,8 @@ impl <UI: 'static + UIProvider> FileManagerStore<UI> { fn create_entry(&self, file_path: &Path, origin: &str) -> Result<SelectedFile, FileManagerThreadError> { use net_traits::filemanager_thread::FileManagerThreadError::FileSystemError; - let handler = try!(File::open(file_path).map_err(|e| FileSystemError(e.to_string()))); - let metadata = try!(handler.metadata().map_err(|e| FileSystemError(e.to_string()))); + let file = try!(File::open(file_path).map_err(|e| FileSystemError(e.to_string()))); + let metadata = try!(file.metadata().map_err(|e| FileSystemError(e.to_string()))); let modified = try!(metadata.modified().map_err(|e| FileSystemError(e.to_string()))); let elapsed = try!(modified.elapsed().map_err(|e| FileSystemError(e.to_string()))); // Unix Epoch: https://doc.servo.org/std/time/constant.UNIX_EPOCH.html @@ -410,22 +408,28 @@ impl <UI: 'static + UIProvider> FileManagerStore<UI> { }) } - fn get_blob_buf(&self, id: &Uuid, origin_in: &FileOrigin, rel_pos: RelativePos, - check_url_validity: bool) -> Result<BlobBuf, BlobURLStoreError> { + fn get_blob_buf(&self, sender: IpcSender<FileManagerResult<ReadFileProgress>>, + id: &Uuid, origin_in: &FileOrigin, rel_pos: RelativePos, + check_url_validity: bool) -> Result<(), BlobURLStoreError> { let file_impl = try!(self.get_impl(id, origin_in, check_url_validity)); match file_impl { FileImpl::Memory(buf) => { let range = rel_pos.to_abs_range(buf.size as usize); - Ok(BlobBuf { + let buf = BlobBuf { filename: None, type_string: buf.type_string, size: range.len() as u64, bytes: buf.bytes.index(range).to_vec(), - }) + }; + + let _ = sender.send(Ok(ReadFileProgress::Meta(buf))); + let _ = sender.send(Ok(ReadFileProgress::EOF)); + + Ok(()) } FileImpl::MetaDataOnly(metadata) => { /* XXX: Snapshot state check (optional) https://w3c.github.io/FileAPI/#snapshot-state. - Concretely, here we create another handler, and this handler might not + Concretely, here we create another file, and this file might not has the same underlying file state (meta-info plus content) as the time create_entry is called. */ @@ -437,25 +441,19 @@ impl <UI: 'static + UIProvider> FileManagerStore<UI> { let mime = guess_mime_type_opt(metadata.path.clone()); let range = rel_pos.to_abs_range(metadata.size as usize); - let mut handler = try!(File::open(&metadata.path) + let mut file = try!(File::open(&metadata.path) .map_err(|e| BlobURLStoreError::External(e.to_string()))); - let seeked_start = try!(handler.seek(SeekFrom::Start(range.start as u64)) + let seeked_start = try!(file.seek(SeekFrom::Start(range.start as u64)) .map_err(|e| BlobURLStoreError::External(e.to_string()))); if seeked_start == (range.start as u64) { - let mut bytes = vec![0; range.len()]; - try!(handler.read_exact(&mut bytes) - .map_err(|e| BlobURLStoreError::External(e.to_string()))); - - Ok(BlobBuf { - filename: opt_filename, - type_string: match mime { - Some(x) => format!("{}", x), - None => "".to_string(), - }, - size: range.len() as u64, - bytes: bytes, - }) + let type_string = match mime { + Some(x) => format!("{}", x), + None => "".to_string(), + }; + + chunked_read(sender, &mut file, range.len(), opt_filename, type_string); + Ok(()) } else { Err(BlobURLStoreError::InvalidEntry) } @@ -463,16 +461,17 @@ impl <UI: 'static + UIProvider> FileManagerStore<UI> { FileImpl::Sliced(parent_id, inner_rel_pos) => { // Next time we don't need to check validity since // we have already done that for requesting URL if necessary - self.get_blob_buf(&parent_id, origin_in, rel_pos.slice_inner(&inner_rel_pos), false) + self.get_blob_buf(sender, &parent_id, origin_in, rel_pos.slice_inner(&inner_rel_pos), false) } } } // Convenient wrapper over get_blob_buf - fn try_read_file(&self, id: SelectedFileId, check_url_validity: bool, - origin_in: FileOrigin) -> Result<BlobBuf, BlobURLStoreError> { + fn try_read_file(&self, sender: IpcSender<FileManagerResult<ReadFileProgress>>, + id: SelectedFileId, check_url_validity: bool, + origin_in: FileOrigin) -> Result<(), BlobURLStoreError> { let id = try!(Uuid::parse_str(&id.0).map_err(|_| BlobURLStoreError::InvalidFileID)); - self.get_blob_buf(&id, &origin_in, RelativePos::full_range(), check_url_validity) + self.get_blob_buf(sender, &id, &origin_in, RelativePos::full_range(), check_url_validity) } fn dec_ref(&self, id: &Uuid, origin_in: &FileOrigin, @@ -563,3 +562,46 @@ fn select_files_pref_enabled() -> bool { PREFS.get("dom.testing.htmlinputelement.select_files.enabled") .as_boolean().unwrap_or(false) } + +const CHUNK_SIZE: usize = 8192; + +fn chunked_read(sender: IpcSender<FileManagerResult<ReadFileProgress>>, + file: &mut File, size: usize, opt_filename: Option<String>, type_string: String) { + // First chunk + let mut buf = vec![0; CHUNK_SIZE]; + match file.read(&mut buf) { + Ok(n) => { + buf.truncate(n); + let blob_buf = BlobBuf { + filename: opt_filename, + type_string: type_string, + size: size as u64, + bytes: buf, + }; + let _ = sender.send(Ok(ReadFileProgress::Meta(blob_buf))); + } + Err(e) => { + let _ = sender.send(Err(FileManagerThreadError::FileSystemError(e.to_string()))); + return; + } + } + + // Send the remaining chunks + loop { + let mut buf = vec![0; CHUNK_SIZE]; + match file.read(&mut buf) { + Ok(0) => { + let _ = sender.send(Ok(ReadFileProgress::EOF)); + return; + } + Ok(n) => { + buf.truncate(n); + let _ = sender.send(Ok(ReadFileProgress::Partial(buf))); + } + Err(e) => { + let _ = sender.send(Err(FileManagerThreadError::FileSystemError(e.to_string()))); + return; + } + } + } +} |