mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Auto merge of #13742 - servo:fetch-documents, r=jdm
Use the fetch stack for documents. <!-- 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/13742) <!-- Reviewable:end -->
This commit is contained in:
commit
ba2fb4e2e2
10 changed files with 156 additions and 143 deletions
|
@ -10,8 +10,8 @@ use fetch::cors_cache::CORSCache;
|
||||||
use filemanager_thread::{FileManager, UIProvider};
|
use filemanager_thread::{FileManager, UIProvider};
|
||||||
use http_loader::{HttpState, set_default_accept_encoding, set_request_cookies};
|
use http_loader::{HttpState, set_default_accept_encoding, set_request_cookies};
|
||||||
use http_loader::{NetworkHttpRequestFactory, ReadResult, StreamedResponse, obtain_response, read_block};
|
use http_loader::{NetworkHttpRequestFactory, ReadResult, StreamedResponse, obtain_response, read_block};
|
||||||
use http_loader::{auth_from_cache, determine_request_referrer};
|
use http_loader::{auth_from_cache, determine_request_referrer, set_cookies_from_headers};
|
||||||
use http_loader::{send_response_to_devtools, send_request_to_devtools};
|
use http_loader::{send_response_to_devtools, send_request_to_devtools, LoadErrorType};
|
||||||
use hyper::header::{Accept, AcceptLanguage, Authorization, AccessControlAllowCredentials};
|
use hyper::header::{Accept, AcceptLanguage, Authorization, AccessControlAllowCredentials};
|
||||||
use hyper::header::{AccessControlAllowOrigin, AccessControlAllowHeaders, AccessControlAllowMethods};
|
use hyper::header::{AccessControlAllowOrigin, AccessControlAllowHeaders, AccessControlAllowMethods};
|
||||||
use hyper::header::{AccessControlRequestHeaders, AccessControlMaxAge, AccessControlRequestMethod, Basic};
|
use hyper::header::{AccessControlRequestHeaders, AccessControlMaxAge, AccessControlRequestMethod, Basic};
|
||||||
|
@ -24,15 +24,15 @@ use hyper::status::StatusCode;
|
||||||
use hyper_serde::Serde;
|
use hyper_serde::Serde;
|
||||||
use mime_guess::guess_mime_type;
|
use mime_guess::guess_mime_type;
|
||||||
use msg::constellation_msg::ReferrerPolicy;
|
use msg::constellation_msg::ReferrerPolicy;
|
||||||
use net_traits::{FetchTaskTarget, FetchMetadata};
|
use net_traits::{FetchTaskTarget, FetchMetadata, NetworkError};
|
||||||
use net_traits::request::{CacheMode, CredentialsMode, Destination};
|
use net_traits::request::{CacheMode, CredentialsMode, Destination};
|
||||||
use net_traits::request::{RedirectMode, Referrer, Request, RequestMode, ResponseTainting};
|
use net_traits::request::{RedirectMode, Referrer, Request, RequestMode, ResponseTainting};
|
||||||
use net_traits::request::{Type, Origin, Window};
|
use net_traits::request::{Type, Origin, Window};
|
||||||
use net_traits::response::{HttpsState, TerminationReason};
|
use net_traits::response::{HttpsState, Response, ResponseBody, ResponseType};
|
||||||
use net_traits::response::{Response, ResponseBody, ResponseType};
|
|
||||||
use resource_thread::CancellationListener;
|
use resource_thread::CancellationListener;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
use std::error::Error;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
|
@ -155,7 +155,7 @@ fn main_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
if request.local_urls_only {
|
if request.local_urls_only {
|
||||||
match request.current_url().scheme() {
|
match request.current_url().scheme() {
|
||||||
"about" | "blob" | "data" | "filesystem" => (), // Ok, the URL is local.
|
"about" | "blob" | "data" | "filesystem" => (), // Ok, the URL is local.
|
||||||
_ => response = Some(Response::network_error())
|
_ => response = Some(Response::network_error(NetworkError::Internal("Non-local scheme".into())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,14 +214,14 @@ fn main_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
basic_fetch(request.clone(), cache, target, done_chan, context)
|
basic_fetch(request.clone(), cache, target, done_chan, context)
|
||||||
|
|
||||||
} else if request.mode == RequestMode::SameOrigin {
|
} else if request.mode == RequestMode::SameOrigin {
|
||||||
Response::network_error()
|
Response::network_error(NetworkError::Internal("Cross-origin response".into()))
|
||||||
|
|
||||||
} else if request.mode == RequestMode::NoCORS {
|
} else if request.mode == RequestMode::NoCORS {
|
||||||
request.response_tainting.set(ResponseTainting::Opaque);
|
request.response_tainting.set(ResponseTainting::Opaque);
|
||||||
basic_fetch(request.clone(), cache, target, done_chan, context)
|
basic_fetch(request.clone(), cache, target, done_chan, context)
|
||||||
|
|
||||||
} else if !matches!(current_url.scheme(), "http" | "https") {
|
} else if !matches!(current_url.scheme(), "http" | "https") {
|
||||||
Response::network_error()
|
Response::network_error(NetworkError::Internal("Non-http scheme".into()))
|
||||||
|
|
||||||
} else if request.use_cors_preflight ||
|
} else if request.use_cors_preflight ||
|
||||||
(request.unsafe_request &&
|
(request.unsafe_request &&
|
||||||
|
@ -263,8 +263,9 @@ fn main_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
|
|
||||||
{
|
{
|
||||||
// Step 14
|
// Step 14
|
||||||
let network_error_res = Response::network_error();
|
let network_error_res;
|
||||||
let internal_response = if response.is_network_error() {
|
let internal_response = if let Some(error) = response.get_network_error() {
|
||||||
|
network_error_res = Response::network_error(error.clone());
|
||||||
&network_error_res
|
&network_error_res
|
||||||
} else {
|
} else {
|
||||||
response.actual_response()
|
response.actual_response()
|
||||||
|
@ -434,10 +435,10 @@ fn basic_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
response.headers.set(ContentType(mime));
|
response.headers.set(ContentType(mime));
|
||||||
response
|
response
|
||||||
},
|
},
|
||||||
Err(_) => Response::network_error()
|
Err(_) => Response::network_error(NetworkError::Internal("Decoding data URL failed".into()))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Response::network_error()
|
Response::network_error(NetworkError::Internal("Unexpected method for data".into()))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -445,23 +446,26 @@ fn basic_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
if *request.method.borrow() == Method::Get {
|
if *request.method.borrow() == Method::Get {
|
||||||
match url.to_file_path() {
|
match url.to_file_path() {
|
||||||
Ok(file_path) => {
|
Ok(file_path) => {
|
||||||
File::open(file_path.clone()).ok().map_or(Response::network_error(), |mut file| {
|
match File::open(file_path.clone()) {
|
||||||
let mut bytes = vec![];
|
Ok(mut file) => {
|
||||||
let _ = file.read_to_end(&mut bytes);
|
let mut bytes = vec![];
|
||||||
let mime = guess_mime_type(file_path);
|
let _ = file.read_to_end(&mut bytes);
|
||||||
|
let mime = guess_mime_type(file_path);
|
||||||
|
|
||||||
let mut response = Response::new();
|
let mut response = Response::new();
|
||||||
// https://github.com/whatwg/fetch/issues/312
|
// https://github.com/whatwg/fetch/issues/312
|
||||||
response.url = Some(url.clone());
|
response.url = Some(url.clone());
|
||||||
*response.body.lock().unwrap() = ResponseBody::Done(bytes);
|
*response.body.lock().unwrap() = ResponseBody::Done(bytes);
|
||||||
response.headers.set(ContentType(mime));
|
response.headers.set(ContentType(mime));
|
||||||
response
|
response
|
||||||
})
|
},
|
||||||
|
_ => Response::network_error(NetworkError::Internal("Opening file failed".into())),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ => Response::network_error()
|
_ => Response::network_error(NetworkError::Internal("Constructing file path failed".into()))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Response::network_error()
|
Response::network_error(NetworkError::Internal("Unexpected method for file".into()))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -469,7 +473,7 @@ fn basic_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
println!("Loading blob {}", url.as_str());
|
println!("Loading blob {}", url.as_str());
|
||||||
// Step 2.
|
// Step 2.
|
||||||
if *request.method.borrow() != Method::Get {
|
if *request.method.borrow() != Method::Get {
|
||||||
return Response::network_error();
|
return Response::network_error(NetworkError::Internal("Unexpected method for blob".into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
match load_blob_sync(url.clone(), context.filemanager.clone()) {
|
match load_blob_sync(url.clone(), context.filemanager.clone()) {
|
||||||
|
@ -482,7 +486,7 @@ fn basic_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
debug!("Failed to load {}: {:?}", url, e);
|
debug!("Failed to load {}: {:?}", url, e);
|
||||||
Response::network_error()
|
Response::network_error(e)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -492,7 +496,7 @@ fn basic_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
panic!("Unimplemented scheme for Fetch")
|
panic!("Unimplemented scheme for Fetch")
|
||||||
},
|
},
|
||||||
|
|
||||||
_ => Response::network_error()
|
_ => Response::network_error(NetworkError::Internal("Unexpected scheme".into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -530,8 +534,8 @@ fn http_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
request.redirect_mode.get() != RedirectMode::Manual) ||
|
request.redirect_mode.get() != RedirectMode::Manual) ||
|
||||||
(res.url_list.borrow().len() > 1 &&
|
(res.url_list.borrow().len() > 1 &&
|
||||||
request.redirect_mode.get() != RedirectMode::Follow) ||
|
request.redirect_mode.get() != RedirectMode::Follow) ||
|
||||||
res.response_type == ResponseType::Error {
|
res.is_network_error() {
|
||||||
return Response::network_error();
|
return Response::network_error(NetworkError::Internal("Request failed".into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Substep 4
|
// Substep 4
|
||||||
|
@ -563,8 +567,8 @@ fn http_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
if method_mismatch || header_mismatch {
|
if method_mismatch || header_mismatch {
|
||||||
let preflight_result = cors_preflight_fetch(request.clone(), cache, context);
|
let preflight_result = cors_preflight_fetch(request.clone(), cache, context);
|
||||||
// Sub-substep 2
|
// Sub-substep 2
|
||||||
if preflight_result.response_type == ResponseType::Error {
|
if let Some(e) = preflight_result.get_network_error() {
|
||||||
return Response::network_error();
|
return Response::network_error(e.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -578,7 +582,7 @@ fn http_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
|
|
||||||
// Substep 4
|
// Substep 4
|
||||||
if cors_flag && cors_check(request.clone(), &fetch_result).is_err() {
|
if cors_flag && cors_check(request.clone(), &fetch_result).is_err() {
|
||||||
return Response::network_error();
|
return Response::network_error(NetworkError::Internal("CORS check failed".into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch_result.return_internal.set(false);
|
fetch_result.return_internal.set(false);
|
||||||
|
@ -589,12 +593,15 @@ fn http_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
let mut response = response.unwrap();
|
let mut response = response.unwrap();
|
||||||
|
|
||||||
// Step 5
|
// Step 5
|
||||||
match response.actual_response().status.unwrap() {
|
match response.actual_response().status {
|
||||||
// Code 301, 302, 303, 307, 308
|
// Code 301, 302, 303, 307, 308
|
||||||
StatusCode::MovedPermanently | StatusCode::Found | StatusCode::SeeOther |
|
Some(StatusCode::MovedPermanently) |
|
||||||
StatusCode::TemporaryRedirect | StatusCode::PermanentRedirect => {
|
Some(StatusCode::Found) |
|
||||||
|
Some(StatusCode::SeeOther) |
|
||||||
|
Some(StatusCode::TemporaryRedirect) |
|
||||||
|
Some(StatusCode::PermanentRedirect) => {
|
||||||
response = match request.redirect_mode.get() {
|
response = match request.redirect_mode.get() {
|
||||||
RedirectMode::Error => Response::network_error(),
|
RedirectMode::Error => Response::network_error(NetworkError::Internal("Redirect mode error".into())),
|
||||||
RedirectMode::Manual => {
|
RedirectMode::Manual => {
|
||||||
response.to_filtered(ResponseType::OpaqueRedirect)
|
response.to_filtered(ResponseType::OpaqueRedirect)
|
||||||
},
|
},
|
||||||
|
@ -608,7 +615,7 @@ fn http_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Code 401
|
// Code 401
|
||||||
StatusCode::Unauthorized => {
|
Some(StatusCode::Unauthorized) => {
|
||||||
// Step 1
|
// Step 1
|
||||||
// FIXME: Figure out what to do with request window objects
|
// FIXME: Figure out what to do with request window objects
|
||||||
if cors_flag || !credentials {
|
if cors_flag || !credentials {
|
||||||
|
@ -633,7 +640,7 @@ fn http_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Code 407
|
// Code 407
|
||||||
StatusCode::ProxyAuthenticationRequired => {
|
Some(StatusCode::ProxyAuthenticationRequired) => {
|
||||||
// Step 1
|
// Step 1
|
||||||
// TODO: Figure out what to do with request window objects
|
// TODO: Figure out what to do with request window objects
|
||||||
|
|
||||||
|
@ -688,13 +695,13 @@ fn http_redirect_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
// Step 3
|
// Step 3
|
||||||
let location = match response.actual_response().headers.get::<Location>() {
|
let location = match response.actual_response().headers.get::<Location>() {
|
||||||
Some(&Location(ref location)) => location.clone(),
|
Some(&Location(ref location)) => location.clone(),
|
||||||
_ => return Response::network_error()
|
_ => return Response::network_error(NetworkError::Internal("Location header parsing failure".into()))
|
||||||
};
|
};
|
||||||
let response_url = response.actual_response().url.as_ref().unwrap();
|
let response_url = response.actual_response().url.as_ref().unwrap();
|
||||||
let location_url = response_url.join(&*location);
|
let location_url = response_url.join(&*location);
|
||||||
let location_url = match location_url {
|
let location_url = match location_url {
|
||||||
Ok(url) => url,
|
Ok(url) => url,
|
||||||
_ => return Response::network_error()
|
_ => return Response::network_error(NetworkError::Internal("Location URL parsing failure".into()))
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 4
|
// Step 4
|
||||||
|
@ -702,7 +709,7 @@ fn http_redirect_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
|
|
||||||
// Step 5
|
// Step 5
|
||||||
if request.redirect_count.get() >= 20 {
|
if request.redirect_count.get() >= 20 {
|
||||||
return Response::network_error();
|
return Response::network_error(NetworkError::Internal("Too many redirects".into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 6
|
// Step 6
|
||||||
|
@ -717,12 +724,12 @@ fn http_redirect_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
let has_credentials = has_credentials(&location_url);
|
let has_credentials = has_credentials(&location_url);
|
||||||
|
|
||||||
if request.mode == RequestMode::CORSMode && !same_origin && has_credentials {
|
if request.mode == RequestMode::CORSMode && !same_origin && has_credentials {
|
||||||
return Response::network_error();
|
return Response::network_error(NetworkError::Internal("Cross-origin credentials check failed".into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 8
|
// Step 8
|
||||||
if cors_flag && has_credentials {
|
if cors_flag && has_credentials {
|
||||||
return Response::network_error();
|
return Response::network_error(NetworkError::Internal("Credentials check failed".into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 9
|
// Step 9
|
||||||
|
@ -938,7 +945,7 @@ fn http_network_or_cache_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
// Step 18
|
// Step 18
|
||||||
if response.is_none() {
|
if response.is_none() {
|
||||||
response = Some(http_network_fetch(http_request.clone(), credentials_flag,
|
response = Some(http_network_fetch(http_request.clone(), credentials_flag,
|
||||||
done_chan, context.devtools_chan.clone()));
|
done_chan, context));
|
||||||
}
|
}
|
||||||
let response = response.unwrap();
|
let response = response.unwrap();
|
||||||
|
|
||||||
|
@ -972,10 +979,11 @@ fn http_network_or_cache_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [HTTP network fetch](https://fetch.spec.whatwg.org/#http-network-fetch)
|
/// [HTTP network fetch](https://fetch.spec.whatwg.org/#http-network-fetch)
|
||||||
fn http_network_fetch(request: Rc<Request>,
|
fn http_network_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
_credentials_flag: bool,
|
credentials_flag: bool,
|
||||||
done_chan: &mut DoneChannel,
|
done_chan: &mut DoneChannel,
|
||||||
devtools_chan: Option<Sender<DevtoolsControlMsg>>) -> Response {
|
context: &FetchContext<UI>)
|
||||||
|
-> Response {
|
||||||
// TODO: Implement HTTP network fetch spec
|
// TODO: Implement HTTP network fetch spec
|
||||||
|
|
||||||
// Step 1
|
// Step 1
|
||||||
|
@ -995,7 +1003,7 @@ fn http_network_fetch(request: Rc<Request>,
|
||||||
let url = request.current_url();
|
let url = request.current_url();
|
||||||
let cancellation_listener = CancellationListener::new(None);
|
let cancellation_listener = CancellationListener::new(None);
|
||||||
|
|
||||||
let request_id = devtools_chan.as_ref().map(|_| {
|
let request_id = context.devtools_chan.as_ref().map(|_| {
|
||||||
uuid::Uuid::new_v4().simple().to_string()
|
uuid::Uuid::new_v4().simple().to_string()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1017,7 +1025,8 @@ fn http_network_fetch(request: Rc<Request>,
|
||||||
response.status = Some(res.response.status);
|
response.status = Some(res.response.status);
|
||||||
response.raw_status = Some((res.response.status_raw().0,
|
response.raw_status = Some((res.response.status_raw().0,
|
||||||
res.response.status_raw().1.as_bytes().to_vec()));
|
res.response.status_raw().1.as_bytes().to_vec()));
|
||||||
response.headers = res.response.headers.clone();
|
response.headers = res.response.headers.clone();
|
||||||
|
response.referrer = request.referrer.borrow().to_url().cloned();
|
||||||
|
|
||||||
let res_body = response.body.clone();
|
let res_body = response.body.clone();
|
||||||
|
|
||||||
|
@ -1028,7 +1037,7 @@ fn http_network_fetch(request: Rc<Request>,
|
||||||
FetchMetadata::Filtered { unsafe_, .. } => unsafe_
|
FetchMetadata::Filtered { unsafe_, .. } => unsafe_
|
||||||
};
|
};
|
||||||
let done_sender = done_chan.as_ref().map(|ch| ch.0.clone());
|
let done_sender = done_chan.as_ref().map(|ch| ch.0.clone());
|
||||||
let devtools_sender = devtools_chan.clone();
|
let devtools_sender = context.devtools_chan.clone();
|
||||||
let meta_status = meta.status.clone();
|
let meta_status = meta.status.clone();
|
||||||
let meta_headers = meta.headers.clone();
|
let meta_headers = meta.headers.clone();
|
||||||
spawn_named(format!("fetch worker thread"), move || {
|
spawn_named(format!("fetch worker thread"), move || {
|
||||||
|
@ -1091,8 +1100,14 @@ fn http_network_fetch(request: Rc<Request>,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
Err(_) => {
|
Err(error) => {
|
||||||
response.termination_reason = Some(TerminationReason::Fatal);
|
let error = match error.error {
|
||||||
|
LoadErrorType::ConnectionAborted { .. } => unreachable!(),
|
||||||
|
LoadErrorType::Ssl { reason } => NetworkError::SslValidation(error.url, reason),
|
||||||
|
LoadErrorType::Cancelled => NetworkError::LoadCancelled,
|
||||||
|
e => NetworkError::Internal(e.description().to_owned())
|
||||||
|
};
|
||||||
|
return Response::network_error(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1133,8 +1148,13 @@ fn http_network_fetch(request: Rc<Request>,
|
||||||
// TODO this step isn't possible yet
|
// TODO this step isn't possible yet
|
||||||
// Step 13
|
// Step 13
|
||||||
|
|
||||||
|
// Step 14.
|
||||||
|
if credentials_flag {
|
||||||
|
set_cookies_from_headers(&url, &response.headers, &context.state.cookie_jar);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO these steps
|
// TODO these steps
|
||||||
// Step 14
|
// Step 15
|
||||||
// Substep 1
|
// Substep 1
|
||||||
// Substep 2
|
// Substep 2
|
||||||
// Sub-substep 1
|
// Sub-substep 1
|
||||||
|
@ -1143,7 +1163,7 @@ fn http_network_fetch(request: Rc<Request>,
|
||||||
// Sub-substep 4
|
// Sub-substep 4
|
||||||
// Substep 3
|
// Substep 3
|
||||||
|
|
||||||
// Step 15
|
// Step 16
|
||||||
response
|
response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1191,7 +1211,7 @@ fn cors_preflight_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
match response.headers.get::<AccessControlAllowMethods>() {
|
match response.headers.get::<AccessControlAllowMethods>() {
|
||||||
Some(&AccessControlAllowMethods(ref m)) => m.clone(),
|
Some(&AccessControlAllowMethods(ref m)) => m.clone(),
|
||||||
// Substep 3
|
// Substep 3
|
||||||
None => return Response::network_error()
|
None => return Response::network_error(NetworkError::Internal("CORS ACAM check failed".into()))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
|
@ -1202,7 +1222,7 @@ fn cors_preflight_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
match response.headers.get::<AccessControlAllowHeaders>() {
|
match response.headers.get::<AccessControlAllowHeaders>() {
|
||||||
Some(&AccessControlAllowHeaders(ref hn)) => hn.clone(),
|
Some(&AccessControlAllowHeaders(ref hn)) => hn.clone(),
|
||||||
// Substep 3
|
// Substep 3
|
||||||
None => return Response::network_error()
|
None => return Response::network_error(NetworkError::Internal("CORS ACAH check failed".into()))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
|
@ -1218,7 +1238,7 @@ fn cors_preflight_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
methods, request.method.borrow());
|
methods, request.method.borrow());
|
||||||
if methods.iter().all(|method| *method != *request.method.borrow()) &&
|
if methods.iter().all(|method| *method != *request.method.borrow()) &&
|
||||||
!is_simple_method(&*request.method.borrow()) {
|
!is_simple_method(&*request.method.borrow()) {
|
||||||
return Response::network_error();
|
return Response::network_error(NetworkError::Internal("CORS method check failed".into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Substep 6
|
// Substep 6
|
||||||
|
@ -1227,7 +1247,7 @@ fn cors_preflight_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
let set: HashSet<&UniCase<String>> = HashSet::from_iter(header_names.iter());
|
let set: HashSet<&UniCase<String>> = HashSet::from_iter(header_names.iter());
|
||||||
if request.headers.borrow().iter().any(|ref hv| !set.contains(&UniCase(hv.name().to_owned())) &&
|
if request.headers.borrow().iter().any(|ref hv| !set.contains(&UniCase(hv.name().to_owned())) &&
|
||||||
!is_simple_header(hv)) {
|
!is_simple_header(hv)) {
|
||||||
return Response::network_error();
|
return Response::network_error(NetworkError::Internal("CORS headers check failed".into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Substep 7, 8
|
// Substep 7, 8
|
||||||
|
@ -1250,7 +1270,7 @@ fn cors_preflight_fetch<UI: 'static + UIProvider>(request: Rc<Request>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 8
|
// Step 8
|
||||||
Response::network_error()
|
Response::network_error(NetworkError::Internal("CORS check failed".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [CORS check](https://fetch.spec.whatwg.org#concept-cors-check)
|
/// [CORS check](https://fetch.spec.whatwg.org#concept-cors-check)
|
||||||
|
|
|
@ -499,8 +499,8 @@ fn set_cookie_for_url(cookie_jar: &Arc<RwLock<CookieStorage>>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_cookies_from_response(url: &Url, response: &HttpResponse, cookie_jar: &Arc<RwLock<CookieStorage>>) {
|
pub fn set_cookies_from_headers(url: &Url, headers: &Headers, cookie_jar: &Arc<RwLock<CookieStorage>>) {
|
||||||
if let Some(cookies) = response.headers().get_raw("set-cookie") {
|
if let Some(cookies) = headers.get_raw("set-cookie") {
|
||||||
for cookie in cookies.iter() {
|
for cookie in cookies.iter() {
|
||||||
if let Ok(cookie_value) = String::from_utf8(cookie.clone()) {
|
if let Ok(cookie_value) = String::from_utf8(cookie.clone()) {
|
||||||
set_cookie_for_url(&cookie_jar,
|
set_cookie_for_url(&cookie_jar,
|
||||||
|
@ -731,7 +731,7 @@ pub fn process_response_headers(response: &HttpResponse,
|
||||||
|
|
||||||
// https://fetch.spec.whatwg.org/#concept-http-network-fetch step 9
|
// https://fetch.spec.whatwg.org/#concept-http-network-fetch step 9
|
||||||
if load_data.credentials_flag {
|
if load_data.credentials_flag {
|
||||||
set_cookies_from_response(url, response, cookie_jar);
|
set_cookies_from_headers(url, response.headers(), cookie_jar);
|
||||||
}
|
}
|
||||||
update_sts_list_from_response(url, response, hsts_list);
|
update_sts_list_from_response(url, response, hsts_list);
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,18 +262,6 @@ pub trait Action<Listener> {
|
||||||
fn process(self, listener: &mut Listener);
|
fn process(self, listener: &mut Listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A listener for asynchronous network events. Cancelling the underlying request is unsupported.
|
|
||||||
pub trait AsyncResponseListener {
|
|
||||||
/// The response headers for a request have been received.
|
|
||||||
fn headers_available(&mut self, metadata: Result<Metadata, NetworkError>);
|
|
||||||
/// A portion of the response body has been received. This data is unavailable after
|
|
||||||
/// this method returned, and must be stored accordingly.
|
|
||||||
fn data_available(&mut self, payload: Vec<u8>);
|
|
||||||
/// The response is complete. If the provided status is an Err value, there is no guarantee
|
|
||||||
/// that the response body was completely read.
|
|
||||||
fn response_complete(&mut self, status: Result<(), NetworkError>);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Data for passing between threads/processes to indicate a particular action to
|
/// Data for passing between threads/processes to indicate a particular action to
|
||||||
/// take on a provided network listener.
|
/// take on a provided network listener.
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
|
@ -286,17 +274,6 @@ pub enum ResponseAction {
|
||||||
ResponseComplete(Result<(), NetworkError>)
|
ResponseComplete(Result<(), NetworkError>)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: AsyncResponseListener> Action<T> for ResponseAction {
|
|
||||||
/// Execute the default action on a provided listener.
|
|
||||||
fn process(self, listener: &mut T) {
|
|
||||||
match self {
|
|
||||||
ResponseAction::HeadersAvailable(m) => listener.headers_available(m),
|
|
||||||
ResponseAction::DataAvailable(d) => listener.data_available(d),
|
|
||||||
ResponseAction::ResponseComplete(r) => listener.response_complete(r),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: FetchResponseListener> Action<T> for FetchResponseMsg {
|
impl<T: FetchResponseListener> Action<T> for FetchResponseMsg {
|
||||||
/// Execute the default action on a provided listener.
|
/// Execute the default action on a provided listener.
|
||||||
fn process(self, listener: &mut T) {
|
fn process(self, listener: &mut T) {
|
||||||
|
|
|
@ -14,12 +14,12 @@ use std::sync::{Arc, Mutex};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
/// [Response type](https://fetch.spec.whatwg.org/#concept-response-type)
|
/// [Response type](https://fetch.spec.whatwg.org/#concept-response-type)
|
||||||
#[derive(Clone, PartialEq, Copy, Debug, Deserialize, Serialize, HeapSizeOf)]
|
#[derive(Clone, PartialEq, Debug, Deserialize, Serialize, HeapSizeOf)]
|
||||||
pub enum ResponseType {
|
pub enum ResponseType {
|
||||||
Basic,
|
Basic,
|
||||||
CORS,
|
CORS,
|
||||||
Default,
|
Default,
|
||||||
Error,
|
Error(NetworkError),
|
||||||
Opaque,
|
Opaque,
|
||||||
OpaqueRedirect
|
OpaqueRedirect
|
||||||
}
|
}
|
||||||
|
@ -91,6 +91,7 @@ pub struct Response {
|
||||||
pub body: Arc<Mutex<ResponseBody>>,
|
pub body: Arc<Mutex<ResponseBody>>,
|
||||||
pub cache_state: CacheState,
|
pub cache_state: CacheState,
|
||||||
pub https_state: HttpsState,
|
pub https_state: HttpsState,
|
||||||
|
pub referrer: Option<Url>,
|
||||||
/// [Internal response](https://fetch.spec.whatwg.org/#concept-internal-response), only used if the Response
|
/// [Internal response](https://fetch.spec.whatwg.org/#concept-internal-response), only used if the Response
|
||||||
/// is a filtered response
|
/// is a filtered response
|
||||||
pub internal_response: Option<Box<Response>>,
|
pub internal_response: Option<Box<Response>>,
|
||||||
|
@ -111,14 +112,15 @@ impl Response {
|
||||||
body: Arc::new(Mutex::new(ResponseBody::Empty)),
|
body: Arc::new(Mutex::new(ResponseBody::Empty)),
|
||||||
cache_state: CacheState::None,
|
cache_state: CacheState::None,
|
||||||
https_state: HttpsState::None,
|
https_state: HttpsState::None,
|
||||||
|
referrer: None,
|
||||||
internal_response: None,
|
internal_response: None,
|
||||||
return_internal: Cell::new(true)
|
return_internal: Cell::new(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn network_error() -> Response {
|
pub fn network_error(e: NetworkError) -> Response {
|
||||||
Response {
|
Response {
|
||||||
response_type: ResponseType::Error,
|
response_type: ResponseType::Error(e),
|
||||||
termination_reason: None,
|
termination_reason: None,
|
||||||
url: None,
|
url: None,
|
||||||
url_list: RefCell::new(vec![]),
|
url_list: RefCell::new(vec![]),
|
||||||
|
@ -128,6 +130,7 @@ impl Response {
|
||||||
body: Arc::new(Mutex::new(ResponseBody::Empty)),
|
body: Arc::new(Mutex::new(ResponseBody::Empty)),
|
||||||
cache_state: CacheState::None,
|
cache_state: CacheState::None,
|
||||||
https_state: HttpsState::None,
|
https_state: HttpsState::None,
|
||||||
|
referrer: None,
|
||||||
internal_response: None,
|
internal_response: None,
|
||||||
return_internal: Cell::new(true)
|
return_internal: Cell::new(true)
|
||||||
}
|
}
|
||||||
|
@ -135,11 +138,18 @@ impl Response {
|
||||||
|
|
||||||
pub fn is_network_error(&self) -> bool {
|
pub fn is_network_error(&self) -> bool {
|
||||||
match self.response_type {
|
match self.response_type {
|
||||||
ResponseType::Error => true,
|
ResponseType::Error(..) => true,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_network_error(&self) -> Option<&NetworkError> {
|
||||||
|
match self.response_type {
|
||||||
|
ResponseType::Error(ref e) => Some(e),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn actual_response(&self) -> &Response {
|
pub fn actual_response(&self) -> &Response {
|
||||||
if self.return_internal.get() && self.internal_response.is_some() {
|
if self.return_internal.get() && self.internal_response.is_some() {
|
||||||
&**self.internal_response.as_ref().unwrap()
|
&**self.internal_response.as_ref().unwrap()
|
||||||
|
@ -159,13 +169,15 @@ impl Response {
|
||||||
/// Convert to a filtered response, of type `filter_type`.
|
/// Convert to a filtered response, of type `filter_type`.
|
||||||
/// Do not use with type Error or Default
|
/// Do not use with type Error or Default
|
||||||
pub fn to_filtered(self, filter_type: ResponseType) -> Response {
|
pub fn to_filtered(self, filter_type: ResponseType) -> Response {
|
||||||
assert!(filter_type != ResponseType::Error);
|
match filter_type {
|
||||||
assert!(filter_type != ResponseType::Default);
|
ResponseType::Default | ResponseType::Error(..) => panic!(),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
let old_response = self.to_actual();
|
let old_response = self.to_actual();
|
||||||
|
|
||||||
if Response::is_network_error(&old_response) {
|
if let ResponseType::Error(e) = old_response.response_type {
|
||||||
return Response::network_error();
|
return Response::network_error(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
let old_headers = old_response.headers.clone();
|
let old_headers = old_response.headers.clone();
|
||||||
|
@ -173,8 +185,8 @@ impl Response {
|
||||||
response.internal_response = Some(Box::new(old_response));
|
response.internal_response = Some(Box::new(old_response));
|
||||||
response.response_type = filter_type;
|
response.response_type = filter_type;
|
||||||
|
|
||||||
match filter_type {
|
match response.response_type {
|
||||||
ResponseType::Default | ResponseType::Error => unreachable!(),
|
ResponseType::Default | ResponseType::Error(..) => unreachable!(),
|
||||||
|
|
||||||
ResponseType::Basic => {
|
ResponseType::Basic => {
|
||||||
let headers = old_headers.iter().filter(|header| {
|
let headers = old_headers.iter().filter(|header| {
|
||||||
|
@ -235,11 +247,12 @@ impl Response {
|
||||||
metadata.headers = Some(Serde(response.headers.clone()));
|
metadata.headers = Some(Serde(response.headers.clone()));
|
||||||
metadata.status = response.raw_status.clone();
|
metadata.status = response.raw_status.clone();
|
||||||
metadata.https_state = response.https_state;
|
metadata.https_state = response.https_state;
|
||||||
|
metadata.referrer = response.referrer.clone();
|
||||||
metadata
|
metadata
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.is_network_error() {
|
if let Some(error) = self.get_network_error() {
|
||||||
return Err(NetworkError::Internal("Cannot extract metadata from network error".to_owned()));
|
return Err(error.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let metadata = self.url.as_ref().map(|url| init_metadata(self, url));
|
let metadata = self.url.as_ref().map(|url| init_metadata(self, url));
|
||||||
|
|
|
@ -28,7 +28,7 @@ use hyper::mime::{Mime, SubLevel, TopLevel};
|
||||||
use hyper_serde::Serde;
|
use hyper_serde::Serde;
|
||||||
use js::jsapi::JSTracer;
|
use js::jsapi::JSTracer;
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
use net_traits::{AsyncResponseListener, Metadata, NetworkError};
|
use net_traits::{FetchMetadata, FetchResponseListener, Metadata, NetworkError};
|
||||||
use network_listener::PreInvoke;
|
use network_listener::PreInvoke;
|
||||||
use profile_traits::time::{TimerMetadata, TimerMetadataFrameType};
|
use profile_traits::time::{TimerMetadata, TimerMetadataFrameType};
|
||||||
use profile_traits::time::{TimerMetadataReflowType, ProfilerCategory, profile};
|
use profile_traits::time::{TimerMetadataReflowType, ProfilerCategory, profile};
|
||||||
|
@ -332,11 +332,21 @@ impl ParserContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsyncResponseListener for ParserContext {
|
impl FetchResponseListener for ParserContext {
|
||||||
fn headers_available(&mut self, meta_result: Result<Metadata, NetworkError>) {
|
fn process_request_body(&mut self) {}
|
||||||
|
|
||||||
|
fn process_request_eof(&mut self) {}
|
||||||
|
|
||||||
|
fn process_response(&mut self,
|
||||||
|
meta_result: Result<FetchMetadata, NetworkError>) {
|
||||||
let mut ssl_error = None;
|
let mut ssl_error = None;
|
||||||
let metadata = match meta_result {
|
let metadata = match meta_result {
|
||||||
Ok(meta) => Some(meta),
|
Ok(meta) => {
|
||||||
|
Some(match meta {
|
||||||
|
FetchMetadata::Unfiltered(m) => m,
|
||||||
|
FetchMetadata::Filtered { unsafe_, .. } => unsafe_
|
||||||
|
})
|
||||||
|
},
|
||||||
Err(NetworkError::SslValidation(url, reason)) => {
|
Err(NetworkError::SslValidation(url, reason)) => {
|
||||||
ssl_error = Some(reason);
|
ssl_error = Some(reason);
|
||||||
let mut meta = Metadata::default(url);
|
let mut meta = Metadata::default(url);
|
||||||
|
@ -408,7 +418,7 @@ impl AsyncResponseListener for ParserContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn data_available(&mut self, payload: Vec<u8>) {
|
fn process_response_chunk(&mut self, payload: Vec<u8>) {
|
||||||
if !self.is_synthesized_document {
|
if !self.is_synthesized_document {
|
||||||
// FIXME: use Vec<u8> (html5ever #34)
|
// FIXME: use Vec<u8> (html5ever #34)
|
||||||
let data = UTF_8.decode(&payload, DecoderTrap::Replace).unwrap();
|
let data = UTF_8.decode(&payload, DecoderTrap::Replace).unwrap();
|
||||||
|
@ -420,7 +430,7 @@ impl AsyncResponseListener for ParserContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn response_complete(&mut self, status: Result<(), NetworkError>) {
|
fn process_response_eof(&mut self, status: Result<(), NetworkError>) {
|
||||||
let parser = match self.parser.as_ref() {
|
let parser = match self.parser.as_ref() {
|
||||||
Some(parser) => parser.root(),
|
Some(parser) => parser.root(),
|
||||||
None => return,
|
None => return,
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use net_traits::{Action, AsyncResponseListener, FetchResponseListener};
|
use net_traits::{Action, FetchResponseListener, FetchResponseMsg};
|
||||||
use net_traits::{FetchResponseMsg, ResponseAction};
|
|
||||||
use script_runtime::{CommonScriptMsg, ScriptChan};
|
use script_runtime::{CommonScriptMsg, ScriptChan};
|
||||||
use script_runtime::ScriptThreadEventCategory::NetworkEvent;
|
use script_runtime::ScriptThreadEventCategory::NetworkEvent;
|
||||||
use script_thread::{Runnable, RunnableWrapper};
|
use script_thread::{Runnable, RunnableWrapper};
|
||||||
|
@ -34,13 +33,6 @@ impl<Listener: PreInvoke + Send + 'static> NetworkListener<Listener> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// helps type inference
|
|
||||||
impl<Listener: AsyncResponseListener + PreInvoke + Send + 'static> NetworkListener<Listener> {
|
|
||||||
pub fn notify_action(&self, action: ResponseAction) {
|
|
||||||
self.notify(action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// helps type inference
|
// helps type inference
|
||||||
impl<Listener: FetchResponseListener + PreInvoke + Send + 'static> NetworkListener<Listener> {
|
impl<Listener: FetchResponseListener + PreInvoke + Send + 'static> NetworkListener<Listener> {
|
||||||
pub fn notify_fetch(&self, action: FetchResponseMsg) {
|
pub fn notify_fetch(&self, action: FetchResponseMsg) {
|
||||||
|
|
|
@ -57,7 +57,7 @@ use dom::window::{ReflowReason, Window};
|
||||||
use dom::worker::TrustedWorkerAddress;
|
use dom::worker::TrustedWorkerAddress;
|
||||||
use euclid::Rect;
|
use euclid::Rect;
|
||||||
use euclid::point::Point2D;
|
use euclid::point::Point2D;
|
||||||
use hyper::header::{ContentType, Headers, HttpDate, LastModified};
|
use hyper::header::{ContentType, HttpDate, LastModified};
|
||||||
use hyper::header::ReferrerPolicy as ReferrerPolicyHeader;
|
use hyper::header::ReferrerPolicy as ReferrerPolicyHeader;
|
||||||
use hyper::method::Method;
|
use hyper::method::Method;
|
||||||
use hyper::mime::{Mime, SubLevel, TopLevel};
|
use hyper::mime::{Mime, SubLevel, TopLevel};
|
||||||
|
@ -72,10 +72,10 @@ use js::rust::Runtime;
|
||||||
use layout_wrapper::ServoLayoutNode;
|
use layout_wrapper::ServoLayoutNode;
|
||||||
use mem::heap_size_of_self_and_children;
|
use mem::heap_size_of_self_and_children;
|
||||||
use msg::constellation_msg::{FrameType, PipelineId, PipelineNamespace, ReferrerPolicy};
|
use msg::constellation_msg::{FrameType, PipelineId, PipelineNamespace, ReferrerPolicy};
|
||||||
use net_traits::{AsyncResponseTarget, CoreResourceMsg, LoadConsumer, LoadContext, Metadata, ResourceThreads};
|
use net_traits::{CoreResourceMsg, IpcSend, Metadata, ResourceThreads};
|
||||||
use net_traits::{IpcSend, LoadData as NetLoadData};
|
|
||||||
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||||
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread};
|
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread};
|
||||||
|
use net_traits::request::{CredentialsMode, Destination, RequestInit};
|
||||||
use network_listener::NetworkListener;
|
use network_listener::NetworkListener;
|
||||||
use profile_traits::mem::{self, OpaqueSender, Report, ReportKind, ReportsChan};
|
use profile_traits::mem::{self, OpaqueSender, Report, ReportKind, ReportsChan};
|
||||||
use profile_traits::time::{self, ProfilerCategory, profile};
|
use profile_traits::time::{self, ProfilerCategory, profile};
|
||||||
|
@ -2114,30 +2114,29 @@ impl ScriptThread {
|
||||||
wrapper: None,
|
wrapper: None,
|
||||||
};
|
};
|
||||||
ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
|
ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
|
||||||
listener.notify_action(message.to().unwrap());
|
listener.notify_fetch(message.to().unwrap());
|
||||||
});
|
});
|
||||||
let response_target = AsyncResponseTarget {
|
|
||||||
sender: action_sender,
|
|
||||||
};
|
|
||||||
|
|
||||||
if load_data.url.scheme() == "javascript" {
|
if load_data.url.scheme() == "javascript" {
|
||||||
load_data.url = Url::parse("about:blank").unwrap();
|
load_data.url = Url::parse("about:blank").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.resource_threads.send(CoreResourceMsg::Load(NetLoadData {
|
let request = RequestInit {
|
||||||
context: LoadContext::Browsing,
|
url: load_data.url.clone(),
|
||||||
url: load_data.url,
|
|
||||||
method: load_data.method,
|
method: load_data.method,
|
||||||
headers: Headers::new(),
|
destination: Destination::Document,
|
||||||
preserved_headers: load_data.headers,
|
credentials_mode: CredentialsMode::Include,
|
||||||
data: load_data.data,
|
use_url_credentials: true,
|
||||||
cors: None,
|
origin: load_data.url,
|
||||||
pipeline_id: Some(id),
|
pipeline_id: Some(id),
|
||||||
credentials_flag: true,
|
referrer_url: load_data.referrer_url,
|
||||||
referrer_policy: load_data.referrer_policy,
|
referrer_policy: load_data.referrer_policy,
|
||||||
referrer_url: load_data.referrer_url
|
headers: load_data.headers,
|
||||||
}, LoadConsumer::Listener(response_target), None)).unwrap();
|
body: load_data.data,
|
||||||
|
.. RequestInit::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
self.resource_threads.send(CoreResourceMsg::Fetch(request, action_sender)).unwrap();
|
||||||
self.incomplete_loads.borrow_mut().push(incomplete);
|
self.incomplete_loads.borrow_mut().push(incomplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -708,7 +708,7 @@ fn response_is_done(response: &Response) -> bool {
|
||||||
(*response.body.lock().unwrap()).is_done()
|
(*response.body.lock().unwrap()).is_done()
|
||||||
}
|
}
|
||||||
// if the internal response cannot have a body, it shouldn't block the "done" state
|
// if the internal response cannot have a body, it shouldn't block the "done" state
|
||||||
ResponseType::Opaque | ResponseType::OpaqueRedirect | ResponseType::Error => true
|
ResponseType::Opaque | ResponseType::OpaqueRedirect | ResponseType::Error(..) => true
|
||||||
};
|
};
|
||||||
|
|
||||||
let internal_complete = if let Some(ref res) = response.internal_response {
|
let internal_complete = if let Some(ref res) = response.internal_response {
|
||||||
|
|
|
@ -6,12 +6,13 @@
|
||||||
<div id=log></div>
|
<div id=log></div>
|
||||||
<iframe src="support/set-parent-src.html"></iframe>
|
<iframe src="support/set-parent-src.html"></iframe>
|
||||||
<script>
|
<script>
|
||||||
onload = function() {
|
async_test(function() {
|
||||||
|
onload = this.step_func(function() {
|
||||||
var fr = document.querySelector("iframe")
|
var fr = document.querySelector("iframe")
|
||||||
fr.contentWindow.go()
|
fr.contentWindow.go()
|
||||||
fr.onload = function() {
|
fr.onload = this.step_func_done(function() {
|
||||||
assert_equals(fr.contentDocument.referrer, document.URL)
|
assert_equals(fr.contentDocument.referrer, document.URL)
|
||||||
done()
|
})
|
||||||
}
|
})
|
||||||
}
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -6,13 +6,14 @@
|
||||||
<div id=log></div>
|
<div id=log></div>
|
||||||
<iframe src="support/location-set.html"></iframe>
|
<iframe src="support/location-set.html"></iframe>
|
||||||
<script>
|
<script>
|
||||||
onload = function() {
|
async_test(function() {
|
||||||
|
onload = this.step_func(function() {
|
||||||
var fr = document.querySelector("iframe")
|
var fr = document.querySelector("iframe")
|
||||||
var url = fr.contentDocument.URL
|
var url = fr.contentDocument.URL
|
||||||
fr.contentWindow.go()
|
fr.contentWindow.go()
|
||||||
fr.onload = function() {
|
fr.onload = this.step_func_done(function() {
|
||||||
assert_equals(fr.contentDocument.referrer, url)
|
assert_equals(fr.contentDocument.referrer, url)
|
||||||
done()
|
})
|
||||||
}
|
})
|
||||||
}
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue