aboutsummaryrefslogtreecommitdiffstats
path: root/components/net/fetch/methods.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/net/fetch/methods.rs')
-rw-r--r--components/net/fetch/methods.rs108
1 files changed, 78 insertions, 30 deletions
diff --git a/components/net/fetch/methods.rs b/components/net/fetch/methods.rs
index 697a46fedda..b1ad01b81e0 100644
--- a/components/net/fetch/methods.rs
+++ b/components/net/fetch/methods.rs
@@ -23,8 +23,8 @@ use net_traits::http_status::HttpStatus;
use net_traits::policy_container::{PolicyContainer, RequestPolicyContainer};
use net_traits::request::{
BodyChunkRequest, BodyChunkResponse, CredentialsMode, Destination, Initiator,
- InsecureRequestsPolicy, Origin, RedirectMode, Referrer, Request, RequestMode, ResponseTainting,
- Window, is_cors_safelisted_method, is_cors_safelisted_request_header,
+ InsecureRequestsPolicy, Origin, ParserMetadata, RedirectMode, Referrer, Request, RequestMode,
+ ResponseTainting, Window, is_cors_safelisted_method, is_cors_safelisted_request_header,
};
use net_traits::response::{Response, ResponseBody, ResponseType};
use net_traits::{
@@ -42,7 +42,7 @@ use crate::fetch::cors_cache::CorsCache;
use crate::fetch::headers::determine_nosniff;
use crate::filemanager_thread::FileManager;
use crate::http_loader::{HttpState, determine_requests_referrer, http_fetch, set_default_accept};
-use crate::protocols::ProtocolRegistry;
+use crate::protocols::{ProtocolRegistry, is_url_potentially_trustworthy};
use crate::request_interceptor::RequestInterceptor;
use crate::subresource_integrity::is_response_integrity_valid;
@@ -169,6 +169,29 @@ pub async fn fetch_with_cors_cache(
// TODO: We don't implement fetchParams as defined in the spec
}
+fn convert_request_to_csp_request(request: &Request, origin: &ImmutableOrigin) -> csp::Request {
+ csp::Request {
+ url: request.url().into_url(),
+ origin: origin.clone().into_url_origin(),
+ redirect_count: request.redirect_count,
+ destination: request.destination,
+ initiator: match request.initiator {
+ Initiator::Download => csp::Initiator::Download,
+ Initiator::ImageSet => csp::Initiator::ImageSet,
+ Initiator::Manifest => csp::Initiator::Manifest,
+ Initiator::Prefetch => csp::Initiator::Prefetch,
+ _ => csp::Initiator::None,
+ },
+ nonce: request.cryptographic_nonce_metadata.clone(),
+ integrity_metadata: request.integrity_metadata.clone(),
+ parser_metadata: match request.parser_metadata {
+ ParserMetadata::ParserInserted => csp::ParserMetadata::ParserInserted,
+ ParserMetadata::NotParserInserted => csp::ParserMetadata::NotParserInserted,
+ ParserMetadata::Default => csp::ParserMetadata::None,
+ },
+ }
+}
+
/// <https://www.w3.org/TR/CSP/#should-block-request>
pub fn should_request_be_blocked_by_csp(
request: &Request,
@@ -178,17 +201,7 @@ pub fn should_request_be_blocked_by_csp(
Origin::Client => return (csp::CheckResult::Allowed, Vec::new()),
Origin::Origin(origin) => origin,
};
-
- let csp_request = csp::Request {
- url: request.url().into_url(),
- origin: origin.clone().into_url_origin(),
- redirect_count: request.redirect_count,
- destination: request.destination,
- initiator: csp::Initiator::None,
- nonce: request.cryptographic_nonce_metadata.clone(),
- integrity_metadata: request.integrity_metadata.clone(),
- parser_metadata: csp::ParserMetadata::None,
- };
+ let csp_request = convert_request_to_csp_request(request, origin);
policy_container
.csp_list
@@ -197,6 +210,24 @@ pub fn should_request_be_blocked_by_csp(
.unwrap_or((csp::CheckResult::Allowed, Vec::new()))
}
+/// <https://www.w3.org/TR/CSP/#report-for-request>
+pub fn report_violations_for_request_by_csp(
+ request: &Request,
+ policy_container: &PolicyContainer,
+) -> Vec<csp::Violation> {
+ let origin = match &request.origin {
+ Origin::Client => return Vec::new(),
+ Origin::Origin(origin) => origin,
+ };
+ let csp_request = convert_request_to_csp_request(request, origin);
+
+ policy_container
+ .csp_list
+ .as_ref()
+ .map(|c| c.report_violations_for_request(&csp_request))
+ .unwrap_or_default()
+}
+
/// [Main fetch](https://fetch.spec.whatwg.org/#concept-main-fetch)
pub async fn main_fetch(
fetch_params: &mut FetchParams,
@@ -232,9 +263,6 @@ 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 {
@@ -242,12 +270,19 @@ pub async fn main_fetch(
RequestPolicyContainer::PolicyContainer(container) => container.to_owned(),
};
+ // Step 2.2.
+ let violations = report_violations_for_request_by_csp(request, &policy_container);
+
+ if !violations.is_empty() {
+ target.process_csp_violations(request, violations);
+ }
+
// Step 3.
// TODO: handle request abort.
// Step 4. Upgrade request to a potentially trustworthy URL, if appropriate.
if should_upgrade_request_to_potentially_trustworty(request, context) ||
- should_upgrade_mixed_content_request(request)
+ should_upgrade_mixed_content_request(request, &context.protocols)
{
trace!(
"upgrading {} targeting {:?}",
@@ -294,7 +329,7 @@ pub async fn main_fetch(
"Request attempted on bad port".into(),
)));
}
- if should_request_be_blocked_as_mixed_content(request) {
+ if should_request_be_blocked_as_mixed_content(request, &context.protocols) {
response = Some(Response::network_error(NetworkError::Internal(
"Blocked as mixed content".into(),
)));
@@ -359,13 +394,16 @@ pub async fn main_fetch(
if (same_origin && request.response_tainting == ResponseTainting::Basic) ||
// request's current URL's scheme is "data"
current_scheme == "data" ||
+ // Note: Although it is not part of the specification, we make an exception here
+ // for custom protocols that are explicitly marked as active for fetch.
+ context.protocols.is_fetchable(current_scheme) ||
// request's mode is "navigate" or "websocket"
matches!(
request.mode,
RequestMode::Navigate | RequestMode::WebSocket { .. }
)
{
- // Substep 1. Set request’s response tainting to "basic".
+ // Substep 1. Set request's response tainting to "basic".
request.response_tainting = ResponseTainting::Basic;
// Substep 2. Return the result of running scheme fetch given fetchParams.
@@ -373,13 +411,13 @@ pub async fn main_fetch(
} else if request.mode == RequestMode::SameOrigin {
Response::network_error(NetworkError::Internal("Cross-origin response".into()))
} else if request.mode == RequestMode::NoCors {
- // Substep 1. If request’s redirect mode is not "follow", then return a network error.
+ // Substep 1. If request's redirect mode is not "follow", then return a network error.
if request.redirect_mode != RedirectMode::Follow {
Response::network_error(NetworkError::Internal(
"NoCors requests must follow redirects".into(),
))
} else {
- // Substep 2. Set request’s response tainting to "opaque".
+ // Substep 2. Set request's response tainting to "opaque".
request.response_tainting = ResponseTainting::Opaque;
// Substep 3. Return the result of running scheme fetch given fetchParams.
@@ -490,7 +528,7 @@ pub async fn main_fetch(
let should_replace_with_mime_type_error = !response_is_network_error &&
should_be_blocked_due_to_mime_type(request.destination, &response.headers);
let should_replace_with_mixed_content = !response_is_network_error &&
- should_response_be_blocked_as_mixed_content(request, &response);
+ should_response_be_blocked_as_mixed_content(request, &response, &context.protocols);
// Step 15.
let mut network_error_response = response
@@ -933,7 +971,10 @@ pub fn should_request_be_blocked_due_to_a_bad_port(url: &ServoUrl) -> bool {
}
/// <https://w3c.github.io/webappsec-mixed-content/#should-block-fetch>
-pub fn should_request_be_blocked_as_mixed_content(request: &Request) -> bool {
+pub fn should_request_be_blocked_as_mixed_content(
+ request: &Request,
+ protocol_registry: &ProtocolRegistry,
+) -> bool {
// Step 1. Return allowed if one or more of the following conditions are met:
// 1.1. Does settings prohibit mixed security contexts?
// returns "Does Not Restrict Mixed Security Contexts" when applied to request’s client.
@@ -944,7 +985,7 @@ pub fn should_request_be_blocked_as_mixed_content(request: &Request) -> bool {
}
// 1.2. request’s URL is a potentially trustworthy URL.
- if request.url().is_potentially_trustworthy() {
+ if is_url_potentially_trustworthy(protocol_registry, &request.url()) {
return false;
}
@@ -961,7 +1002,11 @@ pub fn should_request_be_blocked_as_mixed_content(request: &Request) -> bool {
}
/// <https://w3c.github.io/webappsec-mixed-content/#should-block-response>
-pub fn should_response_be_blocked_as_mixed_content(request: &Request, response: &Response) -> bool {
+pub fn should_response_be_blocked_as_mixed_content(
+ request: &Request,
+ response: &Response,
+ protocol_registry: &ProtocolRegistry,
+) -> bool {
// Step 1. Return allowed if one or more of the following conditions are met:
// 1.1. Does settings prohibit mixed security contexts? returns Does Not Restrict Mixed Content
// when applied to request’s client.
@@ -975,7 +1020,7 @@ pub fn should_response_be_blocked_as_mixed_content(request: &Request, response:
if response
.actual_response()
.url()
- .is_some_and(|response_url| response_url.is_potentially_trustworthy())
+ .is_some_and(|response_url| is_url_potentially_trustworthy(protocol_registry, response_url))
{
return false;
}
@@ -1041,7 +1086,7 @@ fn should_upgrade_request_to_potentially_trustworty(
// request’s header list if any of the following criteria are met:
// * request’s URL is not a potentially trustworthy URL
// * request’s URL's host is not a preloadable HSTS host
- if !request.current_url().is_potentially_trustworthy() ||
+ if !is_url_potentially_trustworthy(&context.protocols, &request.current_url()) ||
!request.current_url().host_str().is_some_and(|host| {
!context.state.hsts_list.read().unwrap().is_host_secure(host)
})
@@ -1094,10 +1139,13 @@ fn do_settings_prohibit_mixed_security_contexts(request: &Request) -> MixedSecur
}
/// <https://w3c.github.io/webappsec-mixed-content/#upgrade-algorithm>
-fn should_upgrade_mixed_content_request(request: &Request) -> bool {
+fn should_upgrade_mixed_content_request(
+ request: &Request,
+ protocol_registry: &ProtocolRegistry,
+) -> bool {
let url = request.url();
// Step 1.1 : request’s URL is a potentially trustworthy URL.
- if url.is_potentially_trustworthy() {
+ if is_url_potentially_trustworthy(protocol_registry, &url) {
return false;
}