implements data-url fetching

This commit is contained in:
Rahul Sharma 2016-03-29 21:54:19 +05:30
parent 9a8d62286c
commit 3e74164e5f
3 changed files with 85 additions and 23 deletions

View file

@ -4,12 +4,14 @@
use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};
use mime_classifier::MIMEClassifier;
use net_traits::ProgressMsg::{Done, Payload};
use net_traits::{LoadConsumer, LoadData, Metadata};
use net_traits::LoadConsumer;
use net_traits::ProgressMsg::{Payload, Done};
use net_traits::{LoadData, Metadata};
use resource_thread::{CancellationListener, send_error, start_sending_sniffed_opt};
use rustc_serialize::base64::FromBase64;
use std::sync::Arc;
use url::SchemeData;
use url::Url;
use url::percent_encoding::percent_decode;
pub fn factory(load_data: LoadData,
@ -23,17 +25,19 @@ pub fn factory(load_data: LoadData,
load(load_data, senders, classifier, cancel_listener)
}
pub fn load(load_data: LoadData,
start_chan: LoadConsumer,
classifier: Arc<MIMEClassifier>,
cancel_listener: CancellationListener) {
let url = load_data.url;
assert!(&*url.scheme == "data");
pub enum DecodeError {
InvalidDataUri,
NonBase64DataUri,
}
pub type DecodeData = (Mime, Vec<u8>);
pub fn decode(url: &Url) -> Result<DecodeData, DecodeError> {
assert!(&*url.scheme == "data");
// Split out content type and data.
let mut scheme_data = match url.scheme_data {
SchemeData::NonRelative(ref scheme_data) => scheme_data.clone(),
_ => panic!("Expected a non-relative scheme URL.")
_ => panic!("Expected a non-relative scheme URL."),
};
match url.query {
Some(ref query) => {
@ -44,8 +48,7 @@ pub fn load(load_data: LoadData,
}
let parts: Vec<&str> = scheme_data.splitn(2, ',').collect();
if parts.len() != 2 {
send_error(url, "invalid data uri".to_owned(), start_chan);
return;
return Err(DecodeError::InvalidDataUri);
}
// ";base64" must come at the end of the content type, per RFC 2397.
@ -69,31 +72,45 @@ pub fn load(load_data: LoadData,
vec!((Attr::Charset, Value::Ext("US-ASCII".to_owned())))));
}
if cancel_listener.is_cancelled() {
return;
}
let bytes = percent_decode(parts[1].as_bytes());
let bytes = if is_base64 {
// FIXME(#2909): Its unclear what to do with non-alphabet characters,
// but Acid 3 apparently depends on spaces being ignored.
let bytes = bytes.into_iter().filter(|&b| b != ' ' as u8).collect::<Vec<u8>>();
match bytes.from_base64() {
Err(..) => return send_error(url, "non-base64 data uri".to_owned(), start_chan),
Err(..) => return Err(DecodeError::NonBase64DataUri),
Ok(data) => data,
}
} else {
bytes
};
Ok((content_type.unwrap(), bytes))
}
let mut metadata = Metadata::default(url);
metadata.set_content_type(content_type.as_ref());
if let Ok(chan) = start_sending_sniffed_opt(start_chan,
pub fn load(load_data: LoadData,
start_chan: LoadConsumer,
classifier: Arc<MIMEClassifier>,
cancel_listener: CancellationListener) {
let url = load_data.url;
if cancel_listener.is_cancelled() {
return;
}
match decode(&url) {
Ok((content_type, bytes)) => {
let mut metadata = Metadata::default(url);
metadata.set_content_type(Some(content_type).as_ref());
if let Ok(chan) = start_sending_sniffed_opt(start_chan,
metadata,
classifier,
&bytes,
load_data.context) {
let _ = chan.send(Payload(bytes));
let _ = chan.send(Done(Ok(())));
let _ = chan.send(Payload(bytes));
let _ = chan.send(Done(Ok(())));
}
},
Err(DecodeError::InvalidDataUri) => send_error(url, "invalid data uri".to_owned(), start_chan),
Err(DecodeError::NonBase64DataUri) => send_error(url, "non-base64 data uri".to_owned(), start_chan),
}
}