mirror of
https://github.com/servo/servo.git
synced 2025-07-22 23:03:42 +01:00
Use spec compliant content-type extraction in more places and enable a <stylesheet>
quirk (#28321)
This changes includes two semi-related things: 1. Fixes some specification compliance issues when parsing mime types and charsets for `XMLHttpRequest`. 2. Implements a `<stylesheet>` parsing quirk involving mime types. Testing: There are tests for these changes. Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
d8837e4a52
commit
6e97fc0bc4
17 changed files with 231 additions and 1148 deletions
|
@ -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 }
|
||||
|
|
|
@ -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()
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue