mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Auto merge of #13750 - servo:fetch-blob, r=Manishearth
Implement blob url support in the fetch stack. <!-- Reviewable:start --> This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/13750) <!-- Reviewable:end -->
This commit is contained in:
commit
d692cf1085
11 changed files with 237 additions and 64 deletions
|
@ -18,12 +18,13 @@ 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
|
||||
// https://w3c.github.io/FileAPI/#requestResponseModel
|
||||
|
||||
pub fn factory<UI: 'static + UIProvider>(filemanager: Arc<FileManager<UI>>)
|
||||
pub fn factory<UI: 'static + UIProvider>(filemanager: FileManager<UI>)
|
||||
-> Box<FnBox(LoadData, LoadConsumer, Arc<MimeClassifier>, CancellationListener) + Send> {
|
||||
box move |load_data: LoadData, start_chan, classifier, cancel_listener| {
|
||||
spawn_named(format!("blob loader for {}", load_data.url), move || {
|
||||
|
@ -35,7 +36,7 @@ pub fn factory<UI: 'static + UIProvider>(filemanager: Arc<FileManager<UI>>)
|
|||
fn load_blob<UI: 'static + UIProvider>
|
||||
(load_data: LoadData, start_chan: LoadConsumer,
|
||||
classifier: Arc<MimeClassifier>,
|
||||
filemanager: Arc<FileManager<UI>>,
|
||||
filemanager: FileManager<UI>,
|
||||
cancel_listener: CancellationListener) {
|
||||
let (chan, recv) = ipc::channel().unwrap();
|
||||
if let Ok((id, origin, _fragment)) = parse_blob_url(&load_data.url.clone()) {
|
||||
|
@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
* 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;
|
||||
use fetch::cors_cache::CORSCache;
|
||||
use filemanager_thread::{FileManager, UIProvider};
|
||||
use http_loader::{HttpState, set_default_accept_encoding, set_request_cookies};
|
||||
use http_loader::{NetworkHttpRequestFactory, ReadResult, StreamedResponse, obtain_response, read_block};
|
||||
use http_loader::{auth_from_cache, determine_request_referrer};
|
||||
|
@ -50,23 +52,28 @@ enum Data {
|
|||
Done,
|
||||
}
|
||||
|
||||
pub struct FetchContext {
|
||||
pub struct FetchContext<UI: 'static + UIProvider> {
|
||||
pub state: HttpState,
|
||||
pub user_agent: Cow<'static, str>,
|
||||
pub devtools_chan: Option<Sender<DevtoolsControlMsg>>,
|
||||
pub filemanager: FileManager<UI>,
|
||||
}
|
||||
|
||||
type DoneChannel = Option<(Sender<Data>, Receiver<Data>)>;
|
||||
|
||||
/// [Fetch](https://fetch.spec.whatwg.org#concept-fetch)
|
||||
pub fn fetch(request: Rc<Request>, target: &mut Target, context: FetchContext) -> Response {
|
||||
pub fn fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||
target: &mut Target,
|
||||
context: FetchContext<UI>)
|
||||
-> Response {
|
||||
fetch_with_cors_cache(request, &mut CORSCache::new(), target, context)
|
||||
}
|
||||
|
||||
pub fn fetch_with_cors_cache(request: Rc<Request>,
|
||||
cache: &mut CORSCache,
|
||||
target: &mut Target,
|
||||
context: FetchContext) -> Response {
|
||||
pub fn fetch_with_cors_cache<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||
cache: &mut CORSCache,
|
||||
target: &mut Target,
|
||||
context: FetchContext<UI>)
|
||||
-> Response {
|
||||
// Step 1
|
||||
if request.window.get() == Window::Client {
|
||||
// TODO: Set window to request's client object if client is a Window object
|
||||
|
@ -131,9 +138,14 @@ pub fn fetch_with_cors_cache(request: Rc<Request>,
|
|||
}
|
||||
|
||||
/// [Main fetch](https://fetch.spec.whatwg.org/#concept-main-fetch)
|
||||
fn main_fetch(request: Rc<Request>, cache: &mut CORSCache, cors_flag: bool,
|
||||
recursive_flag: bool, target: &mut Target, done_chan: &mut DoneChannel,
|
||||
context: &FetchContext) -> Response {
|
||||
fn main_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||
cache: &mut CORSCache,
|
||||
cors_flag: bool,
|
||||
recursive_flag: bool,
|
||||
target: &mut Target,
|
||||
done_chan: &mut DoneChannel,
|
||||
context: &FetchContext<UI>)
|
||||
-> Response {
|
||||
// TODO: Implement main fetch spec
|
||||
|
||||
// Step 1
|
||||
|
@ -389,9 +401,12 @@ fn main_fetch(request: Rc<Request>, cache: &mut CORSCache, cors_flag: bool,
|
|||
}
|
||||
|
||||
/// [Basic fetch](https://fetch.spec.whatwg.org#basic-fetch)
|
||||
fn basic_fetch(request: Rc<Request>, cache: &mut CORSCache,
|
||||
target: &mut Target, done_chan: &mut DoneChannel,
|
||||
context: &FetchContext) -> Response {
|
||||
fn basic_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||
cache: &mut CORSCache,
|
||||
target: &mut Target,
|
||||
done_chan: &mut DoneChannel,
|
||||
context: &FetchContext<UI>)
|
||||
-> Response {
|
||||
let url = request.current_url();
|
||||
|
||||
match url.scheme() {
|
||||
|
@ -450,7 +465,29 @@ fn basic_fetch(request: Rc<Request>, cache: &mut CORSCache,
|
|||
}
|
||||
},
|
||||
|
||||
"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")
|
||||
},
|
||||
|
@ -460,14 +497,15 @@ fn basic_fetch(request: Rc<Request>, cache: &mut CORSCache,
|
|||
}
|
||||
|
||||
/// [HTTP fetch](https://fetch.spec.whatwg.org#http-fetch)
|
||||
fn http_fetch(request: Rc<Request>,
|
||||
cache: &mut CORSCache,
|
||||
cors_flag: bool,
|
||||
cors_preflight_flag: bool,
|
||||
authentication_fetch_flag: bool,
|
||||
target: &mut Target,
|
||||
done_chan: &mut DoneChannel,
|
||||
context: &FetchContext) -> Response {
|
||||
fn http_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||
cache: &mut CORSCache,
|
||||
cors_flag: bool,
|
||||
cors_preflight_flag: bool,
|
||||
authentication_fetch_flag: bool,
|
||||
target: &mut Target,
|
||||
done_chan: &mut DoneChannel,
|
||||
context: &FetchContext<UI>)
|
||||
-> Response {
|
||||
// This is a new async fetch, reset the channel we are waiting on
|
||||
*done_chan = None;
|
||||
// Step 1
|
||||
|
@ -631,13 +669,14 @@ fn http_fetch(request: Rc<Request>,
|
|||
}
|
||||
|
||||
/// [HTTP redirect fetch](https://fetch.spec.whatwg.org#http-redirect-fetch)
|
||||
fn http_redirect_fetch(request: Rc<Request>,
|
||||
cache: &mut CORSCache,
|
||||
response: Rc<Response>,
|
||||
cors_flag: bool,
|
||||
target: &mut Target,
|
||||
done_chan: &mut DoneChannel,
|
||||
context: &FetchContext) -> Response {
|
||||
fn http_redirect_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||
cache: &mut CORSCache,
|
||||
response: Rc<Response>,
|
||||
cors_flag: bool,
|
||||
target: &mut Target,
|
||||
done_chan: &mut DoneChannel,
|
||||
context: &FetchContext<UI>)
|
||||
-> Response {
|
||||
// Step 1
|
||||
assert_eq!(response.return_internal.get(), true);
|
||||
|
||||
|
@ -711,11 +750,12 @@ fn http_redirect_fetch(request: Rc<Request>,
|
|||
}
|
||||
|
||||
/// [HTTP network or cache fetch](https://fetch.spec.whatwg.org#http-network-or-cache-fetch)
|
||||
fn http_network_or_cache_fetch(request: Rc<Request>,
|
||||
credentials_flag: bool,
|
||||
authentication_fetch_flag: bool,
|
||||
done_chan: &mut DoneChannel,
|
||||
context: &FetchContext) -> Response {
|
||||
fn http_network_or_cache_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||
credentials_flag: bool,
|
||||
authentication_fetch_flag: bool,
|
||||
done_chan: &mut DoneChannel,
|
||||
context: &FetchContext<UI>)
|
||||
-> Response {
|
||||
// TODO: Implement Window enum for Request
|
||||
let request_has_no_window = true;
|
||||
|
||||
|
@ -1108,8 +1148,10 @@ fn http_network_fetch(request: Rc<Request>,
|
|||
}
|
||||
|
||||
/// [CORS preflight fetch](https://fetch.spec.whatwg.org#cors-preflight-fetch)
|
||||
fn cors_preflight_fetch(request: Rc<Request>, cache: &mut CORSCache,
|
||||
context: &FetchContext) -> Response {
|
||||
fn cors_preflight_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||
cache: &mut CORSCache,
|
||||
context: &FetchContext<UI>)
|
||||
-> Response {
|
||||
// Step 1
|
||||
let mut preflight = Request::new(request.current_url(), Some(request.origin.borrow().clone()),
|
||||
request.is_service_worker_global_scope, request.pipeline_id.get());
|
||||
|
|
|
@ -116,6 +116,15 @@ pub struct FileManager<UI: 'static + UIProvider> {
|
|||
store: Arc<FileManagerStore<UI>>,
|
||||
}
|
||||
|
||||
// Not derived to avoid an unnecessary `UI: Clone` bound.
|
||||
impl<UI: 'static + UIProvider> Clone for FileManager<UI> {
|
||||
fn clone(&self) -> Self {
|
||||
FileManager {
|
||||
store: self.store.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<UI: 'static + UIProvider> FileManager<UI> {
|
||||
pub fn new(ui: &'static UI) -> FileManager<UI> {
|
||||
FileManager {
|
||||
|
@ -139,7 +148,7 @@ impl<UI: 'static + UIProvider> FileManager<UI> {
|
|||
}
|
||||
FileManagerThreadMsg::ReadFile(sender, id, check_url_validity, origin) => {
|
||||
spawn_named("read file".to_owned(), move || {
|
||||
if let Err(e) = store.try_read_file(sender.clone(), id, check_url_validity,
|
||||
if let Err(e) = store.try_read_file(&sender, id, check_url_validity,
|
||||
origin, cancel_listener) {
|
||||
let _ = sender.send(Err(FileManagerThreadError::BlobURLStoreError(e)));
|
||||
}
|
||||
|
@ -151,24 +160,16 @@ impl<UI: 'static + UIProvider> FileManager<UI> {
|
|||
})
|
||||
}
|
||||
FileManagerThreadMsg::AddSlicedURLEntry(id, rel_pos, sender, origin) =>{
|
||||
spawn_named("add sliced URL entry".to_owned(), move || {
|
||||
store.add_sliced_url_entry(id, rel_pos, sender, origin);
|
||||
})
|
||||
store.add_sliced_url_entry(id, rel_pos, sender, origin);
|
||||
}
|
||||
FileManagerThreadMsg::DecRef(id, origin, sender) => {
|
||||
spawn_named("dec ref".to_owned(), move || {
|
||||
let _ = sender.send(store.dec_ref(&id, &origin));
|
||||
})
|
||||
let _ = sender.send(store.dec_ref(&id, &origin));
|
||||
}
|
||||
FileManagerThreadMsg::RevokeBlobURL(id, origin, sender) => {
|
||||
spawn_named("revoke blob url".to_owned(), move || {
|
||||
let _ = sender.send(store.set_blob_url_validity(false, &id, &origin));
|
||||
})
|
||||
let _ = sender.send(store.set_blob_url_validity(false, &id, &origin));
|
||||
}
|
||||
FileManagerThreadMsg::ActivateBlobURL(id, sender, origin) => {
|
||||
spawn_named("activate blob url".to_owned(), move || {
|
||||
let _ = sender.send(store.set_blob_url_validity(true, &id, &origin));
|
||||
});
|
||||
let _ = sender.send(store.set_blob_url_validity(true, &id, &origin));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -365,7 +366,7 @@ impl <UI: 'static + UIProvider> FileManagerStore<UI> {
|
|||
})
|
||||
}
|
||||
|
||||
fn get_blob_buf(&self, sender: IpcSender<FileManagerResult<ReadFileProgress>>,
|
||||
fn get_blob_buf(&self, sender: &IpcSender<FileManagerResult<ReadFileProgress>>,
|
||||
id: &Uuid, origin_in: &FileOrigin, rel_pos: RelativePos,
|
||||
check_url_validity: bool,
|
||||
cancel_listener: Option<CancellationListener>) -> Result<(), BlobURLStoreError> {
|
||||
|
@ -428,7 +429,7 @@ impl <UI: 'static + UIProvider> FileManagerStore<UI> {
|
|||
}
|
||||
|
||||
// Convenient wrapper over get_blob_buf
|
||||
fn try_read_file(&self, sender: IpcSender<FileManagerResult<ReadFileProgress>>,
|
||||
fn try_read_file(&self, sender: &IpcSender<FileManagerResult<ReadFileProgress>>,
|
||||
id: Uuid, check_url_validity: bool, origin_in: FileOrigin,
|
||||
cancel_listener: Option<CancellationListener>) -> Result<(), BlobURLStoreError> {
|
||||
self.get_blob_buf(sender, &id, &origin_in, RelativePos::full_range(), check_url_validity, cancel_listener)
|
||||
|
@ -541,7 +542,7 @@ fn select_files_pref_enabled() -> bool {
|
|||
|
||||
const CHUNK_SIZE: usize = 8192;
|
||||
|
||||
fn chunked_read(sender: IpcSender<FileManagerResult<ReadFileProgress>>,
|
||||
fn chunked_read(sender: &IpcSender<FileManagerResult<ReadFileProgress>>,
|
||||
file: &mut File, size: usize, opt_filename: Option<String>,
|
||||
type_string: String, cancel_listener: Option<CancellationListener>) {
|
||||
// First chunk
|
||||
|
|
|
@ -475,7 +475,7 @@ pub struct CoreResourceManager {
|
|||
devtools_chan: Option<Sender<DevtoolsControlMsg>>,
|
||||
swmanager_chan: Option<IpcSender<CustomResponseMediator>>,
|
||||
profiler_chan: ProfilerChan,
|
||||
filemanager: Arc<FileManager<TFDProvider>>,
|
||||
filemanager: FileManager<TFDProvider>,
|
||||
cancel_load_map: HashMap<ResourceId, Sender<()>>,
|
||||
next_resource_id: ResourceId,
|
||||
}
|
||||
|
@ -490,7 +490,7 @@ impl CoreResourceManager {
|
|||
devtools_chan: devtools_channel,
|
||||
swmanager_chan: None,
|
||||
profiler_chan: profiler_chan,
|
||||
filemanager: Arc::new(FileManager::new(TFD_PROVIDER)),
|
||||
filemanager: FileManager::new(TFD_PROVIDER),
|
||||
cancel_load_map: HashMap::new(),
|
||||
next_resource_id: ResourceId(0),
|
||||
}
|
||||
|
@ -592,6 +592,7 @@ impl CoreResourceManager {
|
|||
};
|
||||
let ua = self.user_agent.clone();
|
||||
let dc = self.devtools_chan.clone();
|
||||
let filemanager = self.filemanager.clone();
|
||||
spawn_named(format!("fetch thread for {}", init.url), move || {
|
||||
let request = Request::from_init(init);
|
||||
// XXXManishearth: Check origin against pipeline id (also ensure that the mode is allowed)
|
||||
|
@ -599,7 +600,12 @@ impl CoreResourceManager {
|
|||
// todo referrer policy?
|
||||
// todo service worker stuff
|
||||
let mut target = Some(Box::new(sender) as Box<FetchTaskTarget + Send + 'static>);
|
||||
let context = FetchContext { state: http_state, user_agent: ua, devtools_chan: dc };
|
||||
let context = FetchContext {
|
||||
state: http_state,
|
||||
user_agent: ua,
|
||||
devtools_chan: dc,
|
||||
filemanager: filemanager,
|
||||
};
|
||||
fetch(Rc::new(request), &mut target, context);
|
||||
})
|
||||
}
|
||||
|
|
|
@ -366,7 +366,7 @@ impl XMLHttpRequestMethods for XMLHttpRequest {
|
|||
// Step 11 - abort existing requests
|
||||
self.terminate_ongoing_fetch();
|
||||
|
||||
// TODO(izgzhen): In the WPT test: FileAPI/blob/Blob-XHR-revoke.html,
|
||||
// FIXME(#13767): In the WPT test: FileAPI/blob/Blob-XHR-revoke.html,
|
||||
// the xhr.open(url) is expected to hold a reference to the URL,
|
||||
// thus renders following revocations invalid. Though we won't
|
||||
// implement this for now, if ever needed, we should check blob
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
use devtools_traits::DevtoolsControlMsg;
|
||||
use devtools_traits::HttpRequest as DevtoolsHttpRequest;
|
||||
use devtools_traits::HttpResponse as DevtoolsHttpResponse;
|
||||
use filemanager_thread::{TestProvider, TEST_PROVIDER};
|
||||
use http_loader::{expect_devtools_http_request, expect_devtools_http_response};
|
||||
use hyper::LanguageTag;
|
||||
use hyper::header::{Accept, AccessControlAllowCredentials, AccessControlAllowHeaders, AccessControlAllowOrigin};
|
||||
|
@ -22,6 +23,7 @@ use hyper::uri::RequestUri;
|
|||
use msg::constellation_msg::{ReferrerPolicy, TEST_PIPELINE_ID};
|
||||
use net::fetch::cors_cache::CORSCache;
|
||||
use net::fetch::methods::{FetchContext, fetch, fetch_with_cors_cache};
|
||||
use net::filemanager_thread::FileManager;
|
||||
use net::http_loader::HttpState;
|
||||
use net_traits::FetchTaskTarget;
|
||||
use net_traits::request::{Origin, RedirectMode, Referrer, Request, RequestMode};
|
||||
|
@ -46,11 +48,12 @@ struct FetchResponseCollector {
|
|||
sender: Sender<Response>,
|
||||
}
|
||||
|
||||
fn new_fetch_context(dc: Option<Sender<DevtoolsControlMsg>>) -> FetchContext {
|
||||
fn new_fetch_context(dc: Option<Sender<DevtoolsControlMsg>>) -> FetchContext<TestProvider> {
|
||||
FetchContext {
|
||||
state: HttpState::new(),
|
||||
user_agent: DEFAULT_USER_AGENT.into(),
|
||||
devtools_chan: dc,
|
||||
filemanager: FileManager::new(TEST_PROVIDER),
|
||||
}
|
||||
}
|
||||
impl FetchTaskTarget for FetchResponseCollector {
|
||||
|
@ -164,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");
|
||||
|
|
|
@ -10,9 +10,9 @@ use std::fs::File;
|
|||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
|
||||
const TEST_PROVIDER: &'static TestProvider = &TestProvider;
|
||||
pub const TEST_PROVIDER: &'static TestProvider = &TestProvider;
|
||||
|
||||
struct TestProvider;
|
||||
pub struct TestProvider;
|
||||
|
||||
impl UIProvider for TestProvider {
|
||||
fn open_file_dialog(&self, _path: &str, _patterns: Vec<FilterPattern>) -> Option<String> {
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
[Blob-XHR-revoke.html]
|
||||
type: testharness
|
||||
expected: CRASH
|
||||
bug: https://github.com/servo/servo/issues/10539
|
||||
bug: https://github.com/servo/servo/issues/13767
|
||||
[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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
[uniformOutOfBounds.html]
|
||||
type: testharness
|
||||
disabled: https://github.com/servo/servo/issues/13662
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue