Add support for data: URLs

Fixes #778
This commit is contained in:
Keegan McAllister 2013-10-09 20:15:12 -07:00
parent f73e48b32f
commit 3824a01dc5
3 changed files with 69 additions and 0 deletions

View file

@ -0,0 +1,66 @@
/* 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 resource_task::{Done, Payload, Metadata, LoadResponse, LoaderTask, start_sending};
use extra::url::Url;
use extra::base64::FromBase64;
use http::headers::test_utils::from_stream_with_str;
use http::headers::content_type::MediaType;
pub fn factory() -> LoaderTask {
|url, start_chan| {
// 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.
load(url, start_chan)
}
}
fn load(url: Url, start_chan: Chan<LoadResponse>) {
assert!("data" == url.scheme);
let mut metadata = Metadata::default(url.clone());
// Split out content type and data.
let parts: ~[&str] = url.path.splitn_iter(',', 1).to_owned_vec();
if parts.len() != 2 {
start_sending(start_chan, metadata).send(Done(Err(())));
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];
if ct_str.ends_with(";base64") {
is_base64 = true;
ct_str = ct_str.slice_to(ct_str.as_bytes().len() - 7);
}
// Parse the content type using rust-http.
// FIXME: this can go into an infinite loop! (rust-http #25)
let content_type: Option<MediaType> = from_stream_with_str(ct_str);
metadata.set_content_type(&content_type);
let progress_chan = start_sending(start_chan, metadata);
if is_base64 {
match parts[1].from_base64() {
Err(*) => {
progress_chan.send(Done(Err(())));
}
Ok(data) => {
progress_chan.send(Payload(data));
progress_chan.send(Done(Ok(())));
}
}
} else {
// FIXME: Since the %-decoded URL is already a str, we can't
// handle UTF8-incompatible encodings.
progress_chan.send(Payload(parts[1].as_bytes().into_owned()));
progress_chan.send(Done(Ok(())));
}
}

View file

@ -26,6 +26,7 @@ pub mod image {
pub mod file_loader;
pub mod http_loader;
pub mod data_loader;
pub mod image_cache_task;
pub mod local_image_cache;
pub mod resource_task;

View file

@ -6,6 +6,7 @@
use file_loader;
use http_loader;
use data_loader;
use std::cell::Cell;
use std::comm::{Chan, Port, SharedChan};
@ -110,6 +111,7 @@ pub fn ResourceTask() -> ResourceTask {
let loaders = ~[
(~"file", file_loader::factory),
(~"http", http_loader::factory),
(~"data", data_loader::factory),
];
create_resource_task_with_loaders(loaders)
}