Skip to content

Commit

Permalink
Implement blob url support in the fetch stack.
Browse files Browse the repository at this point in the history
  • Loading branch information
Ms2ger committed Oct 14, 2016
1 parent 92f1cbc commit e134871
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 4 deletions.
70 changes: 70 additions & 0 deletions components/net/blob_loader.rs
Expand Up @@ -18,6 +18,7 @@ use resource_thread::{send_error, start_sending_sniffed_opt};
use resource_thread::CancellationListener;
use std::boxed::FnBox;
use std::sync::Arc;
use url::Url;
use util::thread::spawn_named;

// TODO: Check on GET
Expand Down Expand Up @@ -119,3 +120,72 @@ fn load_blob<UI: 'static + UIProvider>
send_error(load_data.url.clone(), format_err, start_chan);
}
}

/// https://fetch.spec.whatwg.org/#concept-basic-fetch (partial)
// TODO: make async.
pub fn load_blob_sync<UI: 'static + UIProvider>
(url: Url,
filemanager: FileManager<UI>)
-> Result<(Headers, Vec<u8>), NetworkError> {
let (id, origin) = match parse_blob_url(&url) {
Ok((id, origin, _fragment)) => (id, origin),
Err(()) => {
let e = format!("Invalid blob URL format {:?}", url);
return Err(NetworkError::Internal(e));
}
};

let (sender, receiver) = ipc::channel().unwrap();
let check_url_validity = true;
let msg = FileManagerThreadMsg::ReadFile(sender, id, check_url_validity, origin);
let _ = filemanager.handle(msg, None);

let blob_buf = match receiver.recv().unwrap() {
Ok(ReadFileProgress::Meta(blob_buf)) => blob_buf,
Ok(_) => {
return Err(NetworkError::Internal("Invalid filemanager reply".to_string()));
}
Err(e) => {
return Err(NetworkError::Internal(format!("{:?}", e)));
}
};

let content_type: Mime = blob_buf.type_string.parse().unwrap_or(mime!(Text / Plain));
let charset = content_type.get_param(Attr::Charset);

let mut headers = Headers::new();

if let Some(name) = blob_buf.filename {
let charset = charset.and_then(|c| c.as_str().parse().ok());
headers.set(ContentDisposition {
disposition: DispositionType::Inline,
parameters: vec![
DispositionParam::Filename(charset.unwrap_or(Charset::Us_Ascii),
None, name.as_bytes().to_vec())
]
});
}

// Basic fetch, Step 4.
headers.set(ContentLength(blob_buf.size as u64));
// Basic fetch, Step 5.
headers.set(ContentType(content_type.clone()));

let mut bytes = blob_buf.bytes;
loop {
match receiver.recv().unwrap() {
Ok(ReadFileProgress::Partial(ref mut new_bytes)) => {
bytes.append(new_bytes);
}
Ok(ReadFileProgress::EOF) => {
return Ok((headers, bytes));
}
Ok(_) => {
return Err(NetworkError::Internal("Invalid filemanager reply".to_string()));
}
Err(e) => {
return Err(NetworkError::Internal(format!("{:?}", e)));
}
}
}
}
25 changes: 24 additions & 1 deletion components/net/fetch/methods.rs
Expand Up @@ -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 blob_loader::load_blob_sync;
use connector::create_http_connector;
use data_loader::decode;
use devtools_traits::DevtoolsControlMsg;
Expand Down Expand Up @@ -464,7 +465,29 @@ fn basic_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
}
},

"blob" | "ftp" => {
"blob" => {
println!("Loading blob {}", url.as_str());
// Step 2.
if *request.method.borrow() != Method::Get {
return Response::network_error();
}

match load_blob_sync(url.clone(), context.filemanager.clone()) {
Ok((headers, bytes)) => {
let mut response = Response::new();
response.url = Some(url.clone());
response.headers = headers;
*response.body.lock().unwrap() = ResponseBody::Done(bytes);
response
},
Err(e) => {
debug!("Failed to load {}: {:?}", url, e);
Response::network_error()
},
}
},

"ftp" => {
// XXXManishearth handle these
panic!("Unimplemented scheme for Fetch")
},
Expand Down
42 changes: 42 additions & 0 deletions tests/unit/net/fetch.rs
Expand Up @@ -167,6 +167,48 @@ fn test_fetch_data() {
}
}

#[test]
fn test_fetch_blob() {
use ipc_channel::ipc;
use net_traits::blob_url_store::BlobBuf;
use net_traits::filemanager_thread::FileManagerThreadMsg;

let context = new_fetch_context(None);

let bytes = b"content";
let blob_buf = BlobBuf {
filename: Some("test.txt".into()),
type_string: "text/plain".into(),
size: bytes.len() as u64,
bytes: bytes.to_vec(),
};

let origin = Url::parse("http://www.example.org/").unwrap();

let (sender, receiver) = ipc::channel().unwrap();
let message = FileManagerThreadMsg::PromoteMemory(blob_buf, true, sender, "http://www.example.org".into());
context.filemanager.handle(message, None);
let id = receiver.recv().unwrap().unwrap();
let url = Url::parse(&format!("blob:{}{}", origin.as_str(), id.simple())).unwrap();


let request = Request::new(url, Some(Origin::Origin(origin.origin())), false, None);
let fetch_response = fetch(Rc::new(request), &mut None, context);

assert!(!fetch_response.is_network_error());

assert_eq!(fetch_response.headers.len(), 2);

let content_type: &ContentType = fetch_response.headers.get().unwrap();
assert_eq!(**content_type, Mime(TopLevel::Text, SubLevel::Plain, vec![]));

let content_length: &ContentLength = fetch_response.headers.get().unwrap();
assert_eq!(**content_length, bytes.len() as u64);

assert_eq!(*fetch_response.body.lock().unwrap(),
ResponseBody::Done(bytes.to_vec()));
}

#[test]
fn test_fetch_file() {
let mut path = resources_dir_path().expect("Cannot find resource dir");
Expand Down
4 changes: 3 additions & 1 deletion tests/wpt/metadata/FileAPI/blob/Blob-XHR-revoke.html.ini
@@ -1,4 +1,6 @@
[Blob-XHR-revoke.html]
type: testharness
expected: CRASH
bug: https://github.com/servo/servo/issues/10539
[Revoking blob URL used with XMLHttpRequest]
expected: FAIL

@@ -1,3 +1,6 @@
[scheme-blob-worker.html]
type: testharness
expected: CRASH
[Fetching [GET\] URL.createObjectURL(blob) is OK]
bug: https://github.com/servo/servo/issues/13766
expected: FAIL

5 changes: 4 additions & 1 deletion tests/wpt/metadata/fetch/api/basic/scheme-blob.html.ini
@@ -1,3 +1,6 @@
[scheme-blob.html]
type: testharness
expected: CRASH
[Fetching [GET\] URL.createObjectURL(blob) is OK]
bug: https://github.com/servo/servo/issues/13766
expected: FAIL

0 comments on commit e134871

Please sign in to comment.