Skip to content

Commit 699287e

Browse files
committed
Implement blob url support in the fetch stack.
1 parent 7e6162a commit 699287e

File tree

3 files changed

+135
-1
lines changed

3 files changed

+135
-1
lines changed

components/net/blob_loader.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use resource_thread::{send_error, start_sending_sniffed_opt};
1818
use resource_thread::CancellationListener;
1919
use std::boxed::FnBox;
2020
use std::sync::Arc;
21+
use url::Url;
2122
use util::thread::spawn_named;
2223

2324
// TODO: Check on GET
@@ -119,3 +120,71 @@ fn load_blob<UI: 'static + UIProvider>
119120
send_error(load_data.url.clone(), format_err, start_chan);
120121
}
121122
}
123+
124+
// TODO: make async.
125+
pub fn load_blob_sync<UI: 'static + UIProvider>
126+
(url: Url,
127+
filemanager: FileManager<UI>)
128+
-> Result<(Headers, Vec<u8>), NetworkError> {
129+
let (id, origin) = match parse_blob_url(&url) {
130+
Ok((id, origin, _fragment)) => (id, origin),
131+
Err(()) => {
132+
let e = format!("Invalid blob URL format {:?}", url);
133+
return Err(NetworkError::Internal(e));
134+
}
135+
};
136+
137+
let (sender, receiver) = ipc::channel().unwrap();
138+
let check_url_validity = true;
139+
let msg = FileManagerThreadMsg::ReadFile(sender, id, check_url_validity, origin);
140+
let _ = filemanager.handle(msg, None);
141+
142+
let blob_buf = match receiver.recv().unwrap() {
143+
Ok(ReadFileProgress::Meta(blob_buf)) => blob_buf,
144+
Ok(_) => {
145+
return Err(NetworkError::Internal("Invalid filemanager reply".to_string()));
146+
}
147+
Err(e) => {
148+
return Err(NetworkError::Internal(format!("{:?}", e)));
149+
}
150+
};
151+
152+
let content_type: Mime = blob_buf.type_string.parse().unwrap_or(mime!(Text / Plain));
153+
let charset = content_type.get_param(Attr::Charset);
154+
155+
let mut headers = Headers::new();
156+
157+
if let Some(name) = blob_buf.filename {
158+
let charset = charset.and_then(|c| c.as_str().parse().ok());
159+
headers.set(ContentDisposition {
160+
disposition: DispositionType::Inline,
161+
parameters: vec![
162+
DispositionParam::Filename(charset.unwrap_or(Charset::Us_Ascii),
163+
None, name.as_bytes().to_vec())
164+
]
165+
});
166+
}
167+
168+
// Basic fetch, Step 4.
169+
headers.set(ContentLength(blob_buf.size as u64));
170+
// Basic fetch, Step 5.
171+
headers.set(ContentType(content_type.clone()));
172+
173+
let mut bytes = blob_buf.bytes;
174+
loop {
175+
match receiver.recv().unwrap() {
176+
Ok(ReadFileProgress::Partial(ref mut new_bytes)) => {
177+
bytes.append(new_bytes);
178+
}
179+
Ok(ReadFileProgress::EOF) => {
180+
return Ok((headers, bytes));
181+
}
182+
Ok(_) => {
183+
return Err(NetworkError::Internal("Invalid filemanager reply".to_string()));
184+
}
185+
Err(e) => {
186+
return Err(NetworkError::Internal(format!("{:?}", e)));
187+
}
188+
}
189+
}
190+
}

components/net/fetch/methods.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5+
use blob_loader::load_blob_sync;
56
use connector::create_http_connector;
67
use data_loader::decode;
78
use devtools_traits::DevtoolsControlMsg;
@@ -464,7 +465,29 @@ fn basic_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
464465
}
465466
},
466467

467-
"blob" | "ftp" => {
468+
"blob" => {
469+
println!("Loading blob {}", url.as_str());
470+
// Step 2.
471+
if *request.method.borrow() != Method::Get {
472+
return Response::network_error();
473+
}
474+
475+
match load_blob_sync(url.clone(), context.filemanager.clone()) {
476+
Ok((headers, bytes)) => {
477+
let mut response = Response::new();
478+
response.url = Some(url.clone());
479+
response.headers = headers;
480+
*response.body.lock().unwrap() = ResponseBody::Done(bytes);
481+
response
482+
},
483+
Err(e) => {
484+
debug!("Failed to load {}: {:?}", url, e);
485+
Response::network_error()
486+
},
487+
}
488+
},
489+
490+
"ftp" => {
468491
// XXXManishearth handle these
469492
panic!("Unimplemented scheme for Fetch")
470493
},

tests/unit/net/fetch.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,48 @@ fn test_fetch_data() {
167167
}
168168
}
169169

170+
#[test]
171+
fn test_fetch_blob() {
172+
use ipc_channel::ipc;
173+
use net_traits::blob_url_store::BlobBuf;
174+
use net_traits::filemanager_thread::FileManagerThreadMsg;
175+
176+
let context = new_fetch_context(None);
177+
178+
let bytes = b"content";
179+
let blob_buf = BlobBuf {
180+
filename: Some("test.txt".into()),
181+
type_string: "text/plain".into(),
182+
size: bytes.len() as u64,
183+
bytes: bytes.to_vec(),
184+
};
185+
186+
let origin = Url::parse("http://www.example.org/").unwrap();
187+
188+
let (sender, receiver) = ipc::channel().unwrap();
189+
let message = FileManagerThreadMsg::PromoteMemory(blob_buf, true, sender, "http://www.example.org".into());
190+
context.filemanager.handle(message, None);
191+
let id = receiver.recv().unwrap().unwrap();
192+
let url = Url::parse(&format!("blob:{}{}", origin.as_str(), id.simple())).unwrap();
193+
194+
195+
let request = Request::new(url, Some(Origin::Origin(origin.origin())), false, None);
196+
let fetch_response = fetch(Rc::new(request), &mut None, context);
197+
198+
assert!(!fetch_response.is_network_error());
199+
200+
assert_eq!(fetch_response.headers.len(), 2);
201+
202+
let content_type: &ContentType = fetch_response.headers.get().unwrap();
203+
assert_eq!(**content_type, Mime(TopLevel::Text, SubLevel::Plain, vec![]));
204+
205+
let content_length: &ContentLength = fetch_response.headers.get().unwrap();
206+
assert_eq!(**content_length, bytes.len() as u64);
207+
208+
assert_eq!(*fetch_response.body.lock().unwrap(),
209+
ResponseBody::Done(bytes.to_vec()));
210+
}
211+
170212
#[test]
171213
fn test_fetch_file() {
172214
let mut path = resources_dir_path().expect("Cannot find resource dir");

0 commit comments

Comments
 (0)