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

Implement MIME sniffing #5005

Merged
merged 6 commits into from Apr 7, 2015
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -4,7 +4,8 @@

use net_traits::{LoadData, Metadata};
use net_traits::ProgressMsg::Done;
use resource_task::{TargetedLoadResponse, start_sending, ResponseSenders};
use mime_classifier::MIMEClassifier;
use resource_task::start_sending;
use file_loader;

use url::Url;
@@ -13,16 +14,13 @@ use util::resource_files::resources_dir_path;

use std::borrow::IntoCow;
use std::fs::PathExt;
use std::sync::mpsc::Sender;
use std::sync::Arc;

pub fn factory(mut load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {
let senders = ResponseSenders {
immediate_consumer: start_chan.clone(),
eventual_consumer: load_data.consumer.clone(),
};
pub fn factory(mut load_data: LoadData, classifier: Arc<MIMEClassifier>) {
match load_data.url.non_relative_scheme_data().unwrap() {
"blank" => {
let chan = start_sending(senders, Metadata {
let start_chan = load_data.consumer;
let chan = start_sending(start_chan, Metadata {
final_url: load_data.url,
content_type: Some(("text".to_string(), "html".to_string())),
charset: Some("utf-8".to_string()),
@@ -40,10 +38,11 @@ pub fn factory(mut load_data: LoadData, start_chan: Sender<TargetedLoadResponse>
load_data.url = Url::from_file_path(&*path).unwrap();
}
_ => {
start_sending(senders, Metadata::default(load_data.url))
let start_chan = load_data.consumer;
start_sending(start_chan, Metadata::default(load_data.url))
.send(Done(Err("Unknown about: URL.".to_string()))).unwrap();
return
}
};
file_loader::factory(load_data, start_chan)
file_loader::factory(load_data, classifier)
}
@@ -4,34 +4,30 @@

use net_traits::{LoadData, Metadata};
use net_traits::ProgressMsg::{Payload, Done};
use resource_task::{TargetedLoadResponse, start_sending, ResponseSenders};
use mime_classifier::MIMEClassifier;
use resource_task::start_sending;

use rustc_serialize::base64::FromBase64;

use hyper::mime::Mime;
use std::sync::Arc;
use url::{percent_decode, SchemeData};

use std::sync::mpsc::Sender;

pub fn factory(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {
pub fn factory(load_data: LoadData, _classifier: Arc<MIMEClassifier>) {
// NB: we don't spawn a new task.
// Hypothesis: data URLs are too small for parallel base64 etc. to be worth it.
// Should be tested at some point.
// Left in separate function to allow easy moving to a task, if desired.
load(load_data, start_chan)
load(load_data)
}

fn load(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {
fn load(load_data: LoadData) {
let start_chan = load_data.consumer;
let url = load_data.url;
assert!(&*url.scheme == "data");

let mut metadata = Metadata::default(url.clone());

let senders = ResponseSenders {
immediate_consumer: start_chan,
eventual_consumer: load_data.consumer,
};

// Split out content type and data.
let mut scheme_data = match url.scheme_data {
SchemeData::NonRelative(scheme_data) => scheme_data,
@@ -46,7 +42,7 @@ fn load(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {
}
let parts: Vec<&str> = scheme_data.splitn(1, ',').collect();
if parts.len() != 2 {
start_sending(senders, metadata).send(Done(Err("invalid data uri".to_string()))).unwrap();
start_sending(start_chan, metadata).send(Done(Err("invalid data uri".to_string()))).unwrap();
return;
}

@@ -64,7 +60,7 @@ fn load(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {
let content_type: Option<Mime> = ct_str.parse().ok();
metadata.set_content_type(content_type.as_ref());

let progress_chan = start_sending(senders, metadata);
let progress_chan = start_sending(start_chan, metadata);
let bytes = percent_decode(parts[1].as_bytes());

if is_base64 {
@@ -93,11 +89,9 @@ fn assert_parse(url: &'static str,
data: Option<Vec<u8>>) {
use std::sync::mpsc::channel;
use url::Url;
use sniffer_task;

let (start_chan, start_port) = channel();
let sniffer_task = sniffer_task::new_sniffer_task();
load(LoadData::new(Url::parse(url).unwrap(), start_chan), sniffer_task);
load(LoadData::new(Url::parse(url).unwrap(), start_chan));

let response = start_port.recv().unwrap();
assert_eq!(&response.metadata.content_type, &content_type);
@@ -4,55 +4,78 @@

use net_traits::{LoadData, Metadata, ProgressMsg};
use net_traits::ProgressMsg::{Payload, Done};
use resource_task::{start_sending, TargetedLoadResponse, ResponseSenders};
use mime_classifier::MIMEClassifier;
use resource_task::{start_sending, start_sending_sniffed};

use std::borrow::ToOwned;
use std::io;
use std::fs::File;
use std::path::PathBuf;
use std::sync::Arc;
use std::sync::mpsc::Sender;
use util::task::spawn_named;

static READ_SIZE: uint = 8192;

enum ReadStatus {
Partial(Vec<u8>),
EOF,
}

fn read_block(reader: &mut io::Read) -> Result<ReadStatus, String> {
let mut buf = vec![0; READ_SIZE];
match reader.read(buf.as_mut_slice()) {
Ok(0) => return Ok(ReadStatus::EOF),
Ok(n) => {
buf.truncate(n);
Ok(ReadStatus::Partial(buf))
}
Err(e) => Err(e.description().to_string()),
}
}

fn read_all(reader: &mut io::Read, progress_chan: &Sender<ProgressMsg>)
-> Result<(), String> {
-> Result<(), String> {
loop {
let mut buf = vec![0; READ_SIZE];
match reader.read(buf.as_mut_slice()) {
Ok(0) => return Ok(()),
Ok(n) => {
buf.truncate(n);
progress_chan.send(Payload(buf)).unwrap();
},
Err(e) => return Err(e.description().to_string()),
match try!(read_block(reader)) {
ReadStatus::Partial(buf) => progress_chan.send(Payload(buf)).unwrap(),
ReadStatus::EOF => return Ok(()),
}
}
}

pub fn factory(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {
pub fn factory(load_data: LoadData, classifier: Arc<MIMEClassifier>) {
let url = load_data.url;
let start_chan = load_data.consumer;
assert!(&*url.scheme == "file");
let senders = ResponseSenders {
immediate_consumer: start_chan,
eventual_consumer: load_data.consumer,
};
let progress_chan = start_sending(senders, Metadata::default(url.clone()));
spawn_named("file_loader".to_owned(), move || {
let metadata = Metadata::default(url.clone());
let file_path: Result<PathBuf, ()> = url.to_file_path();
match file_path {
Ok(file_path) => {
match File::open(&file_path) {
Ok(ref mut reader) => {
let res = read_all(reader, &progress_chan);
let res = read_block(reader);
let (res, progress_chan) = match res {
Ok(ReadStatus::Partial(buf)) => {
let progress_chan = start_sending_sniffed(start_chan, metadata,
classifier, &buf);
progress_chan.send(Payload(buf)).unwrap();
(read_all(reader, &progress_chan), progress_chan)
}
Ok(ReadStatus::EOF) | Err(_) =>
(res.map(|_| ()), start_sending(start_chan, metadata)),
};
progress_chan.send(Done(res)).unwrap();
}
Err(e) => {
let progress_chan = start_sending(start_chan, metadata);
progress_chan.send(Done(Err(e.description().to_string()))).unwrap();
}
}
}
Err(_) => {
let progress_chan = start_sending(start_chan, metadata);
progress_chan.send(Done(Err(url.to_string()))).unwrap();
}
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.