mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Prefetch img and scripts during parsing
This commit is contained in:
parent
5bcb1b579c
commit
1aeb97b281
8 changed files with 351 additions and 45 deletions
|
@ -25,11 +25,12 @@ use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
|||
use net_traits::request::{Destination, RequestBuilder};
|
||||
use net_traits::response::{Response, ResponseInit};
|
||||
use net_traits::storage_thread::StorageThreadMsg;
|
||||
use net_traits::FetchTaskTarget;
|
||||
use net_traits::WebSocketNetworkEvent;
|
||||
use net_traits::{CookieSource, CoreResourceMsg, CoreResourceThread};
|
||||
use net_traits::{CustomResponseMediator, FetchChannels};
|
||||
use net_traits::{FetchResponseMsg, ResourceThreads, WebSocketDomAction};
|
||||
use net_traits::{ResourceFetchTiming, ResourceTimingType};
|
||||
use net_traits::{ResourceThreads, WebSocketDomAction};
|
||||
use profile_traits::mem::ProfilerChan as MemProfilerChan;
|
||||
use profile_traits::mem::{Report, ReportKind, ReportsChan};
|
||||
use profile_traits::time::ProfilerChan;
|
||||
|
@ -245,6 +246,10 @@ impl ResourceChannelManager {
|
|||
action_receiver,
|
||||
http_state,
|
||||
),
|
||||
FetchChannels::Prefetch => {
|
||||
self.resource_manager
|
||||
.fetch(req_init, None, (), http_state, None)
|
||||
},
|
||||
},
|
||||
CoreResourceMsg::DeleteCookies(request) => {
|
||||
http_state
|
||||
|
@ -455,11 +460,11 @@ impl CoreResourceManager {
|
|||
}
|
||||
}
|
||||
|
||||
fn fetch(
|
||||
fn fetch<Target: 'static + FetchTaskTarget + Send>(
|
||||
&self,
|
||||
request_builder: RequestBuilder,
|
||||
res_init_: Option<ResponseInit>,
|
||||
mut sender: IpcSender<FetchResponseMsg>,
|
||||
mut sender: Target,
|
||||
http_state: &Arc<HttpState>,
|
||||
cancel_chan: Option<IpcReceiver<()>>,
|
||||
) {
|
||||
|
|
|
@ -237,6 +237,18 @@ impl FetchTaskTarget for IpcSender<FetchResponseMsg> {
|
|||
}
|
||||
}
|
||||
|
||||
impl FetchTaskTarget for () {
|
||||
fn process_request_body(&mut self, _: &Request) {}
|
||||
|
||||
fn process_request_eof(&mut self, _: &Request) {}
|
||||
|
||||
fn process_response(&mut self, _: &Response) {}
|
||||
|
||||
fn process_response_chunk(&mut self, _: Vec<u8>) {}
|
||||
|
||||
fn process_response_eof(&mut self, _: &Response) {}
|
||||
}
|
||||
|
||||
pub trait Action<Listener> {
|
||||
fn process(self, listener: &mut Listener);
|
||||
}
|
||||
|
@ -368,6 +380,9 @@ pub enum FetchChannels {
|
|||
event_sender: IpcSender<WebSocketNetworkEvent>,
|
||||
action_receiver: IpcReceiver<WebSocketDomAction>,
|
||||
},
|
||||
/// If the fetch is just being done to populate the cache,
|
||||
/// not because the data is needed now.
|
||||
Prefetch,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
|
|
|
@ -80,7 +80,7 @@ use msg::constellation_msg::{
|
|||
use net_traits::filemanager_thread::RelativePos;
|
||||
use net_traits::image::base::{Image, ImageMetadata};
|
||||
use net_traits::image_cache::{ImageCache, PendingImageId};
|
||||
use net_traits::request::{Request, RequestBuilder};
|
||||
use net_traits::request::{Referrer, Request, RequestBuilder};
|
||||
use net_traits::response::HttpsState;
|
||||
use net_traits::response::{Response, ResponseBody};
|
||||
use net_traits::storage_thread::StorageType;
|
||||
|
@ -456,6 +456,7 @@ unsafe_no_jsmanaged_fields!(Request);
|
|||
unsafe_no_jsmanaged_fields!(RequestBuilder);
|
||||
unsafe_no_jsmanaged_fields!(StyleSharedRwLock);
|
||||
unsafe_no_jsmanaged_fields!(USVString);
|
||||
unsafe_no_jsmanaged_fields!(Referrer);
|
||||
unsafe_no_jsmanaged_fields!(ReferrerPolicy);
|
||||
unsafe_no_jsmanaged_fields!(Response);
|
||||
unsafe_no_jsmanaged_fields!(ResponseBody);
|
||||
|
|
|
@ -53,6 +53,7 @@ use html5ever::{LocalName, Prefix};
|
|||
use ipc_channel::ipc;
|
||||
use ipc_channel::router::ROUTER;
|
||||
use mime::{self, Mime};
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use net_traits::image::base::{Image, ImageMetadata};
|
||||
use net_traits::image_cache::UsePlaceholder;
|
||||
use net_traits::image_cache::{CanRequestImages, ImageCache, ImageOrMetadataAvailable};
|
||||
|
@ -61,6 +62,7 @@ use net_traits::request::RequestBuilder;
|
|||
use net_traits::{FetchMetadata, FetchResponseListener, FetchResponseMsg, NetworkError};
|
||||
use net_traits::{ResourceFetchTiming, ResourceTimingType};
|
||||
use num_traits::ToPrimitive;
|
||||
use servo_url::origin::ImmutableOrigin;
|
||||
use servo_url::origin::MutableOrigin;
|
||||
use servo_url::ServoUrl;
|
||||
use std::cell::{Cell, RefMut};
|
||||
|
@ -261,6 +263,17 @@ impl PreInvoke for ImageContext {
|
|||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
) -> RequestBuilder {
|
||||
RequestBuilder::new(img_url)
|
||||
.origin(origin)
|
||||
.pipeline_id(Some(pipeline_id))
|
||||
}
|
||||
|
||||
impl HTMLImageElement {
|
||||
/// Update the current image with a valid URL.
|
||||
fn fetch_image(&self, img_url: &ServoUrl) {
|
||||
|
@ -326,9 +339,11 @@ impl HTMLImageElement {
|
|||
}),
|
||||
);
|
||||
|
||||
let request = RequestBuilder::new(img_url.clone())
|
||||
.origin(document.origin().immutable().clone())
|
||||
.pipeline_id(Some(document.global().pipeline_id()));
|
||||
let request = image_fetch_request(
|
||||
img_url.clone(),
|
||||
document.origin().immutable().clone(),
|
||||
document.global().pipeline_id(),
|
||||
);
|
||||
|
||||
// This is a background load because the load blocker already fulfills the
|
||||
// purpose of delaying the document's load event.
|
||||
|
|
|
@ -32,12 +32,15 @@ use html5ever::{LocalName, Prefix};
|
|||
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::ReferrerPolicy;
|
||||
use net_traits::{FetchMetadata, FetchResponseListener, Metadata, NetworkError};
|
||||
use net_traits::{ResourceFetchTiming, ResourceTimingType};
|
||||
use servo_atoms::Atom;
|
||||
use servo_url::ImmutableOrigin;
|
||||
use servo_url::ServoUrl;
|
||||
use std::cell::Cell;
|
||||
use std::fs::File;
|
||||
|
@ -292,19 +295,18 @@ impl ResourceTimingListener for ClassicContext {
|
|||
|
||||
impl PreInvoke for ClassicContext {}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#fetch-a-classic-script>
|
||||
fn fetch_a_classic_script(
|
||||
script: &HTMLScriptElement,
|
||||
kind: ExternalScriptKind,
|
||||
/// Steps 1-2 of <https://html.spec.whatwg.org/multipage/#fetch-a-classic-script>
|
||||
// This function is also used to prefetch a script in `script::dom::servoparser::prefetch`.
|
||||
pub(crate) fn script_fetch_request(
|
||||
url: ServoUrl,
|
||||
cors_setting: Option<CorsSettings>,
|
||||
origin: ImmutableOrigin,
|
||||
pipeline_id: PipelineId,
|
||||
referrer: Referrer,
|
||||
referrer_policy: Option<ReferrerPolicy>,
|
||||
integrity_metadata: String,
|
||||
character_encoding: &'static Encoding,
|
||||
) {
|
||||
let doc = document_from_node(script);
|
||||
|
||||
// Step 1, 2.
|
||||
let request = RequestBuilder::new(url.clone())
|
||||
) -> RequestBuilder {
|
||||
RequestBuilder::new(url)
|
||||
.destination(Destination::Script)
|
||||
// https://html.spec.whatwg.org/multipage/#create-a-potential-cors-request
|
||||
// Step 1
|
||||
|
@ -318,11 +320,34 @@ fn fetch_a_classic_script(
|
|||
Some(CorsSettings::Anonymous) => CredentialsMode::CredentialsSameOrigin,
|
||||
_ => CredentialsMode::Include,
|
||||
})
|
||||
.origin(doc.origin().immutable().clone())
|
||||
.pipeline_id(Some(script.global().pipeline_id()))
|
||||
.referrer(Some(Referrer::ReferrerUrl(doc.url())))
|
||||
.referrer_policy(doc.get_referrer_policy())
|
||||
.integrity_metadata(integrity_metadata);
|
||||
.origin(origin)
|
||||
.pipeline_id(Some(pipeline_id))
|
||||
.referrer(Some(referrer))
|
||||
.referrer_policy(referrer_policy)
|
||||
.integrity_metadata(integrity_metadata)
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#fetch-a-classic-script>
|
||||
fn fetch_a_classic_script(
|
||||
script: &HTMLScriptElement,
|
||||
kind: ExternalScriptKind,
|
||||
url: ServoUrl,
|
||||
cors_setting: Option<CorsSettings>,
|
||||
integrity_metadata: String,
|
||||
character_encoding: &'static Encoding,
|
||||
) {
|
||||
let doc = document_from_node(script);
|
||||
|
||||
// Step 1, 2.
|
||||
let request = script_fetch_request(
|
||||
url.clone(),
|
||||
cors_setting,
|
||||
doc.origin().immutable().clone(),
|
||||
script.global().pipeline_id(),
|
||||
Referrer::ReferrerUrl(doc.url()),
|
||||
doc.get_referrer_policy(),
|
||||
integrity_metadata,
|
||||
);
|
||||
|
||||
// TODO: Step 3, Add custom steps to perform fetch
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ use tendril::stream::LossyDecoder;
|
|||
|
||||
mod async_html;
|
||||
mod html;
|
||||
mod prefetch;
|
||||
mod xml;
|
||||
|
||||
#[dom_struct]
|
||||
|
@ -101,6 +102,10 @@ pub struct ServoParser {
|
|||
aborted: Cell<bool>,
|
||||
/// <https://html.spec.whatwg.org/multipage/#script-created-parser>
|
||||
script_created_parser: bool,
|
||||
/// We do a quick-and-dirty parse of the input looking for resources to prefetch
|
||||
prefetch_tokenizer: DomRefCell<prefetch::Tokenizer>,
|
||||
#[ignore_malloc_size_of = "Defined in html5ever"]
|
||||
prefetch_input: DomRefCell<BufferQueue>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
|
@ -403,6 +408,8 @@ impl ServoParser {
|
|||
script_nesting_level: Default::default(),
|
||||
aborted: Default::default(),
|
||||
script_created_parser: kind == ParserKind::ScriptCreated,
|
||||
prefetch_tokenizer: DomRefCell::new(prefetch::Tokenizer::new(document)),
|
||||
prefetch_input: DomRefCell::new(BufferQueue::new()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -425,20 +432,50 @@ impl ServoParser {
|
|||
)
|
||||
}
|
||||
|
||||
fn push_tendril_input_chunk(&self, chunk: StrTendril) {
|
||||
if !chunk.is_empty() {
|
||||
// Per https://github.com/whatwg/html/issues/1495
|
||||
// stylesheets should not be loaded for documents
|
||||
// without browsing contexts.
|
||||
// https://github.com/whatwg/html/issues/1495#issuecomment-230334047
|
||||
// suggests that no content should be preloaded in such a case.
|
||||
// We're conservative, and only prefetch for documents
|
||||
// with browsing contexts.
|
||||
if self.document.browsing_context().is_some() {
|
||||
// Push the chunk into the prefetch input stream,
|
||||
// which is tokenized eagerly, to scan for resources
|
||||
// to prefetch. If the user script uses `document.write()`
|
||||
// to overwrite the network input, this prefetching may
|
||||
// have been wasted, but in most cases it won't.
|
||||
let mut prefetch_input = self.prefetch_input.borrow_mut();
|
||||
prefetch_input.push_back(chunk.clone());
|
||||
let _ = self.prefetch_tokenizer
|
||||
.borrow_mut()
|
||||
.feed(&mut *prefetch_input);
|
||||
}
|
||||
// Push the chunk into the network input stream,
|
||||
// which is tokenized lazily.
|
||||
self.network_input.borrow_mut().push_back(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
fn push_bytes_input_chunk(&self, chunk: Vec<u8>) {
|
||||
// For byte input, we convert it to text using the network decoder.
|
||||
let chunk = self
|
||||
.network_decoder
|
||||
.borrow_mut()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.decode(chunk);
|
||||
if !chunk.is_empty() {
|
||||
self.network_input.borrow_mut().push_back(chunk);
|
||||
}
|
||||
self.push_tendril_input_chunk(chunk);
|
||||
}
|
||||
|
||||
fn push_string_input_chunk(&self, chunk: String) {
|
||||
self.network_input.borrow_mut().push_back(chunk.into());
|
||||
// Convert the chunk to a tendril so cloning it isn't expensive.
|
||||
// The input has already been decoded as a string, so doesn't need
|
||||
// to be decoded by the network decoder again.
|
||||
let chunk = StrTendril::from(chunk);
|
||||
self.push_tendril_input_chunk(chunk);
|
||||
}
|
||||
|
||||
fn parse_sync(&self) {
|
||||
|
|
185
components/script/dom/servoparser/prefetch.rs
Normal file
185
components/script/dom/servoparser/prefetch.rs
Normal file
|
@ -0,0 +1,185 @@
|
|||
/* 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 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::htmlscriptelement::script_fetch_request;
|
||||
use crate::stylesheet_loader::stylesheet_fetch_request;
|
||||
use html5ever::buffer_queue::BufferQueue;
|
||||
use html5ever::tokenizer::Tag;
|
||||
use html5ever::tokenizer::TagKind;
|
||||
use html5ever::tokenizer::Token;
|
||||
use html5ever::tokenizer::TokenSink;
|
||||
use html5ever::tokenizer::TokenSinkResult;
|
||||
use html5ever::tokenizer::Tokenizer as HtmlTokenizer;
|
||||
use html5ever::tokenizer::TokenizerResult;
|
||||
use html5ever::Attribute;
|
||||
use html5ever::LocalName;
|
||||
use js::jsapi::JSTracer;
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use net_traits::request::CorsSettings;
|
||||
use net_traits::request::Referrer;
|
||||
use net_traits::CoreResourceMsg;
|
||||
use net_traits::FetchChannels;
|
||||
use net_traits::IpcSend;
|
||||
use net_traits::ReferrerPolicy;
|
||||
use net_traits::ResourceThreads;
|
||||
use servo_url::ImmutableOrigin;
|
||||
use servo_url::ServoUrl;
|
||||
|
||||
#[derive(JSTraceable, MallocSizeOf)]
|
||||
#[must_root]
|
||||
pub struct Tokenizer {
|
||||
#[ignore_malloc_size_of = "Defined in html5ever"]
|
||||
inner: HtmlTokenizer<PrefetchSink>,
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
unsafe impl JSTraceable for HtmlTokenizer<PrefetchSink> {
|
||||
unsafe fn trace(&self, trc: *mut JSTracer) {
|
||||
self.sink.trace(trc)
|
||||
}
|
||||
}
|
||||
|
||||
impl Tokenizer {
|
||||
pub fn new(document: &Document) -> Self {
|
||||
let sink = PrefetchSink {
|
||||
origin: document.origin().immutable().clone(),
|
||||
pipeline_id: document.global().pipeline_id(),
|
||||
base: document.url(),
|
||||
referrer: Referrer::ReferrerUrl(document.url()),
|
||||
referrer_policy: document.get_referrer_policy(),
|
||||
resource_threads: document.loader().resource_threads().clone(),
|
||||
// Initially we set prefetching to false, and only set it
|
||||
// true after the first script tag, since that is what will
|
||||
// block the main parser.
|
||||
prefetching: false,
|
||||
};
|
||||
let options = Default::default();
|
||||
let inner = HtmlTokenizer::new(sink, options);
|
||||
Tokenizer { inner }
|
||||
}
|
||||
|
||||
pub fn feed(&mut self, input: &mut BufferQueue) -> TokenizerResult<()> {
|
||||
self.inner.feed(input)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(JSTraceable)]
|
||||
struct PrefetchSink {
|
||||
origin: ImmutableOrigin,
|
||||
pipeline_id: PipelineId,
|
||||
base: ServoUrl,
|
||||
referrer: Referrer,
|
||||
referrer_policy: Option<ReferrerPolicy>,
|
||||
resource_threads: ResourceThreads,
|
||||
prefetching: bool,
|
||||
}
|
||||
|
||||
impl TokenSink for PrefetchSink {
|
||||
type Handle = ();
|
||||
fn process_token(&mut self, token: Token, _line_number: u64) -> TokenSinkResult<()> {
|
||||
if let Token::TagToken(ref tag) = token {
|
||||
match (tag.kind, &tag.name) {
|
||||
(TagKind::StartTag, local_name!("script")) if self.prefetching => {
|
||||
if let Some(url) = self.get_url(tag, local_name!("src")) {
|
||||
debug!("Prefetch script {}", url);
|
||||
let cors_setting = self.get_cors_settings(tag, local_name!("crossorigin"));
|
||||
let integrity_metadata = self
|
||||
.get_attr(tag, local_name!("integrity"))
|
||||
.map(|attr| String::from(&attr.value))
|
||||
.unwrap_or_default();
|
||||
let request = script_fetch_request(
|
||||
url,
|
||||
cors_setting,
|
||||
self.origin.clone(),
|
||||
self.pipeline_id,
|
||||
self.referrer.clone(),
|
||||
self.referrer_policy,
|
||||
integrity_metadata,
|
||||
);
|
||||
let _ = self
|
||||
.resource_threads
|
||||
.send(CoreResourceMsg::Fetch(request, FetchChannels::Prefetch));
|
||||
}
|
||||
// Don't prefetch inside script
|
||||
self.prefetching = false;
|
||||
},
|
||||
(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 _ = self
|
||||
.resource_threads
|
||||
.send(CoreResourceMsg::Fetch(request, FetchChannels::Prefetch));
|
||||
}
|
||||
},
|
||||
(TagKind::StartTag, local_name!("link")) if self.prefetching => {
|
||||
if let Some(rel) = self.get_attr(tag, local_name!("rel")) {
|
||||
if rel.value.eq_ignore_ascii_case("stylesheet") {
|
||||
if let Some(url) = self.get_url(tag, local_name!("href")) {
|
||||
debug!("Prefetch {} {}", tag.name, url);
|
||||
let cors_setting =
|
||||
self.get_cors_settings(tag, local_name!("crossorigin"));
|
||||
let integrity_metadata = self
|
||||
.get_attr(tag, local_name!("integrity"))
|
||||
.map(|attr| String::from(&attr.value))
|
||||
.unwrap_or_default();
|
||||
let request = stylesheet_fetch_request(
|
||||
url,
|
||||
cors_setting,
|
||||
self.origin.clone(),
|
||||
self.pipeline_id,
|
||||
self.referrer.clone(),
|
||||
self.referrer_policy,
|
||||
integrity_metadata,
|
||||
);
|
||||
let _ = self
|
||||
.resource_threads
|
||||
.send(CoreResourceMsg::Fetch(request, FetchChannels::Prefetch));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
(TagKind::EndTag, local_name!("script")) => {
|
||||
// After the first script tag, the main parser is blocked, so it's worth prefetching.
|
||||
self.prefetching = true;
|
||||
},
|
||||
(TagKind::StartTag, local_name!("base")) => {
|
||||
if let Some(url) = self.get_url(tag, local_name!("href")) {
|
||||
debug!("Setting base {}", url);
|
||||
self.base = url;
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
TokenSinkResult::Continue
|
||||
}
|
||||
}
|
||||
|
||||
impl PrefetchSink {
|
||||
fn get_attr<'a>(&'a self, tag: &'a Tag, name: LocalName) -> Option<&'a Attribute> {
|
||||
tag.attrs.iter().find(|attr| attr.name.local == name)
|
||||
}
|
||||
|
||||
fn get_url(&self, tag: &Tag, name: LocalName) -> Option<ServoUrl> {
|
||||
self.get_attr(tag, name)
|
||||
.and_then(|attr| ServoUrl::parse_with_base(Some(&self.base), &attr.value).ok())
|
||||
}
|
||||
|
||||
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") {
|
||||
Some(CorsSettings::Anonymous)
|
||||
} else if crossorigin.value.eq_ignore_ascii_case("use-credentials") {
|
||||
Some(CorsSettings::UseCredentials)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@ use encoding_rs::UTF_8;
|
|||
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,
|
||||
};
|
||||
|
@ -31,6 +32,7 @@ use net_traits::{
|
|||
use net_traits::{ResourceFetchTiming, ResourceTimingType};
|
||||
use parking_lot::RwLock;
|
||||
use servo_arc::Arc;
|
||||
use servo_url::ImmutableOrigin;
|
||||
use servo_url::ServoUrl;
|
||||
use std::mem;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
@ -318,30 +320,51 @@ impl<'a> StylesheetLoader<'a> {
|
|||
document.increment_script_blocking_stylesheet_count();
|
||||
}
|
||||
|
||||
let request = RequestBuilder::new(url.clone())
|
||||
.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,
|
||||
})
|
||||
.origin(document.origin().immutable().clone())
|
||||
.pipeline_id(Some(self.elem.global().pipeline_id()))
|
||||
.referrer(Some(Referrer::ReferrerUrl(document.url())))
|
||||
.referrer_policy(referrer_policy)
|
||||
.integrity_metadata(integrity_metadata);
|
||||
let request = stylesheet_fetch_request(
|
||||
url.clone(),
|
||||
cors_setting,
|
||||
document.origin().immutable().clone(),
|
||||
self.elem.global().pipeline_id(),
|
||||
Referrer::ReferrerUrl(document.url()),
|
||||
referrer_policy,
|
||||
integrity_metadata,
|
||||
);
|
||||
|
||||
document.fetch_async(LoadType::Stylesheet(url), request, action_sender);
|
||||
}
|
||||
}
|
||||
|
||||
// This function is also used to prefetch a stylesheet in `script::dom::servoparser::prefetch`.
|
||||
pub(crate) fn stylesheet_fetch_request(
|
||||
url: ServoUrl,
|
||||
cors_setting: Option<CorsSettings>,
|
||||
origin: ImmutableOrigin,
|
||||
pipeline_id: PipelineId,
|
||||
referrer: Referrer,
|
||||
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,
|
||||
})
|
||||
.origin(origin)
|
||||
.pipeline_id(Some(pipeline_id))
|
||||
.referrer(Some(referrer))
|
||||
.referrer_policy(referrer_policy)
|
||||
.integrity_metadata(integrity_metadata)
|
||||
}
|
||||
|
||||
impl<'a> StyleStylesheetLoader for StylesheetLoader<'a> {
|
||||
/// Request a stylesheet after parsing a given `@import` rule, and return
|
||||
/// the constructed `@import` rule.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue