servo: Merge #16156 - Update http_network_or_cache_fetch according to spec (from ferjm:issue-16130-http-network-or-cache-fetch); r=jdm

There are still many steps blocked by the absence of an HTTP cache and the inability to trigger a credentials dialog.

- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #16130

Source-Repo: https://github.com/servo/servo
Source-Revision: 0f9dbcc8080e5763553d316261e2d158c19ce6f1

--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : 6ec4952d1393e06f98ca1f1cae413267c2d389c2
This commit is contained in:
Fernando Jiménez Moreno 2017-03-29 19:38:45 -05:00
Родитель 714c6b10e9
Коммит 02a67f151b
1 изменённых файлов: 113 добавлений и 106 удалений

Просмотреть файл

@ -747,15 +747,17 @@ fn http_network_or_cache_fetch(request: Rc<Request>,
// TODO: Implement Window enum for Request // TODO: Implement Window enum for Request
let request_has_no_window = true; let request_has_no_window = true;
// Step 1 // Step 2
let http_request = if request_has_no_window && let http_request = if request_has_no_window &&
request.redirect_mode.get() == RedirectMode::Error { request.redirect_mode.get() == RedirectMode::Error {
request request
} else { } else {
// Step 3
// TODO Implement body source
Rc::new((*request).clone()) Rc::new((*request).clone())
}; };
// Step 2 // Step 4
let credentials_flag = match http_request.credentials_mode { let credentials_flag = match http_request.credentials_mode {
CredentialsMode::Include => true, CredentialsMode::Include => true,
CredentialsMode::CredentialsSameOrigin if http_request.response_tainting.get() == ResponseTainting::Basic CredentialsMode::CredentialsSameOrigin if http_request.response_tainting.get() == ResponseTainting::Basic
@ -766,24 +768,24 @@ fn http_network_or_cache_fetch(request: Rc<Request>,
let content_length_value = match *http_request.body.borrow() { let content_length_value = match *http_request.body.borrow() {
None => None =>
match *http_request.method.borrow() { match *http_request.method.borrow() {
// Step 4 // Step 6
Method::Post | Method::Put => Method::Post | Method::Put =>
Some(0), Some(0),
// Step 3 // Step 5
_ => None _ => None
}, },
// Step 5 // Step 7
Some(ref http_request_body) => Some(http_request_body.len() as u64) Some(ref http_request_body) => Some(http_request_body.len() as u64)
}; };
// Step 6 // Step 8
if let Some(content_length_value) = content_length_value { if let Some(content_length_value) = content_length_value {
http_request.headers.borrow_mut().set(ContentLength(content_length_value)); http_request.headers.borrow_mut().set(ContentLength(content_length_value));
} }
// Step 7 TODO // Step 9 TODO: needs request's client object
// Step 8 // Step 10
match *http_request.referrer.borrow() { match *http_request.referrer.borrow() {
Referrer::NoReferrer => (), Referrer::NoReferrer => (),
Referrer::ReferrerUrl(ref http_request_referrer) => Referrer::ReferrerUrl(ref http_request_referrer) =>
@ -794,7 +796,7 @@ fn http_network_or_cache_fetch(request: Rc<Request>,
unreachable!() unreachable!()
}; };
// Step 9 // Step 11
if !http_request.omit_origin_header.get() { if !http_request.omit_origin_header.get() {
let method = http_request.method.borrow(); let method = http_request.method.borrow();
if cors_flag || (*method != Method::Get && *method != Method::Head) { if cors_flag || (*method != Method::Get && *method != Method::Head) {
@ -807,24 +809,24 @@ fn http_network_or_cache_fetch(request: Rc<Request>,
} }
} }
// Step 10 // Step 12
if !http_request.headers.borrow().has::<UserAgent>() { if !http_request.headers.borrow().has::<UserAgent>() {
let user_agent = context.user_agent.clone().into_owned(); let user_agent = context.user_agent.clone().into_owned();
http_request.headers.borrow_mut().set(UserAgent(user_agent)); http_request.headers.borrow_mut().set(UserAgent(user_agent));
} }
match http_request.cache_mode.get() { match http_request.cache_mode.get() {
// Step 11 // Step 13
CacheMode::Default if is_no_store_cache(&http_request.headers.borrow()) => { CacheMode::Default if is_no_store_cache(&http_request.headers.borrow()) => {
http_request.cache_mode.set(CacheMode::NoStore); http_request.cache_mode.set(CacheMode::NoStore);
}, },
// Step 12 // Step 14
CacheMode::NoCache if !http_request.headers.borrow().has::<CacheControl>() => { CacheMode::NoCache if !http_request.headers.borrow().has::<CacheControl>() => {
http_request.headers.borrow_mut().set(CacheControl(vec![CacheDirective::MaxAge(0)])); http_request.headers.borrow_mut().set(CacheControl(vec![CacheDirective::MaxAge(0)]));
}, },
// Step 13 // Step 15
CacheMode::Reload | CacheMode::NoStore => { CacheMode::Reload | CacheMode::NoStore => {
// Substep 1 // Substep 1
if !http_request.headers.borrow().has::<Pragma>() { if !http_request.headers.borrow().has::<Pragma>() {
@ -840,7 +842,7 @@ fn http_network_or_cache_fetch(request: Rc<Request>,
_ => {} _ => {}
} }
// Step 14 // Step 16
let current_url = http_request.current_url(); let current_url = http_request.current_url();
{ {
let headers = &mut *http_request.headers.borrow_mut(); let headers = &mut *http_request.headers.borrow_mut();
@ -854,7 +856,7 @@ fn http_network_or_cache_fetch(request: Rc<Request>,
set_default_accept_encoding(headers); set_default_accept_encoding(headers);
} }
// Step 15 // Step 17
// TODO some of this step can't be implemented yet // TODO some of this step can't be implemented yet
if credentials_flag { if credentials_flag {
// Substep 1 // Substep 1
@ -892,96 +894,100 @@ fn http_network_or_cache_fetch(request: Rc<Request>,
} }
} }
// Step 16 // Step 18
// TODO If theres a proxy-authentication entry, use it as appropriate. // TODO If theres a proxy-authentication entry, use it as appropriate.
// Step 17 // Step 19
let mut response: Option<Response> = None; let mut response: Option<Response> = None;
// Step 18 // Step 20
let mut revalidation_needed = false;
// Step 21
// TODO have a HTTP cache to check for a completed response // TODO have a HTTP cache to check for a completed response
let complete_http_response_from_cache: Option<Response> = None; let complete_http_response_from_cache: Option<Response> = None;
if http_request.cache_mode.get() != CacheMode::NoStore && if http_request.cache_mode.get() != CacheMode::NoStore &&
http_request.cache_mode.get() != CacheMode::Reload && http_request.cache_mode.get() != CacheMode::Reload &&
complete_http_response_from_cache.is_some() { complete_http_response_from_cache.is_some() {
// Substep 1 // TODO Substep 1 and 2. Select a response from HTTP cache.
// Substep 3
if let Some(ref response) = response {
revalidation_needed = response_needs_revalidation(&response);
};
// Substep 4
if http_request.cache_mode.get() == CacheMode::ForceCache || if http_request.cache_mode.get() == CacheMode::ForceCache ||
http_request.cache_mode.get() == CacheMode::OnlyIfCached { http_request.cache_mode.get() == CacheMode::OnlyIfCached {
// TODO pull response from HTTP cache // TODO pull response from HTTP cache
// response = http_request // response = http_request
} }
let revalidation_needed = match response { if revalidation_needed {
Some(ref response) => response_needs_revalidation(&response), // Substep 5
_ => false // TODO set If-None-Match and If-Modified-Since according to cached
}; // response headers.
} else {
// Substep 2 // Substep 6
if !revalidation_needed && http_request.cache_mode.get() == CacheMode::Default {
// TODO pull response from HTTP cache // TODO pull response from HTTP cache
// response = http_request // response = http_request
// response.cache_state = CacheState::Local; // response.cache_state = CacheState::Local;
} }
// Substep 3
if revalidation_needed && http_request.cache_mode.get() == CacheMode::Default ||
http_request.cache_mode.get() == CacheMode::NoCache {
// TODO this substep
} }
// Step 19 // Step 22
// TODO have a HTTP cache to check for a partial response
} else if http_request.cache_mode.get() == CacheMode::Default ||
http_request.cache_mode.get() == CacheMode::ForceCache {
// TODO this substep
}
// Step 20
if response.is_none() { if response.is_none() {
if http_request.cache_mode.get() == CacheMode::OnlyIfCached {
return Response::network_error(NetworkError::Internal("Couldn't find response in cache".into()))
}
response = Some(http_network_fetch(http_request.clone(), credentials_flag,
done_chan, context));
}
let response = response.unwrap();
if let Some(status) = response.status {
match status {
StatusCode::NotModified => {
// Step 21
if http_request.cache_mode.get() == CacheMode::Default ||
http_request.cache_mode.get() == CacheMode::NoCache {
// Substep 1 // Substep 1
// TODO this substep if http_request.cache_mode.get() == CacheMode::OnlyIfCached {
// let cached_response: Option<Response> = None; return Response::network_error(
NetworkError::Internal("Couldn't find response in cache".into()))
}
// Substep 2 // Substep 2
// if cached_response.is_none() { let forward_response = http_network_fetch(http_request.clone(), credentials_flag,
// return Response::network_error(); done_chan, context);
// } match forward_response.raw_status {
// Substep 3 // Substep 3
Some((200...303, _)) |
// Substep 4 Some((305...399, _)) => {
// response = cached_response; if !http_request.method.borrow().safe() {
// TODO Invalidate HTTP cache response
// Substep 5
// TODO cache_state is immutable?
// response.cache_state = CacheState::Validated;
} }
}, },
StatusCode::Unauthorized => { // Substep 4
// Step 22 Some((304, _)) => {
if revalidation_needed {
// TODO update forward_response headers with cached response
// headers
}
},
_ => {}
}
// Substep 5
if response.is_none() {
response = Some(forward_response);
}
}
let response = response.unwrap();
match response.status {
Some(StatusCode::Unauthorized) => {
// Step 23
// FIXME: Figure out what to do with request window objects // FIXME: Figure out what to do with request window objects
if cors_flag && !credentials_flag { if cors_flag && !credentials_flag {
return response; return response;
} }
// Step 1 // Substep 1
// TODO: Spec says requires testing on multiple WWW-Authenticate headers // TODO: Spec says requires testing on multiple WWW-Authenticate headers
// Step 2 // Substep 2
if http_request.body.borrow().is_some() {
// TODO Implement body source
}
// Substep 3
if !http_request.use_url_credentials || authentication_fetch_flag { if !http_request.use_url_credentials || authentication_fetch_flag {
// TODO: Prompt the user for username and password from the window // TODO: Prompt the user for username and password from the window
// Wrong, but will have to do until we are able to prompt the user // Wrong, but will have to do until we are able to prompt the user
@ -990,11 +996,13 @@ fn http_network_or_cache_fetch(request: Rc<Request>,
return response; return response;
} }
// Step 3 // Substep 4
return http_network_or_cache_fetch(http_request, true, cors_flag, done_chan, context); return http_network_or_cache_fetch(http_request,
true /* authentication flag */,
cors_flag, done_chan, context);
}, },
StatusCode::ProxyAuthenticationRequired => { Some(StatusCode::ProxyAuthenticationRequired) => {
// Step 23 // Step 24
// Step 1 // Step 1
// TODO: Figure out what to do with request window objects // TODO: Figure out what to do with request window objects
@ -1014,14 +1022,13 @@ fn http_network_or_cache_fetch(request: Rc<Request>,
}, },
_ => {} _ => {}
} }
}
// Step 24 // Step 25
if authentication_fetch_flag { if authentication_fetch_flag {
// TODO Create the authentication entry for request and the given realm // TODO Create the authentication entry for request and the given realm
} }
// Step 25 // Step 26
response response
} }