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.rs119
1 files changed, 108 insertions, 11 deletions
diff --git a/components/net/fetch/methods.rs b/components/net/fetch/methods.rs
index 8c5758830c1..49b063f1bc8 100644
--- a/components/net/fetch/methods.rs
+++ b/components/net/fetch/methods.rs
@@ -34,7 +34,7 @@ use net_traits::{
use rustls_pki_types::CertificateDer;
use serde::{Deserialize, Serialize};
use servo_arc::Arc as ServoArc;
-use servo_url::{Host, ServoUrl};
+use servo_url::{Host, ImmutableOrigin, ServoUrl};
use tokio::sync::mpsc::{UnboundedReceiver as TokioReceiver, UnboundedSender as TokioSender};
use super::fetch_params::FetchParams;
@@ -278,7 +278,6 @@ pub async fn main_fetch(
// Step 7. If should request be blocked due to a bad port, should fetching request be blocked
// as mixed content, or should request be blocked by Content Security Policy returns blocked,
// then set response to a network error.
- // TODO: check "should fetching request be blocked as mixed content"
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(
@@ -290,6 +289,11 @@ pub async fn main_fetch(
"Request attempted on bad port".into(),
)));
}
+ if should_request_be_blocked_as_mixed_content(request) {
+ response = Some(Response::network_error(NetworkError::Internal(
+ "Blocked as mixed content".into(),
+ )));
+ }
// 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.
@@ -480,6 +484,8 @@ pub async fn main_fetch(
should_be_blocked_due_to_nosniff(request.destination, &response.headers);
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);
// Step 15.
let mut network_error_response = response
@@ -502,7 +508,7 @@ pub async fn main_fetch(
}
// Step 19. If response is not a network error and any of the following returns blocked
- // TODO: * should internalResponse to request be blocked as mixed content
+ // * should internalResponse to request be blocked as mixed content
// TODO: * should internalResponse to request be blocked by Content Security Policy
// * should internalResponse to request be blocked due to its MIME type
// * should internalResponse to request be blocked due to nosniff
@@ -518,6 +524,10 @@ pub async fn main_fetch(
blocked_error_response =
Response::network_error(NetworkError::Internal("Blocked by mime type".into()));
&blocked_error_response
+ } else if should_replace_with_mixed_content {
+ blocked_error_response =
+ Response::network_error(NetworkError::Internal("Blocked as mixed content".into()));
+ &blocked_error_response
} else {
internal_response
};
@@ -525,7 +535,10 @@ pub async fn main_fetch(
// Step 20. If response’s type is "opaque", internalResponse’s status is 206, internalResponse’s
// range-requested flag is set, and request’s header list does not contain `Range`, then set
// response and internalResponse to a network error.
- let internal_response = if response_type == ResponseType::Opaque &&
+ // Also checking if internal response is a network error to prevent crash from attemtping to
+ // read status of a network error if we blocked the request above.
+ let internal_response = if !internal_response.is_network_error() &&
+ response_type == ResponseType::Opaque &&
internal_response.status.code() == StatusCode::PARTIAL_CONTENT &&
internal_response.range_requested &&
!request.headers.contains_key(RANGE)
@@ -914,6 +927,66 @@ pub fn should_request_be_blocked_due_to_a_bad_port(url: &ServoUrl) -> bool {
false
}
+/// <https://w3c.github.io/webappsec-mixed-content/#should-block-fetch>
+pub fn should_request_be_blocked_as_mixed_content(request: &Request) -> 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.
+ if do_settings_prohibit_mixed_security_contexts(request) ==
+ MixedSecurityProhibited::NotProhibited
+ {
+ return false;
+ }
+
+ // 1.2. request’s URL is a potentially trustworthy URL.
+ if request.url().is_potentially_trustworthy() {
+ return false;
+ }
+
+ // 1.3. The user agent has been instructed to allow mixed content.
+
+ // 1.4. request’s destination is "document", and request’s target browsing context has
+ // no parent browsing context.
+ if request.destination == Destination::Document {
+ // TODO: request's target browsing context has no parent browsing context
+ return false;
+ }
+
+ true
+}
+
+/// <https://w3c.github.io/webappsec-mixed-content/#should-block-response>
+pub fn should_response_be_blocked_as_mixed_content(request: &Request, response: &Response) -> 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.
+ if do_settings_prohibit_mixed_security_contexts(request) ==
+ MixedSecurityProhibited::NotProhibited
+ {
+ return false;
+ }
+
+ // 1.2. response’s url is a potentially trustworthy URL.
+ if response
+ .actual_response()
+ .url()
+ .is_some_and(|response_url| response_url.is_potentially_trustworthy())
+ {
+ return false;
+ }
+
+ // 1.3. TODO: The user agent has been instructed to allow mixed content.
+
+ // 1.4. request’s destination is "document", and request’s target browsing context
+ // has no parent browsing context.
+ if request.destination == Destination::Document {
+ // TODO: if requests target browsing context has no parent browsing context
+ return false;
+ }
+
+ true
+}
+
/// <https://fetch.spec.whatwg.org/#bad-port>
fn is_bad_port(port: u16) -> bool {
static BAD_PORTS: [u16; 78] = [
@@ -983,14 +1056,36 @@ fn should_upgrade_request_to_potentially_trustworty(
request.insecure_requests_policy == InsecureRequestsPolicy::Upgrade
}
-// TODO : Needs to revisit
+#[derive(Debug, PartialEq)]
+pub enum MixedSecurityProhibited {
+ Prohibited,
+ NotProhibited,
+}
+
/// <https://w3c.github.io/webappsec-mixed-content/#categorize-settings-object>
-fn does_settings_prohibit_mixed_security_contexts(url: &ServoUrl) -> bool {
- if url.is_origin_trustworthy() {
- return true;
+fn do_settings_prohibit_mixed_security_contexts(request: &Request) -> MixedSecurityProhibited {
+ if let Origin::Origin(ref origin) = request.origin {
+ // Workers created from a data: url are secure if they were created from secure contexts
+ let is_origin_data_url_worker = matches!(
+ *origin,
+ ImmutableOrigin::Opaque(servo_url::OpaqueOrigin::SecureWorkerFromDataUrl(_))
+ );
+
+ // Step 1. If settings’ origin is a potentially trustworthy origin,
+ // then return "Prohibits Mixed Security Contexts".
+ if origin.is_potentially_trustworthy() || is_origin_data_url_worker {
+ return MixedSecurityProhibited::Prohibited;
+ }
}
- false
+ // Step 2.2. For each navigable navigable in document’s ancestor navigables:
+ // Step 2.2.1. If navigable’s active document's origin is a potentially trustworthy origin,
+ // then return "Prohibits Mixed Security Contexts".
+ if request.has_trustworthy_ancestor_origin {
+ return MixedSecurityProhibited::Prohibited;
+ }
+
+ MixedSecurityProhibited::NotProhibited
}
/// <https://w3c.github.io/webappsec-mixed-content/#upgrade-algorithm>
@@ -1008,12 +1103,14 @@ fn should_upgrade_mixed_content_request(request: &Request) -> bool {
}
// Step 1.3
- if !does_settings_prohibit_mixed_security_contexts(&url) {
+ if do_settings_prohibit_mixed_security_contexts(request) ==
+ MixedSecurityProhibited::NotProhibited
+ {
return false;
}
// Step 1.4 : request’s destination is not "image", "audio", or "video".
- if matches!(
+ if !matches!(
request.destination,
Destination::Audio | Destination::Image | Destination::Video
) {