Append the Sec-Purpose header for prefetch requests (#33490)

Signed-off-by: Shane Handley <shanehandley@fastmail.com>
This commit is contained in:
shanehandley 2024-09-18 22:20:05 +10:00 committed by GitHub
parent aa5bf94b35
commit 777a3ec13f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -41,6 +41,7 @@ use net_traits::request::{
is_cors_safelisted_method, is_cors_safelisted_request_header, BodyChunkRequest,
BodyChunkResponse, CacheMode, CredentialsMode, Destination, Initiator, Origin, RedirectMode,
Referrer, Request, RequestBuilder, RequestMode, ResponseTainting, ServiceWorkersMode,
Window as RequestWindow,
};
use net_traits::response::{HttpsState, Response, ResponseBody, ResponseType};
use net_traits::{
@ -1095,27 +1096,33 @@ async fn http_network_or_cache_fetch(
done_chan: &mut DoneChannel,
context: &FetchContext,
) -> Response {
// Step 2
// Step 3: Let httpRequest be null.
let mut http_request;
// Step 4: Let response be null.
let mut response: Option<Response> = None;
// Step 4
// Step 7: Let the revalidatingFlag be unset.
let mut revalidating_flag = false;
// TODO: Implement Window enum for Request
let request_has_no_window = true;
// Step 8.1: If requests window is "no-window" and requests redirect mode is "error", then set
// httpFetchParams to fetchParams and httpRequest to request.
let request_has_no_window = request.window == RequestWindow::NoWindow;
// Step 5.1
let mut http_request;
let http_request = if request_has_no_window && request.redirect_mode == RedirectMode::Error {
request
} else {
// Step 5.2.1, .2.2 and .2.3 and 2.4
// Step 8.2.1: Set httpRequest to a clone of request.
http_request = request.clone();
&mut http_request
};
// Step 5.3
let credentials_flag = match http_request.credentials_mode {
// Step 8.3: Let includeCredentials be true if one of:
let include_credentials = match http_request.credentials_mode {
// requests credentials mode is "include"
CredentialsMode::Include => true,
// requests credentials mode is "same-origin" and requests response tainting is "basic"
CredentialsMode::CredentialsSameOrigin
if http_request.response_tainting == ResponseTainting::Basic =>
{
@ -1124,33 +1131,42 @@ async fn http_network_or_cache_fetch(
_ => false,
};
// Step 8.4: If Cross-Origin-Embedder-Policy allows credentials with request returns false, then
// set includeCredentials to false.
// TODO: Requires request's client object
// Step 8.5: Let contentLength be httpRequests bodys length, if httpRequests body is
// non-null; otherwise null.
let content_length_value = match http_request.body {
Some(ref http_request_body) => http_request_body.len().map(|size| size as u64),
// Step 8.7: If httpRequests body is null and httpRequests method is `POST` or `PUT`, then
// set contentLengthHeaderValue to `0`.
None => match http_request.method {
// Step 5.5
Method::POST | Method::PUT => Some(0),
// Step 5.4
_ => None,
},
// Step 5.6
Some(ref http_request_body) => http_request_body.len().map(|size| size as u64),
};
// Step 5.7
// Step 8.9: If contentLengthHeaderValue is non-null, then append (`Content-Length`,
// contentLengthHeaderValue) to httpRequests header list.
if let Some(content_length_value) = content_length_value {
http_request
.headers
.typed_insert(ContentLength(content_length_value));
if http_request.keep_alive {
// Step 5.8 TODO: needs request's client object
}
}
// Step 5.9
// Step 8.10: If contentLength is non-null and httpRequests keepalive is true, then:
// TODO Keepalive requires request's client object's fetch group
// Step 8.11: If httpRequests referrer is a URL, then:
match http_request.referrer {
Referrer::NoReferrer => (),
Referrer::ReferrerUrl(ref http_request_referrer) |
Referrer::Client(ref http_request_referrer) => {
// Step 8.11.1: Let referrerValue be httpRequests referrer, serialized and isomorphic
// encoded.
if let Ok(referer) = http_request_referrer.to_string().parse::<Referer>() {
// Step 8.11.2: Append (`Referer`, referrerValue) to httpRequests header list.
http_request.headers.typed_insert(referer);
} else {
// This error should only happen in cases where hyper and rust-url disagree
@ -1161,7 +1177,7 @@ async fn http_network_or_cache_fetch(
},
};
// Step 5.10
// Step 8.12: Append a request `Origin` header for httpRequest.
if cors_flag || (http_request.method != Method::GET && http_request.method != Method::HEAD) {
debug_assert_ne!(http_request.origin, Origin::Client);
if let Origin::Origin(ref url_origin) = http_request.origin {
@ -1171,7 +1187,19 @@ async fn http_network_or_cache_fetch(
}
}
// Step 5.11
// Step 8.13: Append the Fetch metadata headers for httpRequest.
// TODO Implement Sec-Fetch-* headers
// Step 8.14: If httpRequests initiator is "prefetch", then set a structured field value given
// (`Sec-Purpose`, the token "prefetch") in httpRequests header list.
if http_request.initiator == Initiator::Prefetch {
if let Ok(value) = HeaderValue::from_str("prefetch") {
http_request.headers.insert("Sec-Purpose", value);
}
}
// Step 8.15: If httpRequests header list does not contain `User-Agent`, then user agents
// should append (`User-Agent`, default `User-Agent` value) to httpRequests header list.
if !http_request.headers.contains_key(header::USER_AGENT) {
let user_agent = context.user_agent.clone().into_owned();
http_request
@ -1223,7 +1251,7 @@ async fn http_network_or_cache_fetch(
// Step 5.17
// TODO some of this step can't be implemented yet
if credentials_flag {
if include_credentials {
// Substep 1
// TODO http://mxr.mozilla.org/servo/source/components/net/http_loader.rs#504
// XXXManishearth http_loader has block_cookies: support content blocking here too
@ -1436,7 +1464,7 @@ async fn http_network_or_cache_fetch(
if response.is_none() {
// Substep 2
let forward_response =
http_network_fetch(http_request, credentials_flag, done_chan, context).await;
http_network_fetch(http_request, include_credentials, done_chan, context).await;
// Substep 3
if let Some((200..=399, _)) = forward_response.raw_status {
if !http_request.method.is_safe() {
@ -1555,7 +1583,7 @@ async fn http_network_or_cache_fetch(
// Step 10
// FIXME: Figure out what to do with request window objects
if let (Some((StatusCode::UNAUTHORIZED, _)), false, true) =
(response.status.as_ref(), cors_flag, credentials_flag)
(response.status.as_ref(), cors_flag, include_credentials)
{
// Substep 1
// TODO: Spec says requires testing on multiple WWW-Authenticate headers