mirror of
https://github.com/servo/servo.git
synced 2025-08-05 05:30:08 +01:00
Update steps of main_fetch according to the Fetch spec
This commit is contained in:
parent
80e02303d3
commit
28f1f669bc
1 changed files with 82 additions and 79 deletions
|
@ -128,12 +128,10 @@ pub fn main_fetch(request: &mut Request,
|
||||||
done_chan: &mut DoneChannel,
|
done_chan: &mut DoneChannel,
|
||||||
context: &FetchContext)
|
context: &FetchContext)
|
||||||
-> Response {
|
-> Response {
|
||||||
// TODO: Implement main fetch spec
|
// Step 1.
|
||||||
|
|
||||||
// Step 1
|
|
||||||
let mut response = None;
|
let mut response = None;
|
||||||
|
|
||||||
// Step 2
|
// Step 2.
|
||||||
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.
|
||||||
|
@ -141,27 +139,27 @@ pub fn main_fetch(request: &mut Request,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3
|
// Step 3.
|
||||||
// TODO be able to execute report CSP
|
// TODO: handle content security policy violations.
|
||||||
|
|
||||||
// Step 4
|
// Step 4.
|
||||||
// TODO this step, based off of http_loader.rs (upgrade)
|
// TODO: handle upgrade to a potentially secure URL.
|
||||||
|
|
||||||
// Step 5
|
// Step 5.
|
||||||
// TODO this step (CSP port/content blocking)
|
|
||||||
if should_be_blocked_due_to_bad_port(&request.url()) {
|
if should_be_blocked_due_to_bad_port(&request.url()) {
|
||||||
response = Some(Response::network_error(NetworkError::Internal("Request attempted on bad port".into())));
|
response = Some(Response::network_error(NetworkError::Internal("Request attempted on bad port".into())));
|
||||||
}
|
}
|
||||||
|
// TODO: handle blocking as mixed content.
|
||||||
|
// TODO: handle blocking by content security policy.
|
||||||
|
|
||||||
// Step 6
|
// Step 6
|
||||||
// TODO this step (referrer policy)
|
// TODO: handle request's client's referrer policy.
|
||||||
// currently the clients themselves set referrer policy in RequestInit
|
|
||||||
|
|
||||||
// Step 7
|
// Step 7.
|
||||||
let referrer_policy = request.referrer_policy.unwrap_or(ReferrerPolicy::NoReferrerWhenDowngrade);
|
let referrer_policy = request.referrer_policy.unwrap_or(ReferrerPolicy::NoReferrerWhenDowngrade);
|
||||||
request.referrer_policy = Some(referrer_policy);
|
request.referrer_policy = Some(referrer_policy);
|
||||||
|
|
||||||
// Step 8
|
// Step 8.
|
||||||
{
|
{
|
||||||
let referrer_url = match mem::replace(&mut request.referrer, Referrer::NoReferrer) {
|
let referrer_url = match mem::replace(&mut request.referrer, Referrer::NoReferrer) {
|
||||||
Referrer::NoReferrer => None,
|
Referrer::NoReferrer => None,
|
||||||
|
@ -185,7 +183,10 @@ pub fn main_fetch(request: &mut Request,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 9
|
// Step 9.
|
||||||
|
// TODO: handle FTP URLs.
|
||||||
|
|
||||||
|
// Step 10.
|
||||||
if !request.current_url().is_secure_scheme() && request.current_url().domain().is_some() {
|
if !request.current_url().is_secure_scheme() && request.current_url().domain().is_some() {
|
||||||
if context.state
|
if context.state
|
||||||
.hsts_list
|
.hsts_list
|
||||||
|
@ -196,63 +197,61 @@ pub fn main_fetch(request: &mut Request,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 10
|
// Step 11.
|
||||||
// this step is obsoleted by fetch_async
|
// Not applicable: see fetch_async.
|
||||||
|
|
||||||
// Step 11
|
// Step 12.
|
||||||
let response = match response {
|
let response = response.unwrap_or_else(|| {
|
||||||
Some(response) => response,
|
let current_url = request.current_url();
|
||||||
None => {
|
let same_origin = if let Origin::Origin(ref origin) = request.origin {
|
||||||
let current_url = request.current_url();
|
*origin == current_url.origin()
|
||||||
let same_origin = if let Origin::Origin(ref origin) = request.origin {
|
} else {
|
||||||
*origin == current_url.origin()
|
false
|
||||||
} else {
|
};
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
if (same_origin && !cors_flag ) ||
|
if (same_origin && !cors_flag ) ||
|
||||||
current_url.scheme() == "data" ||
|
current_url.scheme() == "data" ||
|
||||||
current_url.scheme() == "file" ||
|
current_url.scheme() == "file" ||
|
||||||
current_url.scheme() == "about" ||
|
current_url.scheme() == "about" ||
|
||||||
request.mode == RequestMode::Navigate {
|
request.mode == RequestMode::Navigate {
|
||||||
basic_fetch(request, cache, target, done_chan, context)
|
basic_fetch(request, cache, target, done_chan, context)
|
||||||
|
|
||||||
} else if request.mode == RequestMode::SameOrigin {
|
} else if request.mode == RequestMode::SameOrigin {
|
||||||
Response::network_error(NetworkError::Internal("Cross-origin response".into()))
|
Response::network_error(NetworkError::Internal("Cross-origin response".into()))
|
||||||
|
|
||||||
} else if request.mode == RequestMode::NoCors {
|
} else if request.mode == RequestMode::NoCors {
|
||||||
request.response_tainting = ResponseTainting::Opaque;
|
request.response_tainting = ResponseTainting::Opaque;
|
||||||
basic_fetch(request, cache, target, done_chan, context)
|
basic_fetch(request, cache, target, done_chan, context)
|
||||||
|
|
||||||
} else if !matches!(current_url.scheme(), "http" | "https") {
|
} else if !matches!(current_url.scheme(), "http" | "https") {
|
||||||
Response::network_error(NetworkError::Internal("Non-http scheme".into()))
|
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 &&
|
||||||
(!is_simple_method(&request.method) ||
|
(!is_simple_method(&request.method) ||
|
||||||
request.headers.iter().any(|h| !is_simple_header(&h)))) {
|
request.headers.iter().any(|h| !is_simple_header(&h)))) {
|
||||||
request.response_tainting = ResponseTainting::CorsTainting;
|
request.response_tainting = ResponseTainting::CorsTainting;
|
||||||
let response = http_fetch(request, cache, true, true, false,
|
let response = http_fetch(request, cache, true, true, false,
|
||||||
target, done_chan, context);
|
target, done_chan, context);
|
||||||
if response.is_network_error() {
|
if response.is_network_error() {
|
||||||
// TODO clear cache entries using request
|
// TODO clear cache entries using request
|
||||||
}
|
|
||||||
response
|
|
||||||
|
|
||||||
} else {
|
|
||||||
request.response_tainting = ResponseTainting::CorsTainting;
|
|
||||||
http_fetch(request, cache, true, false, false, target, done_chan, context)
|
|
||||||
}
|
}
|
||||||
}
|
response
|
||||||
};
|
|
||||||
|
|
||||||
// Step 12
|
} else {
|
||||||
|
request.response_tainting = ResponseTainting::CorsTainting;
|
||||||
|
http_fetch(request, cache, true, false, false, target, done_chan, context)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Step 13.
|
||||||
if recursive_flag {
|
if recursive_flag {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 13
|
// Step 14.
|
||||||
// no need to check if response is a network error, since the type would not be `Default`
|
// We don't need to check whether response is a network error,
|
||||||
|
// given its type would not be `Default` in this case.
|
||||||
let response = if response.response_type == ResponseType::Default {
|
let response = if response.response_type == ResponseType::Default {
|
||||||
let response_type = match request.response_tainting {
|
let response_type = match request.response_tainting {
|
||||||
ResponseTainting::Basic => ResponseType::Basic,
|
ResponseTainting::Basic => ResponseType::Basic,
|
||||||
|
@ -264,8 +263,8 @@ pub fn main_fetch(request: &mut Request,
|
||||||
response
|
response
|
||||||
};
|
};
|
||||||
|
|
||||||
let internal_error = { // Inner scope to reborrow response
|
let internal_error = {
|
||||||
// Step 14
|
// Step 15.
|
||||||
let network_error_response;
|
let network_error_response;
|
||||||
let internal_response = if let Some(error) = response.get_network_error() {
|
let internal_response = if let Some(error) = response.get_network_error() {
|
||||||
network_error_response = Response::network_error(error.clone());
|
network_error_response = Response::network_error(error.clone());
|
||||||
|
@ -274,13 +273,15 @@ pub fn main_fetch(request: &mut Request,
|
||||||
response.actual_response()
|
response.actual_response()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 15
|
// Step 16.
|
||||||
if internal_response.url_list.borrow().is_empty() {
|
if internal_response.url_list.borrow().is_empty() {
|
||||||
*internal_response.url_list.borrow_mut() = request.url_list.clone();
|
*internal_response.url_list.borrow_mut() = request.url_list.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 16
|
// Step 17.
|
||||||
// TODO Blocking for CSP, mixed content, MIME type
|
// TODO: handle blocking as mixed content.
|
||||||
|
// TODO: handle blocking by content security policy.
|
||||||
|
// TODO: handle blocking due to MIME type.
|
||||||
let blocked_error_response;
|
let blocked_error_response;
|
||||||
let internal_response =
|
let internal_response =
|
||||||
if !response.is_network_error() && should_be_blocked_due_to_nosniff(request.type_, &response.headers) {
|
if !response.is_network_error() && should_be_blocked_due_to_nosniff(request.type_, &response.headers) {
|
||||||
|
@ -291,8 +292,9 @@ pub fn main_fetch(request: &mut Request,
|
||||||
internal_response
|
internal_response
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 17
|
// Step 18.
|
||||||
// We check `internal_response` since we did not mutate `response` in the previous step.
|
// We check `internal_response` since we did not mutate `response`
|
||||||
|
// in the previous step.
|
||||||
let not_network_error = !response.is_network_error() && !internal_response.is_network_error();
|
let not_network_error = !response.is_network_error() && !internal_response.is_network_error();
|
||||||
if not_network_error && (is_null_body_status(&internal_response.status) ||
|
if not_network_error && (is_null_body_status(&internal_response.status) ||
|
||||||
match request.method {
|
match request.method {
|
||||||
|
@ -307,21 +309,21 @@ pub fn main_fetch(request: &mut Request,
|
||||||
internal_response.get_network_error().map(|e| e.clone())
|
internal_response.get_network_error().map(|e| e.clone())
|
||||||
};
|
};
|
||||||
|
|
||||||
// Execute deferred rebinding of response
|
// Execute deferred rebinding of response.
|
||||||
let response = if let Some(error) = internal_error {
|
let response = if let Some(error) = internal_error {
|
||||||
Response::network_error(error)
|
Response::network_error(error)
|
||||||
} else {
|
} else {
|
||||||
response
|
response
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 18
|
// Step 19.
|
||||||
let mut response_loaded = false;
|
let mut response_loaded = false;
|
||||||
let response = if !response.is_network_error() && request.integrity_metadata != "" {
|
let response = if !response.is_network_error() && !request.integrity_metadata.is_empty() {
|
||||||
// Substep 1
|
// Step 19.1.
|
||||||
wait_for_response(&response, target, done_chan);
|
wait_for_response(&response, target, done_chan);
|
||||||
response_loaded = true;
|
response_loaded = true;
|
||||||
|
|
||||||
// Substep 2
|
// Step 19.2.
|
||||||
let ref integrity_metadata = &request.integrity_metadata;
|
let ref integrity_metadata = &request.integrity_metadata;
|
||||||
if response.termination_reason.is_none() &&
|
if response.termination_reason.is_none() &&
|
||||||
!is_response_integrity_valid(integrity_metadata, &response) {
|
!is_response_integrity_valid(integrity_metadata, &response) {
|
||||||
|
@ -333,7 +335,7 @@ pub fn main_fetch(request: &mut Request,
|
||||||
response
|
response
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 19
|
// Step 20.
|
||||||
if request.synchronous {
|
if request.synchronous {
|
||||||
// process_response is not supposed to be used
|
// process_response is not supposed to be used
|
||||||
// by sync fetch, but we overload it here for simplicity
|
// by sync fetch, but we overload it here for simplicity
|
||||||
|
@ -346,7 +348,7 @@ pub fn main_fetch(request: &mut Request,
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 20
|
// Step 21.
|
||||||
if request.body.is_some() && matches!(request.current_url().scheme(), "http" | "https") {
|
if request.body.is_some() && matches!(request.current_url().scheme(), "http" | "https") {
|
||||||
// XXXManishearth: We actually should be calling process_request
|
// XXXManishearth: We actually should be calling process_request
|
||||||
// in http_network_fetch. However, we can't yet follow the request
|
// in http_network_fetch. However, we can't yet follow the request
|
||||||
|
@ -356,19 +358,20 @@ pub fn main_fetch(request: &mut Request,
|
||||||
target.process_request_eof(&request);
|
target.process_request_eof(&request);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 21
|
// Step 22.
|
||||||
target.process_response(&response);
|
target.process_response(&response);
|
||||||
|
|
||||||
// Step 22
|
// Step 23.
|
||||||
if !response_loaded {
|
if !response_loaded {
|
||||||
wait_for_response(&response, target, done_chan);
|
wait_for_response(&response, target, done_chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 24
|
// Step 24.
|
||||||
target.process_response_eof(&response);
|
target.process_response_eof(&response);
|
||||||
|
|
||||||
// TODO remove this line when only asynchronous fetches are used
|
// Steps 25-27.
|
||||||
return response;
|
// TODO: remove this line when only asynchronous fetches are used
|
||||||
|
response
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait_for_response(response: &Response, target: Target, done_chan: &mut DoneChannel) {
|
fn wait_for_response(response: &Response, target: Target, done_chan: &mut DoneChannel) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue