diff options
Diffstat (limited to 'components/shared')
-rw-r--r-- | components/shared/net/Cargo.toml | 1 | ||||
-rw-r--r-- | components/shared/net/fetch/headers.rs | 93 | ||||
-rw-r--r-- | components/shared/net/pub_domains.rs | 8 | ||||
-rw-r--r-- | components/shared/net/response.rs | 10 |
4 files changed, 102 insertions, 10 deletions
diff --git a/components/shared/net/Cargo.toml b/components/shared/net/Cargo.toml index 79ea936a688..0dfad486455 100644 --- a/components/shared/net/Cargo.toml +++ b/components/shared/net/Cargo.toml @@ -19,6 +19,7 @@ compositing_traits = { workspace = true } content-security-policy = { workspace = true } cookie = { workspace = true } crossbeam-channel = { workspace = true } +data-url = { workspace = true } embedder_traits = { workspace = true } headers = { workspace = true } http = { workspace = true } diff --git a/components/shared/net/fetch/headers.rs b/components/shared/net/fetch/headers.rs index 11bb68d5d0a..5ffd537adf8 100644 --- a/components/shared/net/fetch/headers.rs +++ b/components/shared/net/fetch/headers.rs @@ -3,8 +3,9 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use std::iter::Peekable; -use std::str::Chars; +use std::str::{Chars, FromStr}; +use data_url::mime::Mime as DataUrlMime; use headers::HeaderMap; /// <https://fetch.spec.whatwg.org/#http-tab-or-space> @@ -184,3 +185,93 @@ fn collect_http_quoted_string(position: &mut Peekable<Chars>, extract_value: boo // Step 6, 7 value } + +/// <https://fetch.spec.whatwg.org/#concept-header-extract-mime-type> +/// This function uses data_url::Mime to parse the MIME Type because +/// mime::Mime does not provide a parser following the Fetch spec +/// see <https://github.com/hyperium/mime/issues/106> +pub fn extract_mime_type_as_dataurl_mime(headers: &HeaderMap) -> Option<DataUrlMime> { + // > 1: Let charset be null. + let mut charset = None; + // > 2: Let essence be null. + let mut essence = String::new(); + // > 3: Let mimeType be null. + let mut mime_type = None; + + // > 4: Let values be the result of getting, decoding, and splitting `Content-Type` + // from headers. + // > 5: If values is null, then return failure. + let headers_values = get_decode_and_split_header_name("content-type", headers)?; + + // > 6: For each value of values: + for header_value in headers_values.iter() { + // > 6.1: Let temporaryMimeType be the result of parsing value. + match DataUrlMime::from_str(header_value) { + // > 6.2: If temporaryMimeType is failure or its essence is "*/*", then continue. + Err(_) => continue, + Ok(temp_mime) => { + let temp_essence = format!("{}/{}", temp_mime.type_, temp_mime.subtype); + + // > 6.2: If temporaryMimeType is failure or its essence is "*/*", then + // continue. + if temp_essence == "*/*" { + continue; + } + + // > 6.3: Set mimeType to temporaryMimeType. + mime_type = Some(DataUrlMime { + type_: temp_mime.type_.to_string(), + subtype: temp_mime.subtype.to_string(), + parameters: temp_mime.parameters.clone(), + }); + + // > 6.4: If mimeType’s essence is not essence, then: + let temp_charset = &temp_mime.get_parameter("charset"); + if temp_essence != essence { + // > 6.4.1: Set charset to null. + // > 6.4.2: If mimeType’s parameters["charset"] exists, then set + // charset to mimeType’s parameters["charset"]. + charset = temp_charset.map(|c| c.to_string()); + // > 6.4.3: Set essence to mimeType’s essence. + essence = temp_essence.to_owned(); + } else { + // > 6.5: Otherwise, if mimeType’s parameters["charset"] does not exist, + // and charset is non-null, set mimeType’s parameters["charset"] to charset. + if temp_charset.is_none() && charset.is_some() { + let DataUrlMime { + type_: t, + subtype: st, + parameters: p, + } = mime_type.unwrap(); + let mut params = p; + params.push(("charset".to_string(), charset.clone().unwrap())); + mime_type = Some(DataUrlMime { + type_: t.to_string(), + subtype: st.to_string(), + parameters: params, + }) + } + } + }, + } + } + + // > 7: If mimeType is null, then return failure. + // > 8: Return mimeType. + mime_type +} + +pub fn extract_mime_type(headers: &HeaderMap) -> Option<Vec<u8>> { + extract_mime_type_as_dataurl_mime(headers).map(|m| format!("{}", m).into_bytes()) +} + +pub fn extract_mime_type_as_mime(headers: &HeaderMap) -> Option<mime::Mime> { + extract_mime_type_as_dataurl_mime(headers).and_then(|mime: DataUrlMime| { + // Try to transform a data-url::mime::Mime into a mime::Mime + let mut mime_as_str = format!("{}/{}", mime.type_, mime.subtype); + for p in mime.parameters { + mime_as_str.push_str(format!("; {}={}", p.0, p.1).as_str()); + } + mime_as_str.parse().ok() + }) +} diff --git a/components/shared/net/pub_domains.rs b/components/shared/net/pub_domains.rs index cbbb2b465b2..6e6f883cd2f 100644 --- a/components/shared/net/pub_domains.rs +++ b/components/shared/net/pub_domains.rs @@ -19,9 +19,11 @@ use std::iter::FromIterator; use std::sync::LazyLock; use embedder_traits::resources::{self, Resource}; +use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; +use malloc_size_of_derive::MallocSizeOf; use servo_url::{Host, ImmutableOrigin, ServoUrl}; -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug, Default, MallocSizeOf)] pub struct PubDomainRules { rules: HashSet<String>, wildcards: HashSet<String>, @@ -30,6 +32,10 @@ pub struct PubDomainRules { static PUB_DOMAINS: LazyLock<PubDomainRules> = LazyLock::new(load_pub_domains); +pub fn public_suffix_list_size_of(ops: &mut MallocSizeOfOps) -> usize { + PUB_DOMAINS.size_of(ops) +} + impl<'a> FromIterator<&'a str> for PubDomainRules { fn from_iter<T>(iter: T) -> Self where diff --git a/components/shared/net/response.rs b/components/shared/net/response.rs index f91993ddccb..9a01fbbf965 100644 --- a/components/shared/net/response.rs +++ b/components/shared/net/response.rs @@ -7,7 +7,6 @@ use std::sync::Mutex; use std::sync::atomic::AtomicBool; -use headers::{ContentType, HeaderMapExt}; use http::HeaderMap; use hyper_serde::Serde; use malloc_size_of_derive::MallocSizeOf; @@ -15,6 +14,7 @@ use serde::{Deserialize, Serialize}; use servo_arc::Arc; use servo_url::ServoUrl; +use crate::fetch::headers::extract_mime_type_as_mime; use crate::http_status::HttpStatus; use crate::{ FetchMetadata, FilteredMetadata, Metadata, NetworkError, ReferrerPolicy, ResourceFetchTiming, @@ -300,13 +300,7 @@ impl Response { pub fn metadata(&self) -> Result<FetchMetadata, NetworkError> { fn init_metadata(response: &Response, url: &ServoUrl) -> Metadata { let mut metadata = Metadata::default(url.clone()); - metadata.set_content_type( - response - .headers - .typed_get::<ContentType>() - .map(|v| v.into()) - .as_ref(), - ); + metadata.set_content_type(extract_mime_type_as_mime(&response.headers).as_ref()); metadata.location_url.clone_from(&response.location_url); metadata.headers = Some(Serde(response.headers.clone())); metadata.status.clone_from(&response.status); |