Skip to content
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
merged 1 commit into from Jun 8, 2016
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -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

This comment has been minimized.

@izgzhen

izgzhen Jun 6, 2016

Author Contributor

@Manishearth Regarding factory, it is totally gone here. And load is just a function that will be called with the extended FileManager's attributes.

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())),

This comment has been minimized.

@izgzhen

izgzhen Jun 6, 2016

Author Contributor

I moved the stuff here (although far from the final model). If this might work, I will change the concrete store previously implemented in script thread to IpcSenders.

}
}

@@ -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);
}
}

@@ -49,6 +49,7 @@ extern crate webrender_traits;
extern crate websocket;

pub mod about_loader;
pub mod blob_loader;
pub mod bluetooth_thread;
pub mod chrome_loader;
pub mod connector;
@@ -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>,

This comment has been minimized.

@Manishearth

Manishearth Jun 8, 2016

Member

This will eventually become an enum between bytes, on-disk file name, and slice, right?

This comment has been minimized.

@izgzhen

izgzhen Jun 8, 2016

Author Contributor

Yes, the Optioned filename looks awkward itself :P

}

/// 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()
})
}
@@ -4,6 +4,7 @@

use ipc_channel::ipc::IpcSender;
use std::path::PathBuf;
use super::{LoadConsumer, LoadData};
use uuid::Uuid;

#[derive(Debug, Deserialize, Serialize)]
@@ -29,6 +30,9 @@ pub enum FileManagerThreadMsg {
/// Delete the FileID entry
DeleteFileID(Uuid),

/// Load resource by Blob URL
LoadBlob(LoadData, LoadConsumer),

/// Shut down this thread
Exit,
}
@@ -43,6 +43,7 @@ use storage_thread::StorageThreadMsg;
use url::Url;
use websocket::header;

pub mod blob_url_store;
pub mod bluetooth_scanfilter;
pub mod bluetooth_thread;
pub mod filemanager_thread;
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.