aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2019-10-03 17:36:02 -0400
committerJosh Matthews <josh@joshmatthews.net>2019-10-04 15:08:40 -0400
commit1df8d57dc6adcf56c22b45053b3d2eca904d17d3 (patch)
treece2ba8d6672925a95d551a0ece8ee9e279332e3e /components
parent583536c9406e685405d5b28da99dd8cab94c7d66 (diff)
downloadservo-1df8d57dc6adcf56c22b45053b3d2eca904d17d3.tar.gz
servo-1df8d57dc6adcf56c22b45053b3d2eca904d17d3.zip
Support CORS attributes for image elements.
Diffstat (limited to 'components')
-rw-r--r--components/layout/context.rs1
-rw-r--r--components/net/image_cache.rs62
-rw-r--r--components/net_traits/image_cache.rs2
-rw-r--r--components/net_traits/request.rs12
-rw-r--r--components/script/dom/canvasrenderingcontext2d.rs48
-rw-r--r--components/script/dom/element.rs12
-rw-r--r--components/script/dom/eventsource.rs24
-rw-r--r--components/script/dom/htmlanchorelement.rs8
-rw-r--r--components/script/dom/htmlcanvaselement.rs8
-rw-r--r--components/script/dom/htmlimageelement.rs38
-rw-r--r--components/script/dom/htmlmediaelement.rs15
-rw-r--r--components/script/dom/htmlscriptelement.rs20
-rw-r--r--components/script/dom/htmlvideoelement.rs1
-rw-r--r--components/script/dom/servoparser/prefetch.rs23
-rw-r--r--components/script/dom/webglrenderingcontext.rs17
-rw-r--r--components/script/fetch.rs31
-rw-r--r--components/script/stylesheet_loader.rs21
17 files changed, 232 insertions, 111 deletions
diff --git a/components/layout/context.rs b/components/layout/context.rs
index 5c373ac668d..90b427b0e15 100644
--- a/components/layout/context.rs
+++ b/components/layout/context.rs
@@ -126,6 +126,7 @@ impl<'a> LayoutContext<'a> {
let result = self.image_cache.find_image_or_metadata(
url.clone(),
self.origin.clone(),
+ None,
use_placeholder,
can_request,
);
diff --git a/components/net/image_cache.rs b/components/net/image_cache.rs
index 89397483ee3..1504f1c06e5 100644
--- a/components/net/image_cache.rs
+++ b/components/net/image_cache.rs
@@ -8,6 +8,7 @@ use net_traits::image::base::{load_from_memory, Image, ImageMetadata};
use net_traits::image_cache::{CanRequestImages, CorsStatus, ImageCache, ImageResponder};
use net_traits::image_cache::{ImageOrMetadataAvailable, ImageResponse, ImageState};
use net_traits::image_cache::{PendingImageId, UsePlaceholder};
+use net_traits::request::CorsSettings;
use net_traits::{FetchMetadata, FetchResponseMsg, FilteredMetadata, NetworkError};
use pixels::PixelFormat;
use servo_url::{ImmutableOrigin, ServoUrl};
@@ -92,6 +93,9 @@ fn set_webrender_image_key(webrender_api: &webrender_api::RenderApi, image: &mut
// Aux structs and enums.
// ======================================================================
+/// https://html.spec.whatwg.org/multipage/#list-of-available-images
+type ImageKey = (ServoUrl, ImmutableOrigin, Option<CorsSettings>);
+
// Represents all the currently pending loads/decodings. For
// performance reasons, loads are indexed by a dedicated load key.
struct AllPendingLoads {
@@ -101,7 +105,7 @@ struct AllPendingLoads {
// Get a load key from its url and requesting origin. Used ony when starting and
// finishing a load or when adding a new listener.
- url_to_load_key: HashMap<(ServoUrl, ImmutableOrigin), LoadKey>,
+ url_to_load_key: HashMap<ImageKey, LoadKey>,
// A counter used to generate instances of LoadKey
keygen: LoadKeyGenerator,
@@ -124,7 +128,11 @@ impl AllPendingLoads {
fn remove(&mut self, key: &LoadKey) -> Option<PendingLoad> {
self.loads.remove(key).and_then(|pending_load| {
self.url_to_load_key
- .remove(&(pending_load.url.clone(), pending_load.load_origin.clone()))
+ .remove(&(
+ pending_load.url.clone(),
+ pending_load.load_origin.clone(),
+ pending_load.cors_setting,
+ ))
.unwrap();
Some(pending_load)
})
@@ -134,9 +142,13 @@ impl AllPendingLoads {
&'a mut self,
url: ServoUrl,
origin: ImmutableOrigin,
+ cors_status: Option<CorsSettings>,
can_request: CanRequestImages,
) -> CacheResult<'a> {
- match self.url_to_load_key.entry((url.clone(), origin.clone())) {
+ match self
+ .url_to_load_key
+ .entry((url.clone(), origin.clone(), cors_status))
+ {
Occupied(url_entry) => {
let load_key = url_entry.get();
CacheResult::Hit(*load_key, self.loads.get_mut(load_key).unwrap())
@@ -149,7 +161,7 @@ impl AllPendingLoads {
let load_key = self.keygen.next();
url_entry.insert(load_key);
- let pending_load = PendingLoad::new(url, origin);
+ let pending_load = PendingLoad::new(url, origin, cors_status);
match self.loads.entry(load_key) {
Occupied(_) => unreachable!(),
Vacant(load_entry) => {
@@ -274,6 +286,9 @@ struct PendingLoad {
/// The origin that requested this load.
load_origin: ImmutableOrigin,
+ /// The CORS attribute setting for the requesting
+ cors_setting: Option<CorsSettings>,
+
/// The CORS status of this image response.
cors_status: CorsStatus,
@@ -282,7 +297,11 @@ struct PendingLoad {
}
impl PendingLoad {
- fn new(url: ServoUrl, load_origin: ImmutableOrigin) -> PendingLoad {
+ fn new(
+ url: ServoUrl,
+ load_origin: ImmutableOrigin,
+ cors_setting: Option<CorsSettings>,
+ ) -> PendingLoad {
PendingLoad {
bytes: ImageBytes::InProgress(vec![]),
metadata: None,
@@ -291,6 +310,7 @@ impl PendingLoad {
url: url,
load_origin,
final_url: None,
+ cors_setting,
cors_status: CorsStatus::Unsafe,
}
}
@@ -308,7 +328,7 @@ struct ImageCacheStore {
pending_loads: AllPendingLoads,
// Images that have finished loading (successful or not)
- completed_loads: HashMap<(ServoUrl, ImmutableOrigin), CompletedLoad>,
+ completed_loads: HashMap<ImageKey, CompletedLoad>,
// The placeholder image used when an image fails to load
placeholder_image: Option<Arc<Image>>,
@@ -346,7 +366,11 @@ impl ImageCacheStore {
let completed_load = CompletedLoad::new(image_response.clone(), key);
self.completed_loads.insert(
- (pending_load.url.into(), pending_load.load_origin),
+ (
+ pending_load.url.into(),
+ pending_load.load_origin,
+ pending_load.cors_setting,
+ ),
completed_load,
);
@@ -361,10 +385,11 @@ impl ImageCacheStore {
&self,
url: ServoUrl,
origin: ImmutableOrigin,
+ cors_setting: Option<CorsSettings>,
placeholder: UsePlaceholder,
) -> Option<Result<ImageOrMetadataAvailable, ImageState>> {
self.completed_loads
- .get(&(url, origin))
+ .get(&(url, origin, cors_setting))
.map(
|completed_load| match (&completed_load.image_response, placeholder) {
(&ImageResponse::Loaded(ref image, ref url), _) |
@@ -421,22 +446,29 @@ impl ImageCache for ImageCacheImpl {
&self,
url: ServoUrl,
origin: ImmutableOrigin,
+ cors_setting: Option<CorsSettings>,
use_placeholder: UsePlaceholder,
can_request: CanRequestImages,
) -> Result<ImageOrMetadataAvailable, ImageState> {
debug!("Find image or metadata for {} ({:?})", url, origin);
let mut store = self.store.lock().unwrap();
- if let Some(result) =
- store.get_completed_image_if_available(url.clone(), origin.clone(), use_placeholder)
- {
+ if let Some(result) = store.get_completed_image_if_available(
+ url.clone(),
+ origin.clone(),
+ cors_setting,
+ use_placeholder,
+ ) {
debug!("{} is available", url);
return result;
}
let decoded = {
- let result = store
- .pending_loads
- .get_cached(url.clone(), origin.clone(), can_request);
+ let result = store.pending_loads.get_cached(
+ url.clone(),
+ origin.clone(),
+ cors_setting,
+ can_request,
+ );
match result {
CacheResult::Hit(key, pl) => match (&pl.result, &pl.metadata) {
(&Some(Ok(_)), _) => {
@@ -468,7 +500,7 @@ impl ImageCache for ImageCacheImpl {
// and ignore the async decode when it finishes later.
// TODO: make this behaviour configurable according to the caller's needs.
store.handle_decoder(decoded);
- match store.get_completed_image_if_available(url, origin, use_placeholder) {
+ match store.get_completed_image_if_available(url, origin, cors_setting, use_placeholder) {
Some(result) => result,
None => Err(ImageState::LoadError),
}
diff --git a/components/net_traits/image_cache.rs b/components/net_traits/image_cache.rs
index 3126b37d8b5..203941227d0 100644
--- a/components/net_traits/image_cache.rs
+++ b/components/net_traits/image_cache.rs
@@ -3,6 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::image::base::{Image, ImageMetadata};
+use crate::request::CorsSettings;
use crate::FetchResponseMsg;
use ipc_channel::ipc::IpcSender;
use servo_url::{ImmutableOrigin, ServoUrl};
@@ -111,6 +112,7 @@ pub trait ImageCache: Sync + Send {
&self,
url: ServoUrl,
origin: ImmutableOrigin,
+ cors_setting: Option<CorsSettings>,
use_placeholder: UsePlaceholder,
can_request: CanRequestImages,
) -> Result<ImageOrMetadataAvailable, ImageState>;
diff --git a/components/net_traits/request.rs b/components/net_traits/request.rs
index cfceb5ee888..dad0ae8ca35 100644
--- a/components/net_traits/request.rs
+++ b/components/net_traits/request.rs
@@ -10,7 +10,7 @@ use msg::constellation_msg::PipelineId;
use servo_url::{ImmutableOrigin, ServoUrl};
/// An [initiator](https://fetch.spec.whatwg.org/#concept-request-initiator)
-#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
+#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
pub enum Initiator {
None,
Download,
@@ -128,7 +128,7 @@ pub enum Window {
}
/// [CORS settings attribute](https://html.spec.whatwg.org/multipage/#attr-crossorigin-anonymous)
-#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
+#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum CorsSettings {
Anonymous,
UseCredentials,
@@ -178,6 +178,7 @@ pub struct RequestBuilder {
// to keep track of redirects
pub url_list: Vec<ServoUrl>,
pub parser_metadata: ParserMetadata,
+ pub initiator: Initiator,
}
impl RequestBuilder {
@@ -204,9 +205,15 @@ impl RequestBuilder {
integrity_metadata: "".to_owned(),
url_list: vec![],
parser_metadata: ParserMetadata::Default,
+ initiator: Initiator::None,
}
}
+ pub fn initiator(mut self, initiator: Initiator) -> RequestBuilder {
+ self.initiator = initiator;
+ self
+ }
+
pub fn method(mut self, method: Method) -> RequestBuilder {
self.method = method;
self
@@ -298,6 +305,7 @@ impl RequestBuilder {
Some(Origin::Origin(self.origin)),
self.pipeline_id,
);
+ request.initiator = self.initiator;
request.method = self.method;
request.headers = self.headers;
request.unsafe_request = self.unsafe_request;
diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs
index 380b9a8312a..c964422c27c 100644
--- a/components/script/dom/canvasrenderingcontext2d.rs
+++ b/components/script/dom/canvasrenderingcontext2d.rs
@@ -19,6 +19,7 @@ use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom};
use crate::dom::bindings::str::DOMString;
use crate::dom::canvasgradient::{CanvasGradient, CanvasGradientStyle, ToFillOrStrokeStyle};
use crate::dom::canvaspattern::CanvasPattern;
+use crate::dom::element::cors_setting_for_element;
use crate::dom::element::Element;
use crate::dom::globalscope::GlobalScope;
use crate::dom::htmlcanvaselement::{CanvasContext, HTMLCanvasElement};
@@ -45,6 +46,7 @@ use net_traits::image_cache::ImageOrMetadataAvailable;
use net_traits::image_cache::ImageResponse;
use net_traits::image_cache::ImageState;
use net_traits::image_cache::UsePlaceholder;
+use net_traits::request::CorsSettings;
use pixels::PixelFormat;
use profile_traits::ipc as profiled_ipc;
use script_traits::ScriptMsg;
@@ -210,8 +212,12 @@ impl CanvasState {
}
}
- fn fetch_image_data(&self, url: ServoUrl) -> Option<(Vec<u8>, Size2D<u32>)> {
- let img = match self.request_image_from_cache(url) {
+ fn fetch_image_data(
+ &self,
+ url: ServoUrl,
+ cors_setting: Option<CorsSettings>,
+ ) -> Option<(Vec<u8>, Size2D<u32>)> {
+ let img = match self.request_image_from_cache(url, cors_setting) {
ImageResponse::Loaded(img, _) => img,
ImageResponse::PlaceholderLoaded(_, _) |
ImageResponse::None |
@@ -229,11 +235,15 @@ impl CanvasState {
Some((image_data, image_size))
}
- #[inline]
- fn request_image_from_cache(&self, url: ServoUrl) -> ImageResponse {
+ fn request_image_from_cache(
+ &self,
+ url: ServoUrl,
+ cors_setting: Option<CorsSettings>,
+ ) -> ImageResponse {
let response = self.image_cache.find_image_or_metadata(
url.clone(),
self.origin.clone(),
+ cors_setting,
UsePlaceholder::No,
CanRequestImages::No,
);
@@ -353,13 +363,28 @@ impl CanvasState {
// If the image argument is an HTMLImageElement object that is in the broken state,
// then throw an InvalidStateError exception
let url = image.get_url().ok_or(Error::InvalidState)?;
- self.fetch_and_draw_image_data(htmlcanvas, url, sx, sy, sw, sh, dx, dy, dw, dh)
+ let cors_setting = cors_setting_for_element(image.upcast());
+ self.fetch_and_draw_image_data(
+ htmlcanvas,
+ url,
+ cors_setting,
+ sx,
+ sy,
+ sw,
+ sh,
+ dx,
+ dy,
+ dw,
+ dh,
+ )
},
CanvasImageSource::CSSStyleValue(ref value) => {
let url = value
.get_url(self.base_url.clone())
.ok_or(Error::InvalidState)?;
- self.fetch_and_draw_image_data(htmlcanvas, url, sx, sy, sw, sh, dx, dy, dw, dh)
+ self.fetch_and_draw_image_data(
+ htmlcanvas, url, None, sx, sy, sw, sh, dx, dy, dw, dh,
+ )
},
};
@@ -435,6 +460,7 @@ impl CanvasState {
&self,
canvas: Option<&HTMLCanvasElement>,
url: ServoUrl,
+ cors_setting: Option<CorsSettings>,
sx: f64,
sy: f64,
sw: Option<f64>,
@@ -445,7 +471,9 @@ impl CanvasState {
dh: Option<f64>,
) -> ErrorResult {
debug!("Fetching image {}.", url);
- let (mut image_data, image_size) = self.fetch_image_data(url).ok_or(Error::InvalidState)?;
+ let (mut image_data, image_size) = self
+ .fetch_image_data(url, cors_setting)
+ .ok_or(Error::InvalidState)?;
pixels::rgba8_premultiply_inplace(&mut image_data);
let image_size = image_size.to_f64();
@@ -788,7 +816,9 @@ impl CanvasState {
// then throw an InvalidStateError exception
image
.get_url()
- .and_then(|url| self.fetch_image_data(url))
+ .and_then(|url| {
+ self.fetch_image_data(url, cors_setting_for_element(image.upcast()))
+ })
.ok_or(Error::InvalidState)?
},
CanvasImageSource::HTMLCanvasElement(ref canvas) => {
@@ -800,7 +830,7 @@ impl CanvasState {
},
CanvasImageSource::CSSStyleValue(ref value) => value
.get_url(self.base_url.clone())
- .and_then(|url| self.fetch_image_data(url))
+ .and_then(|url| self.fetch_image_data(url, None))
.ok_or(Error::InvalidState)?,
};
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index 4b16db4699e..baf4fcd0878 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -35,7 +35,7 @@ use crate::dom::create::create_element;
use crate::dom::customelementregistry::{
CallbackReaction, CustomElementDefinition, CustomElementReaction, CustomElementState,
};
-use crate::dom::document::{Document, LayoutDocumentHelpers};
+use crate::dom::document::{determine_policy_for_token, Document, LayoutDocumentHelpers};
use crate::dom::documentfragment::DocumentFragment;
use crate::dom::domrect::DOMRect;
use crate::dom::domtokenlist::DOMTokenList;
@@ -97,6 +97,7 @@ use js::jsapi::Heap;
use js::jsval::JSVal;
use msg::constellation_msg::InputMethodType;
use net_traits::request::CorsSettings;
+use net_traits::ReferrerPolicy;
use ref_filter_map::ref_filter_map;
use script_layout_interface::message::ReflowGoal;
use selectors::attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint};
@@ -3606,7 +3607,14 @@ pub fn set_cross_origin_attribute(element: &Element, value: Option<DOMString>) {
}
}
-pub fn cors_setting_for_element(element: &Element) -> Option<CorsSettings> {
+pub(crate) fn referrer_policy_for_element(element: &Element) -> Option<ReferrerPolicy> {
+ element
+ .get_attribute_by_name(DOMString::from_string(String::from("referrerpolicy")))
+ .and_then(|attribute: DomRoot<Attr>| determine_policy_for_token(&attribute.Value()))
+ .or_else(|| document_from_node(element).get_referrer_policy())
+}
+
+pub(crate) fn cors_setting_for_element(element: &Element) -> Option<CorsSettings> {
reflect_cross_origin_attribute(element).map_or(None, |attr| match &*attr {
"anonymous" => Some(CorsSettings::Anonymous),
"use-credentials" => Some(CorsSettings::UseCredentials),
diff --git a/components/script/dom/eventsource.rs b/components/script/dom/eventsource.rs
index 02283a3c190..92eb2c2f414 100644
--- a/components/script/dom/eventsource.rs
+++ b/components/script/dom/eventsource.rs
@@ -18,7 +18,7 @@ use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::messageevent::MessageEvent;
use crate::dom::performanceresourcetiming::InitiatorType;
-use crate::fetch::FetchCanceller;
+use crate::fetch::{create_a_potential_CORS_request, FetchCanceller};
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
use crate::task_source::{TaskSource, TaskSourceName};
use crate::timers::OneshotTimerCallback;
@@ -31,8 +31,7 @@ use ipc_channel::router::ROUTER;
use js::conversions::ToJSValConvertible;
use js::jsval::UndefinedValue;
use mime::{self, Mime};
-use net_traits::request::{CacheMode, CorsSettings, CredentialsMode};
-use net_traits::request::{RequestBuilder, RequestMode};
+use net_traits::request::{CacheMode, CorsSettings, Destination, RequestBuilder};
use net_traits::{CoreResourceMsg, FetchChannels, FetchMetadata};
use net_traits::{FetchResponseListener, FetchResponseMsg, NetworkError};
use net_traits::{ResourceFetchTiming, ResourceTimingType};
@@ -516,17 +515,14 @@ impl EventSource {
};
// Step 8
// TODO: Step 9 set request's client settings
- let mut request = RequestBuilder::new(url_record)
- .origin(global.origin().immutable().clone())
- .pipeline_id(Some(global.pipeline_id()))
- // https://html.spec.whatwg.org/multipage/#create-a-potential-cors-request
- .use_url_credentials(true)
- .mode(RequestMode::CorsMode)
- .credentials_mode(if cors_attribute_state == CorsSettings::Anonymous {
- CredentialsMode::CredentialsSameOrigin
- } else {
- CredentialsMode::Include
- });
+ let mut request = create_a_potential_CORS_request(
+ url_record,
+ Destination::None,
+ Some(cors_attribute_state),
+ Some(true),
+ )
+ .origin(global.origin().immutable().clone())
+ .pipeline_id(Some(global.pipeline_id()));
// Step 10
// TODO(eijebong): Replace once typed headers allow it
diff --git a/components/script/dom/htmlanchorelement.rs b/components/script/dom/htmlanchorelement.rs
index cb197a054f3..c5b3fb51362 100644
--- a/components/script/dom/htmlanchorelement.rs
+++ b/components/script/dom/htmlanchorelement.rs
@@ -3,7 +3,6 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::dom::activation::Activatable;
-use crate::dom::attr::Attr;
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
use crate::dom::bindings::codegen::Bindings::HTMLAnchorElementBinding;
@@ -14,10 +13,9 @@ use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
use crate::dom::bindings::str::{DOMString, USVString};
-use crate::dom::document::determine_policy_for_token;
use crate::dom::document::Document;
use crate::dom::domtokenlist::DOMTokenList;
-use crate::dom::element::Element;
+use crate::dom::element::{referrer_policy_for_element, Element};
use crate::dom::event::Event;
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
@@ -669,9 +667,7 @@ pub fn follow_hyperlink(subject: &Element, hyperlink_suffix: Option<String>) {
};
// Step 12.
- let referrer_policy = subject
- .get_attribute_by_name(DOMString::from_string(String::from("referrerpolicy")))
- .and_then(|attribute: DomRoot<Attr>| (determine_policy_for_token(&attribute.Value())));
+ let referrer_policy = referrer_policy_for_element(subject);
// Step 13
let referrer = match subject.get_attribute(&ns!(), &local_name!("rel")) {
diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs
index eb62d920ca9..9e638539995 100644
--- a/components/script/dom/htmlcanvaselement.rs
+++ b/components/script/dom/htmlcanvaselement.rs
@@ -442,13 +442,19 @@ pub mod utils {
use crate::dom::window::Window;
use net_traits::image_cache::CanRequestImages;
use net_traits::image_cache::{ImageOrMetadataAvailable, ImageResponse, UsePlaceholder};
+ use net_traits::request::CorsSettings;
use servo_url::ServoUrl;
- pub fn request_image_from_cache(window: &Window, url: ServoUrl) -> ImageResponse {
+ pub fn request_image_from_cache(
+ window: &Window,
+ url: ServoUrl,
+ cors_setting: Option<CorsSettings>,
+ ) -> ImageResponse {
let image_cache = window.image_cache();
let response = image_cache.find_image_or_metadata(
url.into(),
window.origin().immutable().clone(),
+ cors_setting,
UsePlaceholder::No,
CanRequestImages::No,
);
diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs
index 95f00a2b007..a8dcfca5b92 100644
--- a/components/script/dom/htmlimageelement.rs
+++ b/components/script/dom/htmlimageelement.rs
@@ -20,6 +20,7 @@ use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::root::{DomRoot, LayoutDom, MutNullableDom};
use crate::dom::bindings::str::{DOMString, USVString};
use crate::dom::document::Document;
+use crate::dom::element::{cors_setting_for_element, referrer_policy_for_element};
use crate::dom::element::{reflect_cross_origin_attribute, set_cross_origin_attribute};
use crate::dom::element::{AttributeMutation, Element, RawLayoutElementHelpers};
use crate::dom::event::Event;
@@ -40,6 +41,7 @@ use crate::dom::performanceresourcetiming::InitiatorType;
use crate::dom::values::UNSIGNED_LONG_MAX;
use crate::dom::virtualmethods::VirtualMethods;
use crate::dom::window::Window;
+use crate::fetch::create_a_potential_CORS_request;
use crate::image_listener::{add_cache_listener_for_element, ImageCacheListener};
use crate::microtask::{Microtask, MicrotaskRunnable};
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
@@ -58,9 +60,9 @@ use net_traits::image::base::{Image, ImageMetadata};
use net_traits::image_cache::UsePlaceholder;
use net_traits::image_cache::{CanRequestImages, CorsStatus, ImageCache, ImageOrMetadataAvailable};
use net_traits::image_cache::{ImageResponder, ImageResponse, ImageState, PendingImageId};
-use net_traits::request::RequestBuilder;
+use net_traits::request::{CorsSettings, Destination, Initiator, RequestBuilder};
use net_traits::{FetchMetadata, FetchResponseListener, FetchResponseMsg, NetworkError};
-use net_traits::{ResourceFetchTiming, ResourceTimingType};
+use net_traits::{ReferrerPolicy, ResourceFetchTiming, ResourceTimingType};
use num_traits::ToPrimitive;
use servo_url::origin::ImmutableOrigin;
use servo_url::origin::MutableOrigin;
@@ -263,15 +265,31 @@ impl PreInvoke for ImageContext {
}
}
+#[derive(PartialEq)]
+pub(crate) enum FromPictureOrSrcSet {
+ Yes,
+ No,
+}
+
+// https://html.spec.whatwg.org/multipage/#update-the-image-data steps 17-20
// This function is also used to prefetch an image in `script::dom::servoparser::prefetch`.
pub(crate) fn image_fetch_request(
img_url: ServoUrl,
origin: ImmutableOrigin,
pipeline_id: PipelineId,
+ cors_setting: Option<CorsSettings>,
+ referrer_policy: Option<ReferrerPolicy>,
+ from_picture_or_srcset: FromPictureOrSrcSet,
) -> RequestBuilder {
- RequestBuilder::new(img_url)
- .origin(origin)
- .pipeline_id(Some(pipeline_id))
+ let mut request =
+ create_a_potential_CORS_request(img_url, Destination::Image, cors_setting, None)
+ .origin(origin)
+ .pipeline_id(Some(pipeline_id))
+ .referrer_policy(referrer_policy);
+ if from_picture_or_srcset == FromPictureOrSrcSet::Yes {
+ request = request.initiator(Initiator::ImageSet);
+ }
+ request
}
impl HTMLImageElement {
@@ -282,6 +300,7 @@ impl HTMLImageElement {
let response = image_cache.find_image_or_metadata(
img_url.clone().into(),
window.origin().immutable().clone(),
+ cors_setting_for_element(self.upcast()),
UsePlaceholder::Yes,
CanRequestImages::Yes,
);
@@ -344,6 +363,13 @@ impl HTMLImageElement {
img_url.clone(),
document.origin().immutable().clone(),
document.global().pipeline_id(),
+ cors_setting_for_element(self.upcast()),
+ referrer_policy_for_element(self.upcast()),
+ if Self::uses_srcset_or_picture(self.upcast()) {
+ FromPictureOrSrcSet::Yes
+ } else {
+ FromPictureOrSrcSet::No
+ },
);
// This is a background load because the load blocker already fulfills the
@@ -909,6 +935,7 @@ impl HTMLImageElement {
let response = image_cache.find_image_or_metadata(
img_url.clone().into(),
window.origin().immutable().clone(),
+ cors_setting_for_element(self.upcast()),
UsePlaceholder::No,
CanRequestImages::No,
);
@@ -1065,6 +1092,7 @@ impl HTMLImageElement {
let response = image_cache.find_image_or_metadata(
img_url.clone().into(),
window.origin().immutable().clone(),
+ cors_setting_for_element(self.upcast()),
UsePlaceholder::No,
CanRequestImages::Yes,
);
diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs
index e3cb0dfb5b2..fb14f32c789 100644
--- a/components/script/dom/htmlmediaelement.rs
+++ b/components/script/dom/htmlmediaelement.rs
@@ -58,7 +58,7 @@ use crate::dom::url::URL;
use crate::dom::videotrack::VideoTrack;
use crate::dom::videotracklist::VideoTrackList;
use crate::dom::virtualmethods::VirtualMethods;
-use crate::fetch::FetchCanceller;
+use crate::fetch::{create_a_potential_CORS_request, FetchCanceller};
use crate::microtask::{Microtask, MicrotaskRunnable};
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
use crate::script_thread::ScriptThread;
@@ -74,7 +74,7 @@ use ipc_channel::router::ROUTER;
use media::{glplayer_channel, GLPlayerMsg, GLPlayerMsgForward};
use net_traits::image::base::Image;
use net_traits::image_cache::ImageResponse;
-use net_traits::request::{CredentialsMode, Destination, Referrer, RequestBuilder, RequestMode};
+use net_traits::request::{Destination, Referrer};
use net_traits::{CoreResourceMsg, FetchChannels, FetchMetadata, FetchResponseListener, Metadata};
use net_traits::{NetworkError, ResourceFetchTiming, ResourceTimingType};
use script_layout_interface::HTMLMediaData;
@@ -822,16 +822,9 @@ impl HTMLMediaElement {
None => self.blob_url.borrow().as_ref().unwrap().clone(),
};
- let request = RequestBuilder::new(url.clone())
+ let cors_setting = cors_setting_for_element(self.upcast());
+ let request = create_a_potential_CORS_request(url.clone(), destination, cors_setting, None)
.headers(headers)
- .destination(destination)
- .credentials_mode(CredentialsMode::Include)
- // https://html.spec.whatwg.org/multipage/#create-a-potential-cors-request
- .mode(match cors_setting_for_element(self.upcast::<Element>()) {
- Some(_) => RequestMode::CorsMode,
- None => RequestMode::NoCors,
- })
- .use_url_credentials(true)
.origin(document.origin().immutable().clone())
.pipeline_id(Some(self.global().pipeline_id()))
.referrer(Some(Referrer::ReferrerUrl(document.url())))
diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs
index 4d2cf061804..1bd0101c03d 100644
--- a/components/script/dom/htmlscriptelement.rs
+++ b/components/script/dom/htmlscriptelement.rs
@@ -25,6 +25,7 @@ use crate::dom::node::{document_from_node, window_from_node};
use crate::dom::node::{BindContext, ChildrenMutation, CloneChildrenFlag, Node};
use crate::dom::performanceresourcetiming::InitiatorType;
use crate::dom::virtualmethods::VirtualMethods;
+use crate::fetch::create_a_potential_CORS_request;
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
use dom_struct::dom_struct;
use encoding_rs::Encoding;
@@ -33,9 +34,7 @@ use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
use js::jsval::UndefinedValue;
use msg::constellation_msg::PipelineId;
-use net_traits::request::{
- CorsSettings, CredentialsMode, Destination, Referrer, RequestBuilder, RequestMode,
-};
+use net_traits::request::{CorsSettings, Destination, Referrer, RequestBuilder};
use net_traits::ReferrerPolicy;
use net_traits::{FetchMetadata, FetchResponseListener, Metadata, NetworkError};
use net_traits::{ResourceFetchTiming, ResourceTimingType};
@@ -306,20 +305,7 @@ pub(crate) fn script_fetch_request(
referrer_policy: Option<ReferrerPolicy>,
integrity_metadata: String,
) -> RequestBuilder {
- RequestBuilder::new(url)
- .destination(Destination::Script)
- // https://html.spec.whatwg.org/multipage/#create-a-potential-cors-request
- // Step 1
- .mode(match cors_setting {
- Some(_) => RequestMode::CorsMode,
- None => RequestMode::NoCors,
- })
- // https://html.spec.whatwg.org/multipage/#create-a-potential-cors-request
- // Step 3-4
- .credentials_mode(match cors_setting {
- Some(CorsSettings::Anonymous) => CredentialsMode::CredentialsSameOrigin,
- _ => CredentialsMode::Include,
- })
+ create_a_potential_CORS_request(url, Destination::Script, cors_setting, None)
.origin(origin)
.pipeline_id(Some(pipeline_id))
.referrer(Some(referrer))
diff --git a/components/script/dom/htmlvideoelement.rs b/components/script/dom/htmlvideoelement.rs
index 4a1816b5cd4..9b7fc13fcb1 100644
--- a/components/script/dom/htmlvideoelement.rs
+++ b/components/script/dom/htmlvideoelement.rs
@@ -133,6 +133,7 @@ impl HTMLVideoElement {
let response = image_cache.find_image_or_metadata(
poster_url.clone().into(),
window.origin().immutable().clone(),
+ None,
UsePlaceholder::No,
CanRequestImages::Yes,
);
diff --git a/components/script/dom/servoparser/prefetch.rs b/components/script/dom/servoparser/prefetch.rs
index a2977cc15b1..716be8b0f51 100644
--- a/components/script/dom/servoparser/prefetch.rs
+++ b/components/script/dom/servoparser/prefetch.rs
@@ -4,8 +4,8 @@
use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::trace::JSTraceable;
-use crate::dom::document::Document;
-use crate::dom::htmlimageelement::image_fetch_request;
+use crate::dom::document::{determine_policy_for_token, Document};
+use crate::dom::htmlimageelement::{image_fetch_request, FromPictureOrSrcSet};
use crate::dom::htmlscriptelement::script_fetch_request;
use crate::stylesheet_loader::stylesheet_fetch_request;
use html5ever::buffer_queue::BufferQueue;
@@ -123,7 +123,14 @@ impl TokenSink for PrefetchSink {
(TagKind::StartTag, local_name!("img")) if self.prefetching => {
if let Some(url) = self.get_url(tag, local_name!("src")) {
debug!("Prefetch {} {}", tag.name, url);
- let request = image_fetch_request(url, self.origin.clone(), self.pipeline_id);
+ let request = image_fetch_request(
+ url,
+ self.origin.clone(),
+ self.pipeline_id,
+ self.get_cors_settings(tag, local_name!("crossorigin")),
+ self.get_referrer_policy(tag, LocalName::from("referrerpolicy")),
+ FromPictureOrSrcSet::No,
+ );
let _ = self
.resource_threads
.send(CoreResourceMsg::Fetch(request, FetchChannels::Prefetch));
@@ -137,6 +144,8 @@ impl TokenSink for PrefetchSink {
debug!("Prefetch {} {}", tag.name, url);
let cors_setting =
self.get_cors_settings(tag, local_name!("crossorigin"));
+ let referrer_policy =
+ self.get_referrer_policy(tag, LocalName::from("referrerpolicy"));
let integrity_metadata = self
.get_attr(tag, local_name!("integrity"))
.map(|attr| String::from(&attr.value))
@@ -147,7 +156,7 @@ impl TokenSink for PrefetchSink {
self.origin.clone(),
self.pipeline_id,
self.referrer.clone(),
- self.referrer_policy,
+ referrer_policy,
integrity_metadata,
);
let _ = self
@@ -191,6 +200,12 @@ impl PrefetchSink {
ServoUrl::parse_with_base(Some(base), &attr.value).ok()
}
+ fn get_referrer_policy(&self, tag: &Tag, name: LocalName) -> Option<ReferrerPolicy> {
+ self.get_attr(tag, name)
+ .and_then(|attr| determine_policy_for_token(&*attr.value))
+ .or(self.referrer_policy)
+ }
+
fn get_cors_settings(&self, tag: &Tag, name: LocalName) -> Option<CorsSettings> {
let crossorigin = self.get_attr(tag, name)?;
if crossorigin.value.eq_ignore_ascii_case("anonymous") {
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index 46b9c72c6ca..9aa8bfe053a 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -19,6 +19,7 @@ use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{Dom, DomOnceCell, DomRoot, LayoutDom, MutNullableDom};
use crate::dom::bindings::str::DOMString;
+use crate::dom::element::cors_setting_for_element;
use crate::dom::event::{Event, EventBubbles, EventCancelable};
use crate::dom::htmlcanvaselement::utils as canvas_utils;
use crate::dom::htmlcanvaselement::HTMLCanvasElement;
@@ -576,13 +577,15 @@ impl WebGLRenderingContext {
};
let window = window_from_node(&*self.canvas);
-
- let img = match canvas_utils::request_image_from_cache(&window, img_url) {
- ImageResponse::Loaded(img, _) => img,
- ImageResponse::PlaceholderLoaded(_, _) |
- ImageResponse::None |
- ImageResponse::MetadataLoaded(_) => return Ok(None),
- };
+ let cors_setting = cors_setting_for_element(image.upcast());
+
+ let img =
+ match canvas_utils::request_image_from_cache(&window, img_url, cors_setting) {
+ ImageResponse::Loaded(img, _) => img,
+ ImageResponse::PlaceholderLoaded(_, _) |
+ ImageResponse::None |
+ ImageResponse::MetadataLoaded(_) => return Ok(None),
+ };
let size = Size2D::new(img.width, img.height);
diff --git a/components/script/fetch.rs b/components/script/fetch.rs
index 0b093c5501d..8c31f24f260 100644
--- a/components/script/fetch.rs
+++ b/components/script/fetch.rs
@@ -26,7 +26,9 @@ use crate::network_listener::{
use crate::task_source::TaskSourceName;
use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
-use net_traits::request::RequestBuilder;
+use net_traits::request::{
+ CorsSettings, CredentialsMode, Destination, RequestBuilder, RequestMode,
+};
use net_traits::request::{Request as NetTraitsRequest, ServiceWorkersMode};
use net_traits::CoreResourceMsg::Fetch as NetTraitsFetch;
use net_traits::{CoreResourceMsg, CoreResourceThread, FetchResponseMsg};
@@ -124,6 +126,7 @@ fn request_init_from_request(request: NetTraitsRequest) -> RequestBuilder {
integrity_metadata: "".to_owned(),
url_list: vec![],
parser_metadata: request.parser_metadata,
+ initiator: request.initiator,
}
}
@@ -339,3 +342,29 @@ pub fn load_whole_resource(
}
}
}
+
+/// https://html.spec.whatwg.org/multipage/#create-a-potential-cors-request
+pub(crate) fn create_a_potential_CORS_request(
+ url: ServoUrl,
+ destination: Destination,
+ cors_setting: Option<CorsSettings>,
+ same_origin_fallback: Option<bool>,
+) -> RequestBuilder {
+ RequestBuilder::new(url)
+ // https://html.spec.whatwg.org/multipage/#create-a-potential-cors-request
+ // Step 1
+ .mode(match cors_setting {
+ Some(_) => RequestMode::CorsMode,
+ None if same_origin_fallback == Some(true) => RequestMode::SameOrigin,
+ None => RequestMode::NoCors,
+ })
+ // https://html.spec.whatwg.org/multipage/#create-a-potential-cors-request
+ // Step 3-4
+ .credentials_mode(match cors_setting {
+ Some(CorsSettings::Anonymous) => CredentialsMode::CredentialsSameOrigin,
+ _ => CredentialsMode::Include,
+ })
+ // Step 5
+ .destination(destination)
+ .use_url_credentials(true)
+}
diff --git a/components/script/stylesheet_loader.rs b/components/script/stylesheet_loader.rs
index 258286dd6ea..82b5bbdf532 100644
--- a/components/script/stylesheet_loader.rs
+++ b/components/script/stylesheet_loader.rs
@@ -16,6 +16,7 @@ use crate::dom::htmllinkelement::{HTMLLinkElement, RequestGenerationId};
use crate::dom::node::{containing_shadow_root, document_from_node, window_from_node};
use crate::dom::performanceresourcetiming::InitiatorType;
use crate::dom::shadowroot::ShadowRoot;
+use crate::fetch::create_a_potential_CORS_request;
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
use cssparser::SourceLocation;
use encoding_rs::UTF_8;
@@ -23,9 +24,7 @@ use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
use mime::{self, Mime};
use msg::constellation_msg::PipelineId;
-use net_traits::request::{
- CorsSettings, CredentialsMode, Destination, Referrer, RequestBuilder, RequestMode,
-};
+use net_traits::request::{CorsSettings, Destination, Referrer, RequestBuilder};
use net_traits::{
FetchMetadata, FetchResponseListener, FilteredMetadata, Metadata, NetworkError, ReferrerPolicy,
};
@@ -335,6 +334,7 @@ impl<'a> StylesheetLoader<'a> {
}
// This function is also used to prefetch a stylesheet in `script::dom::servoparser::prefetch`.
+// https://html.spec.whatwg.org/multipage/#default-fetch-and-process-the-linked-resource
pub(crate) fn stylesheet_fetch_request(
url: ServoUrl,
cors_setting: Option<CorsSettings>,
@@ -344,20 +344,7 @@ pub(crate) fn stylesheet_fetch_request(
referrer_policy: Option<ReferrerPolicy>,
integrity_metadata: String,
) -> RequestBuilder {
- RequestBuilder::new(url)
- .destination(Destination::Style)
- // https://html.spec.whatwg.org/multipage/#create-a-potential-cors-request
- // Step 1
- .mode(match cors_setting {
- Some(_) => RequestMode::CorsMode,
- None => RequestMode::NoCors,
- })
- // https://html.spec.whatwg.org/multipage/#create-a-potential-cors-request
- // Step 3-4
- .credentials_mode(match cors_setting {
- Some(CorsSettings::Anonymous) => CredentialsMode::CredentialsSameOrigin,
- _ => CredentialsMode::Include,
- })
+ create_a_potential_CORS_request(url, Destination::Style, cors_setting, None)
.origin(origin)
.pipeline_id(Some(pipeline_id))
.referrer(Some(referrer))