servo/components/net/data_loader.rs
Eli Friedman 10664cf3f4 Refactor resource loaders to use send_error utility.
No substantial functional change.
2015-10-13 16:37:12 -07:00

88 lines
3.3 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* 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 hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};
use mime_classifier::MIMEClassifier;
use net_traits::ProgressMsg::{Done, Payload};
use net_traits::{LoadConsumer, LoadData, Metadata};
use resource_task::{send_error, start_sending};
use rustc_serialize::base64::FromBase64;
use std::sync::Arc;
use url::SchemeData;
use url::percent_encoding::percent_decode;
pub fn factory(load_data: LoadData, senders: LoadConsumer, _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, senders)
}
pub fn load(load_data: LoadData, start_chan: LoadConsumer) {
let url = load_data.url;
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.")
};
match url.query {
Some(ref query) => {
scheme_data.push_str("?");
scheme_data.push_str(query);
},
None => ()
}
let parts: Vec<&str> = scheme_data.splitn(2, ',').collect();
if parts.len() != 2 {
send_error(url, "invalid data uri".to_owned(), start_chan);
return;
}
// ";base64" must come at the end of the content type, per RFC 2397.
// rust-http will fail to parse it because there's no =value part.
let mut is_base64 = false;
let mut ct_str = parts[0].to_owned();
if ct_str.ends_with(";base64") {
is_base64 = true;
let end_index = ct_str.len() - 7;
ct_str.truncate(end_index);
}
if ct_str.starts_with(";charset=") {
ct_str = format!("text/plain{}", ct_str);
}
// Parse the content type using rust-http.
// FIXME: this can go into an infinite loop! (rust-http #25)
let mut content_type: Option<Mime> = ct_str.parse().ok();
if content_type == None {
content_type = Some(Mime(TopLevel::Text, SubLevel::Plain,
vec!((Attr::Charset, Value::Ext("US-ASCII".to_owned())))));
}
let mut metadata = Metadata::default(url);
metadata.set_content_type(content_type.as_ref());
let progress_chan = start_sending(start_chan, metadata);
let bytes = percent_decode(parts[1].as_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(..) => {
progress_chan.send(Done(Err("non-base64 data uri".to_owned()))).unwrap();
}
Ok(data) => {
progress_chan.send(Payload(data)).unwrap();
progress_chan.send(Done(Ok(()))).unwrap();
}
}
} else {
progress_chan.send(Payload(bytes)).unwrap();
progress_chan.send(Done(Ok(()))).unwrap();
}
}