diff options
author | shanehandley <1322294+shanehandley@users.noreply.github.com> | 2024-11-08 18:19:23 +1100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-08 07:19:23 +0000 |
commit | 645176742813c423c3c5016eaba69a546b286339 (patch) | |
tree | 7b47b66bdeb596668681aa83f8cf3a64a8ff8408 /components/net/fetch | |
parent | 4f6283d7fead1b2489456651185e3a8bbbc725e8 (diff) | |
download | servo-645176742813c423c3c5016eaba69a546b286339.tar.gz servo-645176742813c423c3c5016eaba69a546b286339.zip |
Implement PolicyContainer and update the default ReferrerPolicy (#33977)
* Implement PolicyContainer
Signed-off-by: Shane Handley <shanehandley@fastmail.com>
* implement small parts of fetch that interact with policy container
Signed-off-by: Shane Handley <shanehandley@fastmail.com>
* fix: allow policy container's csp list to be unset
Signed-off-by: Shane Handley <shanehandley@fastmail.com>
* fix: use the correct default policy when parsing from a token
Signed-off-by: Shane Handley <shanehandley@fastmail.com>
---------
Signed-off-by: Shane Handley <shanehandley@fastmail.com>
Diffstat (limited to 'components/net/fetch')
-rw-r--r-- | components/net/fetch/methods.rs | 82 |
1 files changed, 60 insertions, 22 deletions
diff --git a/components/net/fetch/methods.rs b/components/net/fetch/methods.rs index 7d64b57436d..2e99f5f3314 100644 --- a/components/net/fetch/methods.rs +++ b/components/net/fetch/methods.rs @@ -20,6 +20,7 @@ use log::warn; use mime::{self, Mime}; use net_traits::filemanager_thread::{FileTokenCheck, RelativePos}; use net_traits::http_status::HttpStatus; +use net_traits::policy_container::{PolicyContainer, RequestPolicyContainer}; use net_traits::request::{ is_cors_safelisted_method, is_cors_safelisted_request_header, BodyChunkRequest, BodyChunkResponse, CredentialsMode, Destination, Origin, RedirectMode, Referrer, Request, @@ -27,8 +28,8 @@ use net_traits::request::{ }; use net_traits::response::{Response, ResponseBody, ResponseType}; use net_traits::{ - FetchTaskTarget, NetworkError, ReferrerPolicy, ResourceAttribute, ResourceFetchTiming, - ResourceTimeValue, ResourceTimingType, + FetchTaskTarget, NetworkError, ResourceAttribute, ResourceFetchTiming, ResourceTimeValue, + ResourceTimingType, }; use rustls::Certificate; use serde::{Deserialize, Serialize}; @@ -114,52 +115,83 @@ pub async fn fetch(request: &mut Request, target: Target<'_>, context: &FetchCon fetch_with_cors_cache(request, &mut CorsCache::default(), target, context).await; } +/// Continuation of fetch from step 9. +/// +/// <https://fetch.spec.whatwg.org#concept-fetch> pub async fn fetch_with_cors_cache( request: &mut Request, cache: &mut CorsCache, target: Target<'_>, context: &FetchContext, ) { - // Step 1. + // Step 9: If request’s window is "client", then set request’s window to request’s client, if + // request’s client’s global object is a Window object; otherwise "no-window". if request.window == Window::Client { // TODO: Set window to request's client object if client is a Window object } else { request.window = Window::NoWindow; } - // Step 2. + // Step 10: If request’s origin is "client", then set request’s origin to request’s client’s + // origin. if request.origin == Origin::Client { // TODO: set request's origin to request's client's origin unimplemented!() } - // Step 3. + // Step 11: If all of the following conditions are true: + // - request’s URL’s scheme is an HTTP(S) scheme + // - request’s mode is "same-origin", "cors", or "no-cors" + // - request’s window is an environment settings object + // - request’s method is `GET` + // - request’s unsafe-request flag is not set or request’s header list is empty + // TODO: evaluate these conditions when we have an an environment settings object + + // Step 12: If request’s policy container is "client", then: + if let RequestPolicyContainer::Client = request.policy_container { + // Step 12.1: If request’s client is non-null, then set request’s policy container to a clone + // of request’s client’s policy container. + // TODO: Requires request's client to support PolicyContainer + + // Step 12.2: Otherwise, set request’s policy container to a new policy container. + request.policy_container = + RequestPolicyContainer::PolicyContainer(PolicyContainer::default()); + } + + // Step 13: If request’s header list does not contain `Accept`: set_default_accept(request); - // Step 4. + // Step 14: If request’s header list does not contain `Accept-Language`, then user agents should + // append (`Accept-Language, an appropriate header value) to request’s header list. set_default_accept_language(&mut request.headers); - // Step 5. + // Step 15. If request’s internal priority is null, then use request’s priority, initiator, + // destination, and render-blocking in an implementation-defined manner to set request’s + // internal priority to an implementation-defined object. // TODO: figure out what a Priority object is. - // Step 6. - // TODO: handle client hints headers. - - // Step 7. + // Step 16: If request is a subresource request, then: if request.is_subresource_request() { - // TODO: handle client hints headers. + // TODO: requires keepalive. } - // Step 8. + // Step 17: Run main fetch given fetchParams. main_fetch(request, cache, false, false, target, &mut None, context).await; + + // Step 18: Return fetchParams’s controller. + // TODO: We don't implement fetchParams as defined in the spec } /// <https://www.w3.org/TR/CSP/#should-block-request> -pub fn should_request_be_blocked_by_csp(request: &Request) -> csp::CheckResult { +pub fn should_request_be_blocked_by_csp( + request: &Request, + policy_container: &PolicyContainer, +) -> csp::CheckResult { let origin = match &request.origin { Origin::Client => return csp::CheckResult::Allowed, Origin::Origin(origin) => origin, }; + let csp_request = csp::Request { url: request.url().into_url(), origin: origin.clone().into_url_origin(), @@ -170,8 +202,9 @@ pub fn should_request_be_blocked_by_csp(request: &Request) -> csp::CheckResult { integrity_metadata: request.integrity_metadata.clone(), parser_metadata: csp::ParserMetadata::None, }; + // TODO: Instead of ignoring violations, report them. - request + policy_container .csp_list .as_ref() .map(|c| c.should_request_be_blocked(&csp_request).0) @@ -213,8 +246,15 @@ pub async fn main_fetch( // Step 2.2. // TODO: Report violations. + // The request should have a valid policy_container associated with it. + // TODO: This should not be `Client` here + let policy_container = match &request.policy_container { + RequestPolicyContainer::Client => PolicyContainer::default(), + RequestPolicyContainer::PolicyContainer(container) => container.to_owned(), + }; + // Step 2.4. - if should_request_be_blocked_by_csp(request) == csp::CheckResult::Blocked { + if should_request_be_blocked_by_csp(request, &policy_container) == csp::CheckResult::Blocked { warn!("Request blocked by CSP"); response = Some(Response::network_error(NetworkError::Internal( "Blocked by Content-Security-Policy".into(), @@ -236,16 +276,14 @@ pub async fn main_fetch( // TODO: handle blocking as mixed content. // TODO: handle blocking by content security policy. - // Step 6 - // TODO: handle request's client's referrer policy. - - // Step 7. + // Step 8: If request’s referrer policy is the empty string, then set request’s referrer policy + // to request’s policy container’s referrer policy. request.referrer_policy = request .referrer_policy - .or(Some(ReferrerPolicy::NoReferrerWhenDowngrade)); + .or(Some(policy_container.referrer_policy)); - // Step 8. assert!(request.referrer_policy.is_some()); + let referrer_url = match mem::replace(&mut request.referrer, Referrer::NoReferrer) { Referrer::NoReferrer => None, Referrer::ReferrerUrl(referrer_source) | Referrer::Client(referrer_source) => { |