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

View file

@ -2,6 +2,7 @@
* 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 data_loader::decode;
use fetch::cors_cache::{BasicCORSCache, CORSCache, CacheRequestDetails};
use http_loader::{NetworkHttpRequestFactory, create_http_connector, obtain_response};
use hyper::header::{Accept, CacheControl, IfMatch, IfRange, IfUnmodifiedSince, Location};
@ -305,7 +306,23 @@ fn basic_fetch(request: Rc<Request>) -> Response {
http_fetch(request.clone(), BasicCORSCache::new(), false, false, false)
},
"blob" | "data" | "file" | "ftp" => {
"data" => {
if *request.method.borrow() == Method::Get {
match decode(&url) {
Ok((mime, bytes)) => {
let mut response = Response::new();
*response.body.lock().unwrap() = ResponseBody::Done(bytes);
response.headers.set(ContentType(mime));
response
},
Err(_) => Response::network_error()
}
} else {
Response::network_error()
}
},
"blob" | "file" | "ftp" => {
// XXXManishearth handle these
panic!("Unimplemented scheme for Fetch")
},