Remove referrer policy from document (#34263)

* Remove the referrer policy from document and rely on its policy container

Signed-off-by: Shane Handley <shanehandley@fastmail.com>

* Make ReferrerPolicy non-optional, instead using a new enum value to represent the empty string case

Signed-off-by: Shane Handley <shanehandley@fastmail.com>

* Fix clippy issue

Signed-off-by: Shane Handley <shanehandley@fastmail.com>

* Fix usage of Option<ReferrerPolicy> in unit test

Signed-off-by: Shane Handley <shanehandley@fastmail.com>

---------

Signed-off-by: Shane Handley <shanehandley@fastmail.com>
This commit is contained in:
shanehandley 2024-11-19 23:45:10 +11:00 committed by GitHub
parent 83f8e88818
commit 975e2ae859
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
108 changed files with 171 additions and 1509 deletions

View file

@ -28,8 +28,8 @@ use net_traits::request::{
};
use net_traits::response::{Response, ResponseBody, ResponseType};
use net_traits::{
FetchTaskTarget, NetworkError, ResourceAttribute, ResourceFetchTiming, ResourceTimeValue,
ResourceTimingType,
FetchTaskTarget, NetworkError, ReferrerPolicy, ResourceAttribute, ResourceFetchTiming,
ResourceTimeValue, ResourceTimingType,
};
use rustls::Certificate;
use serde::{Deserialize, Serialize};
@ -278,18 +278,16 @@ pub async fn main_fetch(
// Step 8: If requests referrer policy is the empty string, then set requests referrer policy
// to requests policy containers referrer policy.
request.referrer_policy = request
.referrer_policy
.or(Some(policy_container.referrer_policy));
assert!(request.referrer_policy.is_some());
if request.referrer_policy == ReferrerPolicy::EmptyString {
request.referrer_policy = policy_container.get_referrer_policy();
}
let referrer_url = match mem::replace(&mut request.referrer, Referrer::NoReferrer) {
Referrer::NoReferrer => None,
Referrer::ReferrerUrl(referrer_source) | Referrer::Client(referrer_source) => {
request.headers.remove(header::REFERER);
determine_requests_referrer(
request.referrer_policy.unwrap(),
request.referrer_policy,
referrer_source,
request.current_url(),
)

View file

@ -313,7 +313,7 @@ pub fn determine_requests_referrer(
current_url: ServoUrl,
) -> Option<ServoUrl> {
match referrer_policy {
ReferrerPolicy::NoReferrer => None,
ReferrerPolicy::EmptyString | ReferrerPolicy::NoReferrer => None,
ReferrerPolicy::Origin => strip_url_for_use_as_referrer(referrer_source, true),
ReferrerPolicy::UnsafeUrl => strip_url_for_use_as_referrer(referrer_source, false),
ReferrerPolicy::StrictOrigin => strict_origin(referrer_source, current_url),
@ -831,7 +831,9 @@ pub async fn http_fetch(
// response is guaranteed to be something by now
let mut response = response.unwrap();
// Step 5
// TODO: Step 5: cross-origin resource policy check
// Step 6
if response
.actual_response()
.status
@ -986,12 +988,12 @@ pub async fn http_redirect_fetch(
ResourceTimeValue::RedirectStart,
)); // updates start_time only if redirect_start is nonzero (implying TAO)
// Step 5
// Step 7: If requests redirect count is 20, then return a network error.
if request.redirect_count >= 20 {
return Response::network_error(NetworkError::Internal("Too many redirects".into()));
}
// Step 6
// Step 8: Increase requests redirect count by 1.
request.redirect_count += 1;
// Step 7
@ -1002,6 +1004,7 @@ pub async fn http_redirect_fetch(
request.current_url()
),
};
let has_credentials = has_credentials(&location_url);
if request.mode == RequestMode::CorsMode && !same_origin && has_credentials {
@ -1010,24 +1013,25 @@ pub async fn http_redirect_fetch(
));
}
// Step 8
// Step 9
if cors_flag && location_url.origin() != request.current_url().origin() {
request.origin = Origin::Origin(ImmutableOrigin::new_opaque());
}
// Step 10
if cors_flag && has_credentials {
return Response::network_error(NetworkError::Internal("Credentials check failed".into()));
}
// Step 9
// Step 11: If internalResponses status is not 303, requests body is non-null, and requests
// bodys source is null, then return a network error.
if response.actual_response().status != StatusCode::SEE_OTHER &&
request.body.as_ref().is_some_and(|b| b.source_is_null())
{
return Response::network_error(NetworkError::Internal("Request body is not done".into()));
}
// Step 10
if cors_flag && location_url.origin() != request.current_url().origin() {
request.origin = Origin::Origin(ImmutableOrigin::new_opaque());
}
// Step 11
// Step 12
if response
.actual_response()
.status
@ -1040,10 +1044,10 @@ pub async fn http_redirect_fetch(
request.method != Method::GET)
})
{
// Step 11.1
// Step 12.1
request.method = Method::GET;
request.body = None;
// Step 11.2
// Step 12.2
for name in &[
CONTENT_ENCODING,
CONTENT_LANGUAGE,
@ -1075,13 +1079,7 @@ pub async fn http_redirect_fetch(
request.url_list.push(location_url);
// Step 19: Invoke set requests referrer policy on redirect on request and internalResponse.
if let Some(referrer_policy) = response
.actual_response()
.headers
.typed_get::<headers::ReferrerPolicy>()
{
request.referrer_policy = Some(referrer_policy.into());
}
set_requests_referrer_policy_on_redirect(request, response.actual_response());
// Step 20: Let recursive be true.
// Step 21: If requests redirect mode is "manual", then...
@ -2364,15 +2362,13 @@ fn append_a_request_origin_header(request: &mut Request) {
// Step 4.1 If requests mode is not "cors", then switch on requests referrer policy:
if request.mode != RequestMode::CorsMode {
match request.referrer_policy {
Some(ReferrerPolicy::NoReferrer) => {
ReferrerPolicy::NoReferrer => {
// Set serializedOrigin to `null`.
serialized_origin = headers::Origin::NULL;
},
Some(
ReferrerPolicy::NoReferrerWhenDowngrade |
ReferrerPolicy::StrictOrigin |
ReferrerPolicy::StrictOriginWhenCrossOrigin,
) => {
ReferrerPolicy::NoReferrerWhenDowngrade |
ReferrerPolicy::StrictOrigin |
ReferrerPolicy::StrictOriginWhenCrossOrigin => {
// If requests origin is a tuple origin, its scheme is "https", and
// requests current URLs scheme is not "https", then set serializedOrigin to `null`.
if let ImmutableOrigin::Tuple(scheme, _, _) = &request_origin {
@ -2381,7 +2377,7 @@ fn append_a_request_origin_header(request: &mut Request) {
}
}
},
Some(ReferrerPolicy::SameOrigin) => {
ReferrerPolicy::SameOrigin => {
// If requests origin is not same origin with requests current URLs origin,
// then set serializedOrigin to `null`.
if *request_origin != request.current_url().origin() {
@ -2507,3 +2503,18 @@ fn set_the_sec_fetch_user_header(r: &mut Request) {
// Step 5. Set a structured field value `Sec-Fetch-User`/header in rs header list.
r.headers.typed_insert(header);
}
/// <https://w3c.github.io/webappsec-referrer-policy/#set-requests-referrer-policy-on-redirect>
fn set_requests_referrer_policy_on_redirect(request: &mut Request, response: &Response) {
// Step 1: Let policy be the result of executing §8.1 Parse a referrer policy from a
// Referrer-Policy header on actualResponse.
let referrer_policy: ReferrerPolicy = response
.headers
.typed_get::<headers::ReferrerPolicy>()
.into();
// Step 2: If policy is not the empty string, then set requests referrer policy to policy.
if referrer_policy != ReferrerPolicy::EmptyString {
request.referrer_policy = referrer_policy;
}
}

View file

@ -322,7 +322,7 @@ fn test_cors_preflight_fetch() {
let target_url = url.clone().join("a.html").unwrap();
let mut request = RequestBuilder::new(url, Referrer::ReferrerUrl(target_url)).build();
request.referrer_policy = Some(ReferrerPolicy::Origin);
request.referrer_policy = ReferrerPolicy::Origin;
request.use_cors_preflight = true;
request.mode = RequestMode::CorsMode;
let fetch_response = fetch(&mut request, None);