New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add blob loader #11536
Merged
+191
−0
Merged
Add blob loader #11536
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.
| @@ -0,0 +1,87 @@ | ||
| /* 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 filemanager_thread::BlobURLStore; | ||
| use hyper::header::{DispositionType, ContentDisposition, DispositionParam}; | ||
| use hyper::header::{Headers, ContentType, ContentLength, Charset}; | ||
| use hyper::http::RawStatus; | ||
| use mime::{Mime, Attr}; | ||
| use mime_classifier::MIMEClassifier; | ||
| use net_traits::ProgressMsg::Done; | ||
| use net_traits::blob_url_store::{parse_blob_url, BlobURLStoreEntry, BlobURLStoreError}; | ||
| use net_traits::response::HttpsState; | ||
| use net_traits::{LoadConsumer, LoadData, Metadata, NetworkError}; | ||
| use resource_thread::{send_error, start_sending_sniffed_opt}; | ||
| use std::str; | ||
| use std::sync::{Arc, RwLock}; | ||
|
|
||
|
|
||
| // TODO: Check on GET | ||
| // https://w3c.github.io/FileAPI/#requestResponseModel | ||
|
|
||
| pub fn load(load_data: LoadData, consumer: LoadConsumer, | ||
| blob_url_store: Arc<RwLock<BlobURLStore>>, | ||
| classifier: Arc<MIMEClassifier>) { // XXX: Move it into net process later | ||
|
|
||
|
||
| match parse_blob_url(&load_data.url) { | ||
| None => { | ||
| let format_err = NetworkError::Internal(format!("Invalid blob URL format {:?}", load_data.url)); | ||
| send_error(load_data.url.clone(), format_err, consumer); | ||
| } | ||
| Some((uuid, _fragment)) => { | ||
| match blob_url_store.read().unwrap().request(uuid, &load_data.url.origin()) { | ||
| Ok(entry) => load_blob(&load_data, consumer, classifier, entry), | ||
| Err(e) => { | ||
| let err = match e { | ||
| BlobURLStoreError::InvalidKey => | ||
| format!("Invalid blob URL key {:?}", uuid.simple().to_string()), | ||
| BlobURLStoreError::InvalidOrigin => | ||
| format!("Invalid blob URL origin {:?}", load_data.url.origin()), | ||
| }; | ||
| send_error(load_data.url.clone(), NetworkError::Internal(err), consumer); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| fn load_blob(load_data: &LoadData, | ||
| start_chan: LoadConsumer, | ||
| classifier: Arc<MIMEClassifier>, | ||
| entry: &BlobURLStoreEntry) { | ||
| let content_type: Mime = entry.type_string.parse().unwrap_or(mime!(Text / Plain)); | ||
| let charset = content_type.get_param(Attr::Charset); | ||
|
|
||
| let mut headers = Headers::new(); | ||
|
|
||
| if let Some(ref name) = entry.filename { | ||
| let charset = charset.and_then(|c| c.as_str().parse().ok()); | ||
| headers.set(ContentDisposition { | ||
| disposition: DispositionType::Inline, | ||
| parameters: vec![ | ||
| DispositionParam::Filename(charset.unwrap_or(Charset::Us_Ascii), | ||
| None, name.as_bytes().to_vec()) | ||
| ] | ||
| }); | ||
| } | ||
|
|
||
| headers.set(ContentType(content_type.clone())); | ||
| headers.set(ContentLength(entry.size)); | ||
|
|
||
| let metadata = Metadata { | ||
| final_url: load_data.url.clone(), | ||
| content_type: Some(ContentType(content_type.clone())), | ||
| charset: charset.map(|c| c.as_str().to_string()), | ||
| headers: Some(headers), | ||
| // https://w3c.github.io/FileAPI/#TwoHundredOK | ||
| status: Some(RawStatus(200, "OK".into())), | ||
| https_state: HttpsState::None, | ||
| }; | ||
|
|
||
| if let Ok(chan) = | ||
| start_sending_sniffed_opt(start_chan, metadata, classifier, | ||
| &entry.bytes, load_data.context.clone()) { | ||
| let _ = chan.send(Done(Ok(()))); | ||
| } | ||
| } | ||
| @@ -2,20 +2,27 @@ | ||
| * 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 blob_loader; | ||
| use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; | ||
| 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 std::collections::HashMap; | ||
| use std::fs::File; | ||
| use std::io::Read; | ||
| use std::path::{Path, PathBuf}; | ||
| use std::sync::{Arc, RwLock}; | ||
| 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 { | ||
| @@ -41,6 +48,8 @@ impl FileManager { | ||
| FileManager { | ||
| receiver: recv, | ||
| idmap: HashMap::new(), | ||
| classifier: Arc::new(MIMEClassifier::new()), | ||
| blob_url_store: Arc::new(RwLock::new(BlobURLStore::new())), | ||
izgzhen
Author
Contributor
|
||
| } | ||
| } | ||
|
|
||
| @@ -52,6 +61,11 @@ impl FileManager { | ||
| FileManagerThreadMsg::SelectFiles(sender) => self.select_files(sender), | ||
| FileManagerThreadMsg::ReadFile(sender, id) => self.read_file(sender, id), | ||
| FileManagerThreadMsg::DeleteFileID(id) => self.delete_fileid(id), | ||
| FileManagerThreadMsg::LoadBlob(load_data, consumer) => { | ||
| blob_loader::load(load_data, consumer, | ||
| self.blob_url_store.clone(), | ||
| self.classifier.clone()); | ||
| }, | ||
| FileManagerThreadMsg::Exit => break, | ||
| } | ||
| } | ||
| @@ -156,3 +170,37 @@ impl FileManager { | ||
| self.idmap.remove(&id); | ||
| } | ||
| } | ||
|
|
||
| pub struct BlobURLStore { | ||
| entries: HashMap<Uuid, (Origin, BlobURLStoreEntry)>, | ||
| } | ||
|
|
||
| impl BlobURLStore { | ||
| pub fn new() -> BlobURLStore { | ||
| BlobURLStore { | ||
| entries: HashMap::new(), | ||
| } | ||
| } | ||
|
|
||
| pub fn request(&self, id: Uuid, origin: &Origin) -> Result<&BlobURLStoreEntry, BlobURLStoreError> { | ||
| match self.entries.get(&id) { | ||
| Some(ref pair) => { | ||
| if pair.0 == *origin { | ||
| Ok(&pair.1) | ||
| } else { | ||
| Err(BlobURLStoreError::InvalidOrigin) | ||
| } | ||
| } | ||
| None => Err(BlobURLStoreError::InvalidKey) | ||
| } | ||
| } | ||
|
|
||
| pub fn add_entry(&mut self, id: Uuid, origin: Origin, blob: BlobURLStoreEntry) { | ||
| self.entries.insert(id, (origin, blob)); | ||
| } | ||
|
|
||
| pub fn delete_entry(&mut self, id: Uuid) { | ||
| self.entries.remove(&id); | ||
| } | ||
| } | ||
|
|
||
| @@ -0,0 +1,50 @@ | ||
| /* 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 ipc_channel::ipc::IpcSender; | ||
| use std::str::FromStr; | ||
| use url::Url; | ||
| use uuid::Uuid; | ||
|
|
||
| /// Errors returns to BlobURLStoreMsg::Request | ||
| #[derive(Clone, Serialize, Deserialize)] | ||
| pub enum BlobURLStoreError { | ||
| /// Invalid UUID key | ||
| InvalidKey, | ||
| /// Invalid URL origin | ||
| InvalidOrigin, | ||
| } | ||
|
|
||
| /// Blob URL store entry, a packaged form of Blob DOM object | ||
| #[derive(Clone, Serialize, Deserialize)] | ||
| pub struct BlobURLStoreEntry { | ||
| /// MIME type string | ||
| pub type_string: String, | ||
| /// Some filename if the backend of Blob is a file | ||
| pub filename: Option<String>, | ||
| /// Size of content in bytes | ||
| pub size: u64, | ||
| /// Content of blob | ||
| pub bytes: Vec<u8>, | ||
Manishearth
Member
|
||
| } | ||
|
|
||
| /// 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>)> { | ||
| url.path_segments().and_then(|mut segments| { | ||
| let id_str = match (segments.next(), segments.next()) { | ||
| (Some(s), None) => s, | ||
| _ => return None, | ||
| }; | ||
|
|
||
| Uuid::from_str(id_str).map(|id| (id, url.fragment())).ok() | ||
| }) | ||
| } | ||
ProTip!
Use n and p to navigate between commits in a pull request.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
@Manishearth Regarding
factory, it is totally gone here. Andloadis just a function that will be called with the extendedFileManager's attributes.