mirror of
https://github.com/servo/servo
synced 2026-04-25 17:15:48 +02:00
`blob` URLs have a implicit blob URL entry attached, which stores the data contained in the blob. The specification requires this entry to be resolved as the URL is parsed. We only resolve it inside `net` when loading the URL. That causes problems if the blob entry has been revoked in the meantime - see https://github.com/servo/servo/issues/25226. Ideally we would want to resolve blobs at parse-time as required. But because `ServoUrl` is such a fundamental type, I've not managed to do this change without having to touch hundreds of files at once. Thus, we now require passing a `UrlWithBlobClaim` instead of a `ServoUrl` when `fetch`-ing. This type proves that the caller has acquired the blob beforehand. As a temporary escape hatch, I've added `UrlWithBlobClaim::from_url_without_having_claimed_blob`. That method logs a warning if its used unsafely. This method is currently used in most places to keep this change small. Only workers now acquire the blob beforehand. Testing: A new test starts to pass Part of https://github.com/servo/servo/issues/43326 Part of https://github.com/servo/servo/issues/25226 --------- Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> Co-authored-by: Josh Matthews <josh@joshmatthews.net>
169 lines
4.3 KiB
Rust
169 lines
4.3 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
use std::ops::Deref;
|
|
|
|
use headers::{ContentType, HeaderMapExt};
|
|
use hyper_serde::Serde;
|
|
use mime::{self, Mime};
|
|
use net_traits::blob_url_store::UrlWithBlobClaim;
|
|
use net_traits::request::Referrer;
|
|
use net_traits::response::ResponseBody;
|
|
use net_traits::{FetchMetadata, FilteredMetadata, NetworkError};
|
|
use servo_base::id::TEST_WEBVIEW_ID;
|
|
use servo_url::ServoUrl;
|
|
|
|
use crate::fetch;
|
|
|
|
#[cfg(test)]
|
|
fn assert_parse(
|
|
url: &'static str,
|
|
content_type: Option<ContentType>,
|
|
charset: Option<&str>,
|
|
data: Option<&[u8]>,
|
|
) {
|
|
use net_traits::request::RequestBuilder;
|
|
|
|
let url = UrlWithBlobClaim::new(ServoUrl::parse(url).unwrap(), None);
|
|
let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
|
|
.origin(url.origin())
|
|
.pipeline_id(None)
|
|
.policy_container(Default::default())
|
|
.build();
|
|
|
|
let response = fetch(request, None);
|
|
|
|
match data {
|
|
Some(data) => {
|
|
assert!(!response.is_network_error());
|
|
assert_eq!(response.headers.len(), 1);
|
|
|
|
let header_content_type = response.headers.typed_get::<ContentType>();
|
|
assert_eq!(header_content_type, content_type);
|
|
|
|
let metadata = match response.metadata() {
|
|
Ok(FetchMetadata::Filtered {
|
|
filtered: FilteredMetadata::Basic(m),
|
|
..
|
|
}) => m,
|
|
result => panic!("{:?}", result),
|
|
};
|
|
assert_eq!(metadata.content_type.map(Serde::into_inner), content_type);
|
|
assert_eq!(metadata.charset.as_ref().map(String::deref), charset);
|
|
|
|
let resp_body = response.body.lock();
|
|
match *resp_body {
|
|
ResponseBody::Done(ref val) => {
|
|
assert_eq!(val, &data);
|
|
},
|
|
_ => panic!(),
|
|
}
|
|
},
|
|
None => {
|
|
assert!(response.is_network_error());
|
|
assert_eq!(
|
|
response.metadata().err(),
|
|
Some(NetworkError::ResourceLoadError(
|
|
"Decoding data URL failed".to_owned()
|
|
))
|
|
);
|
|
},
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn empty_invalid() {
|
|
assert_parse("data:", None, None, None);
|
|
}
|
|
|
|
#[test]
|
|
fn plain() {
|
|
assert_parse(
|
|
"data:,hello%20world",
|
|
Some(ContentType::from(
|
|
"text/plain; charset=US-ASCII".parse::<Mime>().unwrap(),
|
|
)),
|
|
Some("us-ascii"),
|
|
Some(b"hello world"),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn plain_ct() {
|
|
assert_parse(
|
|
"data:text/plain,hello",
|
|
Some(ContentType::from(mime::TEXT_PLAIN)),
|
|
None,
|
|
Some(b"hello"),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn plain_html() {
|
|
assert_parse(
|
|
"data:text/html,<p>Servo</p>",
|
|
Some(ContentType::from(mime::TEXT_HTML)),
|
|
None,
|
|
Some(b"<p>Servo</p>"),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn plain_charset() {
|
|
assert_parse(
|
|
"data:text/plain;charset=latin1,hello",
|
|
Some(ContentType::from(
|
|
"text/plain; charset=latin1".parse::<Mime>().unwrap(),
|
|
)),
|
|
Some("latin1"),
|
|
Some(b"hello"),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn plain_only_charset() {
|
|
assert_parse(
|
|
"data:;charset=utf-8,hello",
|
|
Some(ContentType::from(mime::TEXT_PLAIN_UTF_8)),
|
|
Some("utf-8"),
|
|
Some(b"hello"),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn base64() {
|
|
assert_parse(
|
|
"data:;base64,C62+7w==",
|
|
Some(ContentType::from(
|
|
"text/plain; charset=US-ASCII".parse::<Mime>().unwrap(),
|
|
)),
|
|
Some("us-ascii"),
|
|
Some(&[0x0B, 0xAD, 0xBE, 0xEF]),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn base64_ct() {
|
|
assert_parse(
|
|
"data:application/octet-stream;base64,C62+7w==",
|
|
Some(ContentType::from(mime::APPLICATION_OCTET_STREAM)),
|
|
None,
|
|
Some(&[0x0B, 0xAD, 0xBE, 0xEF]),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn base64_charset() {
|
|
assert_parse(
|
|
"data:text/plain;charset=koi8-r;base64,8PLl9+XkIO3l5Pfl5A==",
|
|
Some(ContentType::from(
|
|
"text/plain; charset=koi8-r".parse::<Mime>().unwrap(),
|
|
)),
|
|
Some("koi8-r"),
|
|
Some(&[
|
|
0xF0, 0xF2, 0xE5, 0xF7, 0xE5, 0xE4, 0x20, 0xED, 0xE5, 0xE4, 0xF7, 0xE5, 0xE4,
|
|
]),
|
|
);
|
|
}
|