checkpoint - dynamic load inside of a module and classic script works.

This commit is contained in:
Josh Matthews 2020-05-25 13:15:19 -04:00 committed by CYBAI
parent 0c7f08f743
commit 1aef31bb2f
6 changed files with 525 additions and 114 deletions

View file

@ -77,12 +77,13 @@ use hyper::Method;
use hyper::StatusCode; use hyper::StatusCode;
use indexmap::IndexMap; use indexmap::IndexMap;
use ipc_channel::ipc::{IpcReceiver, IpcSender}; use ipc_channel::ipc::{IpcReceiver, IpcSender};
use js::glue::{CallObjectTracer, CallValueTracer}; use js::glue::{CallObjectTracer, CallStringTracer, CallValueTracer};
use js::jsapi::{GCTraceKindToAscii, Heap, JSObject, JSTracer, JobQueue, TraceKind}; use js::jsapi::{GCTraceKindToAscii, Heap, JSObject, JSString, JSTracer, JobQueue, TraceKind};
use js::jsval::JSVal; use js::jsval::JSVal;
use js::rust::{GCMethods, Handle, Runtime}; use js::rust::{GCMethods, Handle, Runtime};
use js::typedarray::TypedArray; use js::typedarray::TypedArray;
use js::typedarray::TypedArrayElement; use js::typedarray::TypedArrayElement;
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use media::WindowGLContext; use media::WindowGLContext;
use metrics::{InteractiveMetrics, InteractiveWindow}; use metrics::{InteractiveMetrics, InteractiveWindow};
use mime::Mime; use mime::Mime;
@ -134,6 +135,7 @@ use std::borrow::Cow;
use std::cell::{Cell, RefCell, UnsafeCell}; use std::cell::{Cell, RefCell, UnsafeCell};
use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
use std::hash::{BuildHasher, Hash}; use std::hash::{BuildHasher, Hash};
use std::mem;
use std::ops::{Deref, DerefMut, Range}; use std::ops::{Deref, DerefMut, Range};
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
@ -251,6 +253,18 @@ pub fn trace_object(tracer: *mut JSTracer, description: &str, obj: &Heap<*mut JS
} }
} }
/// Trace a `JSString`.
pub fn trace_string(tracer: *mut JSTracer, description: &str, s: &Heap<*mut JSString>) {
unsafe {
trace!("tracing {}", description);
CallStringTracer(
tracer,
s.ptr.get() as *mut _,
GCTraceKindToAscii(TraceKind::String),
);
}
}
unsafe impl<T: JSTraceable> JSTraceable for Rc<T> { unsafe impl<T: JSTraceable> JSTraceable for Rc<T> {
unsafe fn trace(&self, trc: *mut JSTracer) { unsafe fn trace(&self, trc: *mut JSTracer) {
(**self).trace(trc) (**self).trace(trc)
@ -322,6 +336,15 @@ unsafe impl JSTraceable for Heap<*mut JSObject> {
} }
} }
unsafe impl JSTraceable for Heap<*mut JSString> {
unsafe fn trace(&self, trc: *mut JSTracer) {
if self.get().is_null() {
return;
}
trace_string(trc, "heap string", self);
}
}
unsafe impl JSTraceable for Heap<JSVal> { unsafe impl JSTraceable for Heap<JSVal> {
unsafe fn trace(&self, trc: *mut JSTracer) { unsafe fn trace(&self, trc: *mut JSTracer) {
trace_jsval(trc, "heap value", self); trace_jsval(trc, "heap value", self);
@ -1066,6 +1089,17 @@ where
} }
} }
impl<T: JSTraceable + MallocSizeOf> MallocSizeOf for RootedTraceableBox<T> {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
// Briefly resurrect the real Box value so we can rely on the existing calculations.
// Then immediately forget about it again to avoid dropping the box.
let inner = unsafe { Box::from_raw(self.ptr) };
let size = inner.size_of(ops);
mem::forget(inner);
size
}
}
impl<T: JSTraceable + Default> Default for RootedTraceableBox<T> { impl<T: JSTraceable + Default> Default for RootedTraceableBox<T> {
fn default() -> RootedTraceableBox<T> { fn default() -> RootedTraceableBox<T> {
RootedTraceableBox::new(T::default()) RootedTraceableBox::new(T::default())

View file

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::cell::{DomRefCell, RefMut};
use crate::dom::bindings::codegen::Bindings::BroadcastChannelBinding::BroadcastChannelMethods; use crate::dom::bindings::codegen::Bindings::BroadcastChannelBinding::BroadcastChannelMethods;
use crate::dom::bindings::codegen::Bindings::EventSourceBinding::EventSourceBinding::EventSourceMethods; use crate::dom::bindings::codegen::Bindings::EventSourceBinding::EventSourceBinding::EventSourceMethods;
use crate::dom::bindings::codegen::Bindings::ImageBitmapBinding::{ use crate::dom::bindings::codegen::Bindings::ImageBitmapBinding::{
@ -51,7 +51,7 @@ use crate::dom::workerglobalscope::WorkerGlobalScope;
use crate::dom::workletglobalscope::WorkletGlobalScope; use crate::dom::workletglobalscope::WorkletGlobalScope;
use crate::microtask::{Microtask, MicrotaskQueue, UserMicrotask}; use crate::microtask::{Microtask, MicrotaskQueue, UserMicrotask};
use crate::realms::{enter_realm, AlreadyInRealm, InRealm}; use crate::realms::{enter_realm, AlreadyInRealm, InRealm};
use crate::script_module::ModuleTree; use crate::script_module::{DynamicModuleList, ModuleTree};
use crate::script_runtime::{ use crate::script_runtime::{
CommonScriptMsg, ContextForRequestInterrupt, JSContext as SafeJSContext, ScriptChan, ScriptPort, CommonScriptMsg, ContextForRequestInterrupt, JSContext as SafeJSContext, ScriptChan, ScriptPort,
}; };
@ -298,6 +298,9 @@ pub struct GlobalScope {
/// The stack of active group labels for the Console APIs. /// The stack of active group labels for the Console APIs.
console_group_stack: DomRefCell<Vec<DOMString>>, console_group_stack: DomRefCell<Vec<DOMString>>,
/// List of ongoing dynamic module imports.
dynamic_modules: DomRefCell<DynamicModuleList>,
} }
/// A wrapper for glue-code between the ipc router and the event-loop. /// A wrapper for glue-code between the ipc router and the event-loop.
@ -748,6 +751,7 @@ impl GlobalScope {
frozen_supported_performance_entry_types: DomRefCell::new(Default::default()), frozen_supported_performance_entry_types: DomRefCell::new(Default::default()),
https_state: Cell::new(HttpsState::None), https_state: Cell::new(HttpsState::None),
console_group_stack: DomRefCell::new(Vec::new()), console_group_stack: DomRefCell::new(Vec::new()),
dynamic_modules: DomRefCell::new(DynamicModuleList::new()),
} }
} }
@ -2953,6 +2957,10 @@ impl GlobalScope {
pub(crate) fn pop_console_group(&self) { pub(crate) fn pop_console_group(&self) {
let _ = self.console_group_stack.borrow_mut().pop(); let _ = self.console_group_stack.borrow_mut().pop();
} }
pub(crate) fn dynamic_module_list(&self) -> RefMut<DynamicModuleList> {
self.dynamic_modules.borrow_mut()
}
} }
fn timestamp_in_ms(time: Timespec) -> u64 { fn timestamp_in_ms(time: Timespec) -> u64 {

View file

@ -28,7 +28,7 @@ use crate::dom::virtualmethods::VirtualMethods;
use crate::fetch::create_a_potential_cors_request; use crate::fetch::create_a_potential_cors_request;
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener}; use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
use crate::script_module::fetch_inline_module_script; use crate::script_module::fetch_inline_module_script;
use crate::script_module::{fetch_external_module_script, ModuleOwner}; use crate::script_module::{fetch_external_module_script, ModuleOwner, ScriptFetchOptions};
use content_security_policy as csp; use content_security_policy as csp;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use encoding_rs::Encoding; use encoding_rs::Encoding;
@ -37,8 +37,9 @@ use ipc_channel::ipc;
use ipc_channel::router::ROUTER; use ipc_channel::router::ROUTER;
use js::jsval::UndefinedValue; use js::jsval::UndefinedValue;
use msg::constellation_msg::PipelineId; use msg::constellation_msg::PipelineId;
use net_traits::request::{CorsSettings, CredentialsMode, Destination, Referrer, RequestBuilder}; use net_traits::request::{
use net_traits::ReferrerPolicy; CorsSettings, CredentialsMode, Destination, ParserMetadata, RequestBuilder,
};
use net_traits::{FetchMetadata, FetchResponseListener, Metadata, NetworkError}; use net_traits::{FetchMetadata, FetchResponseListener, Metadata, NetworkError};
use net_traits::{ResourceFetchTiming, ResourceTimingType}; use net_traits::{ResourceFetchTiming, ResourceTimingType};
use servo_atoms::Atom; use servo_atoms::Atom;
@ -322,15 +323,22 @@ pub(crate) fn script_fetch_request(
cors_setting: Option<CorsSettings>, cors_setting: Option<CorsSettings>,
origin: ImmutableOrigin, origin: ImmutableOrigin,
pipeline_id: PipelineId, pipeline_id: PipelineId,
referrer: Referrer, options: ScriptFetchOptions,
referrer_policy: Option<ReferrerPolicy>,
integrity_metadata: String,
) -> RequestBuilder { ) -> RequestBuilder {
create_a_potential_cors_request(url, Destination::Script, cors_setting, None, referrer) // We intentionally ignore options' credentials_mode member for classic scripts.
.origin(origin) // The mode is initialized by create_a_potential_cors_request.
.pipeline_id(Some(pipeline_id)) create_a_potential_cors_request(
.referrer_policy(referrer_policy) url,
.integrity_metadata(integrity_metadata) Destination::Script,
cors_setting,
None,
options.referrer,
)
.origin(origin)
.pipeline_id(Some(pipeline_id))
.parser_metadata(options.parser_metadata)
.integrity_metadata(options.integrity_metadata.clone())
.referrer_policy(options.referrer_policy)
} }
/// <https://html.spec.whatwg.org/multipage/#fetch-a-classic-script> /// <https://html.spec.whatwg.org/multipage/#fetch-a-classic-script>
@ -339,7 +347,7 @@ fn fetch_a_classic_script(
kind: ExternalScriptKind, kind: ExternalScriptKind,
url: ServoUrl, url: ServoUrl,
cors_setting: Option<CorsSettings>, cors_setting: Option<CorsSettings>,
integrity_metadata: String, options: ScriptFetchOptions,
character_encoding: &'static Encoding, character_encoding: &'static Encoding,
) { ) {
let doc = document_from_node(script); let doc = document_from_node(script);
@ -350,9 +358,7 @@ fn fetch_a_classic_script(
cors_setting, cors_setting,
doc.origin().immutable().clone(), doc.origin().immutable().clone(),
script.global().pipeline_id(), script.global().pipeline_id(),
script.global().get_referrer(), options,
doc.get_referrer_policy(),
integrity_metadata,
); );
// TODO: Step 3, Add custom steps to perform fetch // TODO: Step 3, Add custom steps to perform fetch
@ -400,7 +406,7 @@ impl HTMLScriptElement {
let was_parser_inserted = self.parser_inserted.get(); let was_parser_inserted = self.parser_inserted.get();
self.parser_inserted.set(false); self.parser_inserted.set(false);
// Step 3. // Step 4.
let element = self.upcast::<Element>(); let element = self.upcast::<Element>();
let r#async = element.has_attribute(&local_name!("async")); let r#async = element.has_attribute(&local_name!("async"));
// Note: confusingly, this is done if the element does *not* have an "async" attribute. // Note: confusingly, this is done if the element does *not* have an "async" attribute.
@ -408,13 +414,13 @@ impl HTMLScriptElement {
self.non_blocking.set(true); self.non_blocking.set(true);
} }
// Step 4-5. // Step 5-6.
let text = self.Text(); let text = self.Text();
if text.is_empty() && !element.has_attribute(&local_name!("src")) { if text.is_empty() && !element.has_attribute(&local_name!("src")) {
return; return;
} }
// Step 6. // Step 7.
if !self.upcast::<Node>().is_connected() { if !self.upcast::<Node>().is_connected() {
return; return;
} }
@ -432,26 +438,26 @@ impl HTMLScriptElement {
self.non_blocking.set(false); self.non_blocking.set(false);
} }
// Step 9. // Step 10.
self.already_started.set(true); self.already_started.set(true);
// Step 10. // Step 12.
let doc = document_from_node(self); let doc = document_from_node(self);
if self.parser_inserted.get() && &*self.parser_document != &*doc { if self.parser_inserted.get() && &*self.parser_document != &*doc {
return; return;
} }
// Step 11. // Step 13.
if !doc.is_scripting_enabled() { if !doc.is_scripting_enabled() {
return; return;
} }
// Step 12 // Step 14
if element.has_attribute(&local_name!("nomodule")) && script_type == ScriptType::Classic { if element.has_attribute(&local_name!("nomodule")) && script_type == ScriptType::Classic {
return; return;
} }
// Step 13. // Step 15.
if !element.has_attribute(&local_name!("src")) && if !element.has_attribute(&local_name!("src")) &&
doc.should_elements_inline_type_behavior_be_blocked( doc.should_elements_inline_type_behavior_be_blocked(
&element, &element,
@ -463,7 +469,7 @@ impl HTMLScriptElement {
return; return;
} }
// Step 14. // Step 16.
if script_type == ScriptType::Classic { if script_type == ScriptType::Classic {
let for_attribute = element.get_attribute(&ns!(), &local_name!("for")); let for_attribute = element.get_attribute(&ns!(), &local_name!("for"));
let event_attribute = element.get_attribute(&ns!(), &local_name!("event")); let event_attribute = element.get_attribute(&ns!(), &local_name!("event"));
@ -485,31 +491,31 @@ impl HTMLScriptElement {
} }
} }
// Step 15. // Step 17.
let encoding = element let encoding = element
.get_attribute(&ns!(), &local_name!("charset")) .get_attribute(&ns!(), &local_name!("charset"))
.and_then(|charset| Encoding::for_label(charset.value().as_bytes())) .and_then(|charset| Encoding::for_label(charset.value().as_bytes()))
.unwrap_or_else(|| doc.encoding()); .unwrap_or_else(|| doc.encoding());
// Step 16. // Step 18.
let cors_setting = cors_setting_for_element(element); let cors_setting = cors_setting_for_element(element);
// Step 17. // Step 19.
let credentials_mode = match script_type { let module_credentials_mode = match script_type {
ScriptType::Classic => None, ScriptType::Classic => CredentialsMode::CredentialsSameOrigin,
ScriptType::Module => Some(reflect_cross_origin_attribute(element).map_or( ScriptType::Module => reflect_cross_origin_attribute(element).map_or(
CredentialsMode::CredentialsSameOrigin, CredentialsMode::CredentialsSameOrigin,
|attr| match &*attr { |attr| match &*attr {
"use-credentials" => CredentialsMode::Include, "use-credentials" => CredentialsMode::Include,
"anonymous" => CredentialsMode::CredentialsSameOrigin, "anonymous" => CredentialsMode::CredentialsSameOrigin,
_ => CredentialsMode::CredentialsSameOrigin, _ => CredentialsMode::CredentialsSameOrigin,
}, },
)), ),
}; };
// TODO: Step 18: Nonce. // TODO: Step 20: Nonce.
// Step 19: Integrity metadata. // Step 21: Integrity metadata.
let im_attribute = element.get_attribute(&ns!(), &local_name!("integrity")); let im_attribute = element.get_attribute(&ns!(), &local_name!("integrity"));
let integrity_val = im_attribute.as_ref().map(|a| a.value()); let integrity_val = im_attribute.as_ref().map(|a| a.value());
let integrity_metadata = match integrity_val { let integrity_metadata = match integrity_val {
@ -517,30 +523,43 @@ impl HTMLScriptElement {
None => "", None => "",
}; };
// TODO: Step 20: referrer policy // TODO: Step 22: referrer policy
// TODO: Step 21: parser state. // Step 23
let parser_metadata = if self.parser_inserted.get() {
ParserMetadata::ParserInserted
} else {
ParserMetadata::NotParserInserted
};
// TODO: Step 22: Fetch options // Step 24.
let options = ScriptFetchOptions {
cryptographic_nonce: "".into(),
integrity_metadata: integrity_metadata.to_owned(),
parser_metadata,
referrer: self.global().get_referrer(),
referrer_policy: doc.get_referrer_policy(),
credentials_mode: module_credentials_mode,
};
// TODO: Step 23: environment settings object. // TODO: Step 23: environment settings object.
let base_url = doc.base_url(); let base_url = doc.base_url();
if let Some(src) = element.get_attribute(&ns!(), &local_name!("src")) { if let Some(src) = element.get_attribute(&ns!(), &local_name!("src")) {
// Step 24. // Step 26.
// Step 24.1. // Step 26.1.
let src = src.value(); let src = src.value();
// Step 24.2. // Step 26.2.
if src.is_empty() { if src.is_empty() {
self.queue_error_event(); self.queue_error_event();
return; return;
} }
// Step 24.3: The "from an external file"" flag is stored in ScriptOrigin. // Step 26.3: The "from an external file"" flag is stored in ScriptOrigin.
// Step 24.4-24.5. // Step 26.4-26.5.
let url = match base_url.join(&src) { let url = match base_url.join(&src) {
Ok(url) => url, Ok(url) => url,
Err(_) => { Err(_) => {
@ -550,7 +569,7 @@ impl HTMLScriptElement {
}, },
}; };
// Step 24.6. // Step 26.6.
match script_type { match script_type {
ScriptType::Classic => { ScriptType::Classic => {
// Preparation for step 26. // Preparation for step 26.
@ -572,14 +591,7 @@ impl HTMLScriptElement {
}; };
// Step 24.6. // Step 24.6.
fetch_a_classic_script( fetch_a_classic_script(self, kind, url, cors_setting, options, encoding);
self,
kind,
url,
cors_setting,
integrity_metadata.to_owned(),
encoding,
);
// Step 23. // Step 23.
match kind { match kind {
@ -596,8 +608,7 @@ impl HTMLScriptElement {
ModuleOwner::Window(Trusted::new(self)), ModuleOwner::Window(Trusted::new(self)),
url.clone(), url.clone(),
Destination::Script, Destination::Script,
integrity_metadata.to_owned(), options,
credentials_mode.unwrap(),
); );
if !r#async && was_parser_inserted { if !r#async && was_parser_inserted {
@ -610,19 +621,19 @@ impl HTMLScriptElement {
}, },
} }
} else { } else {
// Step 25. // Step 27.
assert!(!text.is_empty()); assert!(!text.is_empty());
let text_rc = Rc::new(text); let text_rc = Rc::new(text);
// Step 25-1. & 25-2. // Step 27-1. & 27-2.
let result = Ok(ScriptOrigin::internal( let result = Ok(ScriptOrigin::internal(
Rc::clone(&text_rc), Rc::clone(&text_rc),
base_url.clone(), base_url.clone(),
script_type.clone(), script_type.clone(),
)); ));
// Step 25-2. // Step 27-2.
match script_type { match script_type {
ScriptType::Classic => { ScriptType::Classic => {
if was_parser_inserted && if was_parser_inserted &&
@ -630,10 +641,10 @@ impl HTMLScriptElement {
.map_or(false, |parser| parser.script_nesting_level() <= 1) && .map_or(false, |parser| parser.script_nesting_level() <= 1) &&
doc.get_script_blocking_stylesheets_count() > 0 doc.get_script_blocking_stylesheets_count() > 0
{ {
// Step 26.h: classic, has no src, was parser-inserted, is blocked on stylesheet. // Step 27.h: classic, has no src, was parser-inserted, is blocked on stylesheet.
doc.set_pending_parsing_blocking_script(self, Some(result)); doc.set_pending_parsing_blocking_script(self, Some(result));
} else { } else {
// Step 26.i: otherwise. // Step 27.i: otherwise.
self.execute(result); self.execute(result);
} }
}, },
@ -654,7 +665,7 @@ impl HTMLScriptElement {
text_rc, text_rc,
base_url.clone(), base_url.clone(),
self.id.clone(), self.id.clone(),
credentials_mode.unwrap(), options,
); );
}, },
} }

View file

@ -7,6 +7,7 @@ use crate::dom::bindings::trace::JSTraceable;
use crate::dom::document::{determine_policy_for_token, Document}; use crate::dom::document::{determine_policy_for_token, Document};
use crate::dom::htmlimageelement::{image_fetch_request, FromPictureOrSrcSet}; use crate::dom::htmlimageelement::{image_fetch_request, FromPictureOrSrcSet};
use crate::dom::htmlscriptelement::script_fetch_request; use crate::dom::htmlscriptelement::script_fetch_request;
use crate::script_module::ScriptFetchOptions;
use crate::stylesheet_loader::stylesheet_fetch_request; use crate::stylesheet_loader::stylesheet_fetch_request;
use html5ever::buffer_queue::BufferQueue; use html5ever::buffer_queue::BufferQueue;
use html5ever::tokenizer::states::RawKind; use html5ever::tokenizer::states::RawKind;
@ -22,6 +23,8 @@ use html5ever::LocalName;
use js::jsapi::JSTracer; use js::jsapi::JSTracer;
use msg::constellation_msg::PipelineId; use msg::constellation_msg::PipelineId;
use net_traits::request::CorsSettings; use net_traits::request::CorsSettings;
use net_traits::request::CredentialsMode;
use net_traits::request::ParserMetadata;
use net_traits::request::Referrer; use net_traits::request::Referrer;
use net_traits::CoreResourceMsg; use net_traits::CoreResourceMsg;
use net_traits::FetchChannels; use net_traits::FetchChannels;
@ -110,9 +113,14 @@ impl TokenSink for PrefetchSink {
cors_setting, cors_setting,
self.origin.clone(), self.origin.clone(),
self.pipeline_id, self.pipeline_id,
self.referrer.clone(), ScriptFetchOptions {
self.referrer_policy, referrer: self.referrer.clone(),
integrity_metadata, referrer_policy: self.referrer_policy,
integrity_metadata,
cryptographic_nonce: String::new(),
credentials_mode: CredentialsMode::CredentialsSameOrigin,
parser_metadata: ParserMetadata::ParserInserted,
},
); );
let _ = self let _ = self
.resource_threads .resource_threads

View file

@ -19,6 +19,7 @@ use crate::dom::bindings::settings_stack::AutoIncumbentScript;
use crate::dom::bindings::str::DOMString; use crate::dom::bindings::str::DOMString;
use crate::dom::bindings::trace::RootedTraceableBox; use crate::dom::bindings::trace::RootedTraceableBox;
use crate::dom::document::Document; use crate::dom::document::Document;
use crate::dom::dynamicmoduleowner::{DynamicModuleId, DynamicModuleOwner};
use crate::dom::element::Element; use crate::dom::element::Element;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::htmlscriptelement::{HTMLScriptElement, ScriptId}; use crate::dom::htmlscriptelement::{HTMLScriptElement, ScriptId};
@ -43,12 +44,12 @@ use ipc_channel::router::ROUTER;
use js::jsapi::Handle as RawHandle; use js::jsapi::Handle as RawHandle;
use js::jsapi::HandleObject; use js::jsapi::HandleObject;
use js::jsapi::HandleValue as RawHandleValue; use js::jsapi::HandleValue as RawHandleValue;
use js::jsapi::{CompileModule, ExceptionStackBehavior}; use js::jsapi::{CompileModule, ExceptionStackBehavior, FinishDynamicModuleImport};
use js::jsapi::{GetModuleResolveHook, JSRuntime, SetModuleResolveHook}; use js::jsapi::{GetModuleResolveHook, JSRuntime, SetModuleResolveHook};
use js::jsapi::{GetRequestedModules, SetModuleMetadataHook}; use js::jsapi::{GetRequestedModules, SetModuleMetadataHook};
use js::jsapi::{Heap, JSContext, JS_ClearPendingException, SetModulePrivate}; use js::jsapi::{Heap, JSContext, JS_ClearPendingException, SetModulePrivate};
use js::jsapi::{JSAutoRealm, JSObject, JSString}; use js::jsapi::{JSAutoRealm, JSObject, JSString};
use js::jsapi::{JS_DefineProperty4, JS_NewStringCopyN, JSPROP_ENUMERATE}; use js::jsapi::{JS_DefineProperty4, JS_IsExceptionPending, JS_NewStringCopyN, JSPROP_ENUMERATE};
use js::jsapi::{ModuleEvaluate, ModuleInstantiate}; use js::jsapi::{ModuleEvaluate, ModuleInstantiate};
use js::jsapi::{SetModuleDynamicImportHook, SetScriptPrivateReferenceHooks}; use js::jsapi::{SetModuleDynamicImportHook, SetScriptPrivateReferenceHooks};
use js::jsval::{JSVal, PrivateValue, UndefinedValue}; use js::jsval::{JSVal, PrivateValue, UndefinedValue};
@ -60,8 +61,10 @@ use js::rust::CompileOptionsWrapper;
use js::rust::{Handle, HandleValue, IntoHandle}; use js::rust::{Handle, HandleValue, IntoHandle};
use mime::Mime; use mime::Mime;
use net_traits::request::{CredentialsMode, Destination, ParserMetadata}; use net_traits::request::{CredentialsMode, Destination, ParserMetadata};
use net_traits::request::{RequestBuilder, RequestMode}; use net_traits::request::{Referrer, RequestBuilder, RequestMode};
use net_traits::{FetchMetadata, Metadata}; use net_traits::IpcSend;
use net_traits::{CoreResourceMsg, FetchChannels};
use net_traits::{FetchMetadata, Metadata, ReferrerPolicy};
use net_traits::{FetchResponseListener, NetworkError}; use net_traits::{FetchResponseListener, NetworkError};
use net_traits::{ResourceFetchTiming, ResourceTimingType}; use net_traits::{ResourceFetchTiming, ResourceTimingType};
use servo_url::ServoUrl; use servo_url::ServoUrl;
@ -71,6 +74,7 @@ use std::rc::Rc;
use std::str::FromStr; use std::str::FromStr;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use url::ParseError as UrlParseError; use url::ParseError as UrlParseError;
use uuid::Uuid;
#[allow(unsafe_code)] #[allow(unsafe_code)]
unsafe fn gen_type_error(global: &GlobalScope, string: String) -> RethrowError { unsafe fn gen_type_error(global: &GlobalScope, string: String) -> RethrowError {
@ -109,6 +113,8 @@ impl Clone for RethrowError {
struct ModuleScript { struct ModuleScript {
base_url: ServoUrl, base_url: ServoUrl,
options: ScriptFetchOptions,
owner: ModuleOwner,
} }
/// Identity for a module which will be /// Identity for a module which will be
@ -119,7 +125,7 @@ struct ModuleScript {
/// module identity so that we can get module tree /// module identity so that we can get module tree
/// from a descendant no matter the parent is an /// from a descendant no matter the parent is an
/// inline script or a external script /// inline script or a external script
#[derive(Clone, Eq, Hash, JSTraceable, PartialEq)] #[derive(Clone, Debug, Eq, Hash, JSTraceable, PartialEq)]
pub enum ModuleIdentity { pub enum ModuleIdentity {
ScriptId(ScriptId), ScriptId(ScriptId),
ModuleUrl(ServoUrl), ModuleUrl(ServoUrl),
@ -306,7 +312,7 @@ impl ModuleTree {
// We just leverage the power of Promise to run the task for `finish` the owner. // We just leverage the power of Promise to run the task for `finish` the owner.
// Thus, we will always `resolve` it and no need to register a callback for `reject` // Thus, we will always `resolve` it and no need to register a callback for `reject`
pub fn append_handler(&self, owner: ModuleOwner, module_identity: ModuleIdentity) { fn append_handler(&self, owner: ModuleOwner, module_identity: ModuleIdentity) {
let this = owner.clone(); let this = owner.clone();
let identity = module_identity.clone(); let identity = module_identity.clone();
@ -314,7 +320,43 @@ impl ModuleTree {
&owner.global(), &owner.global(),
Some(ModuleHandler::new(Box::new( Some(ModuleHandler::new(Box::new(
task!(fetched_resolve: move || { task!(fetched_resolve: move || {
this.notify_owner_to_finish(identity); this.notify_owner_to_finish(identity.clone());
}),
))),
None,
);
let realm = enter_realm(&*owner.global());
let comp = InRealm::Entered(&realm);
let _ais = AutoIncumbentScript::new(&*owner.global());
let mut promise = self.promise.borrow_mut();
match promise.as_ref() {
Some(promise) => promise.append_native_handler(&handler, comp),
None => {
let new_promise = Promise::new_in_current_realm(&owner.global(), comp);
new_promise.append_native_handler(&handler, comp);
*promise = Some(new_promise);
},
}
}
fn append_dynamic_module_handler(
&self,
owner: ModuleOwner,
module_identity: ModuleIdentity,
dynamic_module: RootedTraceableBox<DynamicModule>,
) {
let this = owner.clone();
let identity = module_identity.clone();
let module_id = owner.global().dynamic_module_list().push(dynamic_module);
let handler = PromiseNativeHandler::new(
&owner.global(),
Some(ModuleHandler::new(Box::new(
task!(fetched_resolve: move || {
this.finish_dynamic_module(identity, module_id);
}), }),
))), ))),
None, None,
@ -351,8 +393,10 @@ impl ModuleTree {
fn compile_module_script( fn compile_module_script(
&self, &self,
global: &GlobalScope, global: &GlobalScope,
owner: ModuleOwner,
module_script_text: Rc<DOMString>, module_script_text: Rc<DOMString>,
url: ServoUrl, url: ServoUrl,
options: ScriptFetchOptions,
) -> Result<ModuleObject, RethrowError> { ) -> Result<ModuleObject, RethrowError> {
let module: Vec<u16> = module_script_text.encode_utf16().collect(); let module: Vec<u16> = module_script_text.encode_utf16().collect();
@ -387,6 +431,8 @@ impl ModuleTree {
let module_script_data = Box::new(ModuleScript { let module_script_data = Box::new(ModuleScript {
base_url: url.clone(), base_url: url.clone(),
options,
owner,
}); });
SetModulePrivate( SetModulePrivate(
@ -640,7 +686,7 @@ impl ModuleTree {
&self, &self,
owner: &ModuleOwner, owner: &ModuleOwner,
destination: Destination, destination: Destination,
credentials_mode: CredentialsMode, options: &ScriptFetchOptions,
parent_identity: ModuleIdentity, parent_identity: ModuleIdentity,
) { ) {
debug!("Start to load dependencies of {}", self.url.clone()); debug!("Start to load dependencies of {}", self.url.clone());
@ -713,17 +759,18 @@ impl ModuleTree {
// Step 1. // Step 1.
assert!(visited_urls.get(&url).is_some()); assert!(visited_urls.get(&url).is_some());
let options = options.descendant_fetch_options();
// Step 2. // Step 2.
fetch_single_module_script( fetch_single_module_script(
owner.clone(), owner.clone(),
url.clone(), url.clone(),
visited_urls.clone(), visited_urls.clone(),
destination.clone(), destination.clone(),
ParserMetadata::NotParserInserted, options,
"".to_owned(), // integrity
credentials_mode.clone(),
Some(parent_identity.clone()), Some(parent_identity.clone()),
false, false,
None,
); );
} }
}, },
@ -822,10 +869,11 @@ impl Callback for ModuleHandler {
/// The owner of the module /// The owner of the module
/// It can be `worker` or `script` element /// It can be `worker` or `script` element
#[derive(Clone)] #[derive(Clone)]
pub enum ModuleOwner { pub(crate) enum ModuleOwner {
#[allow(dead_code)] #[allow(dead_code)]
Worker(TrustedWorkerAddress), Worker(TrustedWorkerAddress),
Window(Trusted<HTMLScriptElement>), Window(Trusted<HTMLScriptElement>),
DynamicModule(Trusted<DynamicModuleOwner>),
} }
impl ModuleOwner { impl ModuleOwner {
@ -833,12 +881,14 @@ impl ModuleOwner {
match &self { match &self {
ModuleOwner::Worker(worker) => (*worker.root().clone()).global(), ModuleOwner::Worker(worker) => (*worker.root().clone()).global(),
ModuleOwner::Window(script) => (*script.root()).global(), ModuleOwner::Window(script) => (*script.root()).global(),
ModuleOwner::DynamicModule(dynamic_module) => (*dynamic_module.root()).global(),
} }
} }
pub fn notify_owner_to_finish(&self, module_identity: ModuleIdentity) { pub fn notify_owner_to_finish(&self, module_identity: ModuleIdentity) {
match &self { match &self {
ModuleOwner::Worker(_) => unimplemented!(), ModuleOwner::Worker(_) => unimplemented!(),
ModuleOwner::DynamicModule(_) => unimplemented!(),
ModuleOwner::Window(script) => { ModuleOwner::Window(script) => {
let global = self.global(); let global = self.global();
@ -880,6 +930,80 @@ impl ModuleOwner {
}, },
} }
} }
#[allow(unsafe_code)]
/// <https://html.spec.whatwg.org/multipage/#hostimportmoduledynamically(referencingscriptormodule,-specifier,-promisecapability):fetch-an-import()-module-script-graph>
/// Step 6-9
pub fn finish_dynamic_module(
&self,
module_identity: ModuleIdentity,
dynamic_module_id: DynamicModuleId,
) {
let global = self.global();
let module = global.dynamic_module_list().remove(dynamic_module_id);
let cx = global.get_cx();
let module_tree = module_identity.get_module_tree(&global);
// In the timing of executing this `finish_dynamic_module` function,
// we've run `find_first_parse_error` which means we've had the highest
// priority error in the tree. So, we can just get both `network_error` and
// `rethrow_error` directly here.
let network_error = module_tree.get_network_error().borrow().as_ref().cloned();
let existing_rethrow_error = module_tree.get_rethrow_error().borrow().as_ref().cloned();
let execution_err = if network_error.is_none() && existing_rethrow_error.is_none() {
let record = module_tree
.get_record()
.borrow()
.as_ref()
.map(|record| record.handle());
if let Some(record) = record {
let evaluated = module_tree.execute_module(&global, record).err();
if let Some(exception) = evaluated.clone() {
module_tree.set_rethrow_error(exception);
}
evaluated
} else {
None
}
} else {
None
};
// Ensure any failures related to importing this dynamic module are immediately reported.
match (network_error, existing_rethrow_error, execution_err) {
(Some(_), _, _) => unsafe {
let err = gen_type_error(&global, "Dynamic import failed".to_owned());
JS_SetPendingException(*cx, err.handle(), ExceptionStackBehavior::Capture)
},
(None, _, Some(execution_err)) => unsafe {
JS_SetPendingException(*cx, execution_err.handle(), ExceptionStackBehavior::Capture)
},
(None, Some(rethrow_error), _) => unsafe {
JS_SetPendingException(*cx, rethrow_error.handle(), ExceptionStackBehavior::Capture)
},
// do nothing if there's no errors
(None, None, None) => {},
}
debug!("Finishing dynamic import for {:?}", module_identity);
unsafe {
FinishDynamicModuleImport(
*cx,
module.referencing_private.handle(),
module.specifier.handle(),
module.promise.reflector().get_jsobject().into_handle(),
);
assert!(!JS_IsExceptionPending(*cx));
}
return;
}
} }
/// The context required for asynchronously loading an external module script source. /// The context required for asynchronously loading an external module script source.
@ -894,8 +1018,8 @@ struct ModuleContext {
url: ServoUrl, url: ServoUrl,
/// Destination of current module context /// Destination of current module context
destination: Destination, destination: Destination,
/// Credentials Mode of current module context /// Options for the current script fetch
credentials_mode: CredentialsMode, options: ScriptFetchOptions,
/// Indicates whether the request failed, and why /// Indicates whether the request failed, and why
status: Result<(), NetworkError>, status: Result<(), NetworkError>,
/// Timing object for this resource /// Timing object for this resource
@ -1005,8 +1129,10 @@ impl FetchResponseListener for ModuleContext {
let compiled_module = module_tree.compile_module_script( let compiled_module = module_tree.compile_module_script(
&global, &global,
self.owner.clone(),
resp_mod_script.text(), resp_mod_script.text(),
self.url.clone(), self.url.clone(),
self.options.clone(),
); );
match compiled_module { match compiled_module {
@ -1020,7 +1146,7 @@ impl FetchResponseListener for ModuleContext {
module_tree.fetch_module_descendants( module_tree.fetch_module_descendants(
&self.owner, &self.owner,
self.destination.clone(), self.destination.clone(),
self.credentials_mode.clone(), &self.options,
ModuleIdentity::ModuleUrl(self.url.clone()), ModuleIdentity::ModuleUrl(self.url.clone()),
); );
}, },
@ -1066,8 +1192,159 @@ pub unsafe fn EnsureModuleHooksInitialized(rt: *mut JSRuntime) {
SetModuleResolveHook(rt, Some(HostResolveImportedModule)); SetModuleResolveHook(rt, Some(HostResolveImportedModule));
SetModuleMetadataHook(rt, Some(HostPopulateImportMeta)); SetModuleMetadataHook(rt, Some(HostPopulateImportMeta));
SetScriptPrivateReferenceHooks(rt, None, None); SetScriptPrivateReferenceHooks(rt, None, None);
SetModuleDynamicImportHook(rt, Some(host_import_module_dynamically));
}
SetModuleDynamicImportHook(rt, None); #[allow(unsafe_code)]
/// <https://html.spec.whatwg.org/multipage/#hostimportmoduledynamically(referencingscriptormodule,-specifier,-promisecapability)>
pub unsafe extern "C" fn host_import_module_dynamically(
cx: *mut JSContext,
reference_private: RawHandleValue,
specifier: RawHandle<*mut JSString>,
promise: RawHandle<*mut JSObject>,
) -> bool {
// Step 1.
let cx = SafeJSContext::from_ptr(cx);
let in_realm_proof = AlreadyInRealm::assert_for_cx(cx);
let global_scope = GlobalScope::from_context(*cx, InRealm::Already(&in_realm_proof));
// Step 2.
let mut base_url = global_scope.api_base_url();
// Step 3.
let mut options = ScriptFetchOptions::default_classic_script(&global_scope);
// Step 4.
let module_data = module_script_from_reference_private(&reference_private);
if let Some(data) = module_data {
base_url = data.base_url.clone();
options = data.options.descendant_fetch_options();
}
let promise = Promise::new_with_js_promise(Handle::from_raw(promise), cx);
//Step 5 & 6.
if let Err(e) = fetch_an_import_module_script_graph(
&global_scope,
specifier,
reference_private,
base_url,
options,
promise,
) {
JS_SetPendingException(*cx, e.handle(), ExceptionStackBehavior::Capture);
return false;
}
true
}
#[derive(Clone)]
/// <https://html.spec.whatwg.org/multipage/#script-fetch-options>
pub(crate) struct ScriptFetchOptions {
pub referrer: Referrer,
pub integrity_metadata: String,
pub credentials_mode: CredentialsMode,
pub cryptographic_nonce: String,
pub parser_metadata: ParserMetadata,
pub referrer_policy: Option<ReferrerPolicy>,
}
impl ScriptFetchOptions {
/// <https://html.spec.whatwg.org/multipage/#default-classic-script-fetch-options>
fn default_classic_script(global: &GlobalScope) -> ScriptFetchOptions {
Self {
cryptographic_nonce: String::new(),
integrity_metadata: String::new(),
referrer: global.get_referrer(),
parser_metadata: ParserMetadata::NotParserInserted,
credentials_mode: CredentialsMode::CredentialsSameOrigin,
referrer_policy: None,
}
}
/// <https://html.spec.whatwg.org/multipage/#descendant-script-fetch-options>
fn descendant_fetch_options(&self) -> ScriptFetchOptions {
Self {
referrer: self.referrer.clone(),
integrity_metadata: String::new(),
cryptographic_nonce: self.cryptographic_nonce.clone(),
credentials_mode: self.credentials_mode,
parser_metadata: self.parser_metadata,
referrer_policy: self.referrer_policy,
}
}
}
#[allow(unsafe_code)]
unsafe fn module_script_from_reference_private<'a>(
reference_private: &RawHandle<JSVal>,
) -> Option<&ModuleScript> {
if reference_private.get().is_undefined() {
return None;
}
(reference_private.get().to_private() as *const ModuleScript).as_ref()
}
/// <https://html.spec.whatwg.org/multipage/#fetch-an-import()-module-script-graph>
#[allow(unsafe_code)]
fn fetch_an_import_module_script_graph(
global: &GlobalScope,
specifier: RawHandle<*mut JSString>,
reference_private: RawHandleValue,
base_url: ServoUrl,
options: ScriptFetchOptions,
promise: Rc<Promise>,
) -> Result<(), RethrowError> {
// Step 1.
let url = ModuleTree::resolve_module_specifier(*global.get_cx(), &base_url, specifier);
// Step 2.
if url.is_err() {
let specifier_error =
unsafe { gen_type_error(&global, "Wrong module specifier".to_owned()) };
return Err(specifier_error);
}
let dynamic_module_id = DynamicModuleId(Uuid::new_v4());
// Step 3.
let owner = match unsafe { module_script_from_reference_private(&reference_private) } {
Some(module_data) => module_data.owner.clone(),
None => ModuleOwner::DynamicModule(Trusted::new(&DynamicModuleOwner::new(
global,
promise.clone(),
dynamic_module_id.clone(),
))),
};
let dynamic_module = RootedTraceableBox::new(DynamicModule {
promise,
specifier: Heap::default(),
referencing_private: Heap::default(),
id: dynamic_module_id,
});
dynamic_module.specifier.set(specifier.get());
dynamic_module
.referencing_private
.set(reference_private.get());
let url = url.unwrap();
let mut visited_urls = HashSet::new();
visited_urls.insert(url.clone());
fetch_single_module_script(
owner,
url,
visited_urls,
Destination::Script,
options,
None,
true,
Some(dynamic_module),
);
Ok(())
} }
#[allow(unsafe_code, non_snake_case)] #[allow(unsafe_code, non_snake_case)]
@ -1085,7 +1362,7 @@ unsafe extern "C" fn HostResolveImportedModule(
let mut base_url = global_scope.api_base_url(); let mut base_url = global_scope.api_base_url();
// Step 3. // Step 3.
let module_data = (reference_private.to_private() as *const ModuleScript).as_ref(); let module_data = module_script_from_reference_private(&reference_private);
if let Some(data) = module_data { if let Some(data) = module_data {
base_url = data.base_url.clone(); base_url = data.base_url.clone();
} }
@ -1131,7 +1408,7 @@ unsafe extern "C" fn HostPopulateImportMeta(
let global_scope = GlobalScope::from_context(cx, InRealm::Already(&in_realm_proof)); let global_scope = GlobalScope::from_context(cx, InRealm::Already(&in_realm_proof));
// Step 2. // Step 2.
let base_url = match (reference_private.to_private() as *const ModuleScript).as_ref() { let base_url = match module_script_from_reference_private(&reference_private) {
Some(module_data) => module_data.base_url.clone(), Some(module_data) => module_data.base_url.clone(),
None => global_scope.api_base_url(), None => global_scope.api_base_url(),
}; };
@ -1153,12 +1430,11 @@ unsafe extern "C" fn HostPopulateImportMeta(
} }
/// https://html.spec.whatwg.org/multipage/#fetch-a-module-script-tree /// https://html.spec.whatwg.org/multipage/#fetch-a-module-script-tree
pub fn fetch_external_module_script( pub(crate) fn fetch_external_module_script(
owner: ModuleOwner, owner: ModuleOwner,
url: ServoUrl, url: ServoUrl,
destination: Destination, destination: Destination,
integrity_metadata: String, options: ScriptFetchOptions,
credentials_mode: CredentialsMode,
) { ) {
let mut visited_urls = HashSet::new(); let mut visited_urls = HashSet::new();
visited_urls.insert(url.clone()); visited_urls.insert(url.clone());
@ -1169,25 +1445,71 @@ pub fn fetch_external_module_script(
url, url,
visited_urls, visited_urls,
destination, destination,
ParserMetadata::NotParserInserted, options,
integrity_metadata,
credentials_mode,
None, None,
true, true,
); None,
)
}
#[derive(JSTraceable, MallocSizeOf)]
#[unrooted_must_root_lint::must_root]
pub(crate) struct DynamicModuleList {
requests: Vec<RootedTraceableBox<DynamicModule>>,
#[ignore_malloc_size_of = "Define in uuid"]
next_id: DynamicModuleId,
}
impl DynamicModuleList {
pub fn new() -> Self {
Self {
requests: vec![],
next_id: DynamicModuleId(Uuid::new_v4()),
}
}
fn push(&mut self, mut module: RootedTraceableBox<DynamicModule>) -> DynamicModuleId {
let id = self.next_id;
self.next_id = DynamicModuleId(Uuid::new_v4());
module.id = id;
self.requests.push(module);
id
}
fn remove(&mut self, id: DynamicModuleId) -> RootedTraceableBox<DynamicModule> {
let index = self
.requests
.iter()
.position(|module| module.id == id)
.expect("missing dynamic module");
self.requests.remove(index)
}
}
#[unrooted_must_root_lint::must_root]
#[derive(JSTraceable, MallocSizeOf)]
struct DynamicModule {
#[ignore_malloc_size_of = "Rc is hard"]
promise: Rc<Promise>,
#[ignore_malloc_size_of = "GC types are hard"]
specifier: Heap<*mut JSString>,
#[ignore_malloc_size_of = "GC types are hard"]
referencing_private: Heap<JSVal>,
#[ignore_malloc_size_of = "Defined in uuid"]
id: DynamicModuleId,
} }
/// https://html.spec.whatwg.org/multipage/#fetch-a-single-module-script /// https://html.spec.whatwg.org/multipage/#fetch-a-single-module-script
pub fn fetch_single_module_script( fn fetch_single_module_script(
owner: ModuleOwner, owner: ModuleOwner,
url: ServoUrl, url: ServoUrl,
visited_urls: HashSet<ServoUrl>, visited_urls: HashSet<ServoUrl>,
destination: Destination, destination: Destination,
parser_metadata: ParserMetadata, options: ScriptFetchOptions,
integrity_metadata: String,
credentials_mode: CredentialsMode,
parent_identity: Option<ModuleIdentity>, parent_identity: Option<ModuleIdentity>,
top_level_module_fetch: bool, top_level_module_fetch: bool,
dynamic_module: Option<RootedTraceableBox<DynamicModule>>,
) { ) {
{ {
// Step 1. // Step 1.
@ -1201,8 +1523,16 @@ pub fn fetch_single_module_script(
debug!("Meet a fetched url {} and its status is {:?}", url, status); debug!("Meet a fetched url {} and its status is {:?}", url, status);
if top_level_module_fetch { match dynamic_module {
module_tree.append_handler(owner.clone(), ModuleIdentity::ModuleUrl(url.clone())); Some(module) => module_tree.append_dynamic_module_handler(
owner.clone(),
ModuleIdentity::ModuleUrl(url.clone()),
module,
),
None if top_level_module_fetch => module_tree
.append_handler(owner.clone(), ModuleIdentity::ModuleUrl(url.clone())),
// do nothing if it's neither a dynamic module nor a top level module
None => {},
} }
if let Some(parent_identity) = parent_identity { if let Some(parent_identity) = parent_identity {
@ -1230,8 +1560,17 @@ pub fn fetch_single_module_script(
let module_tree = ModuleTree::new(url.clone(), is_external, visited_urls); let module_tree = ModuleTree::new(url.clone(), is_external, visited_urls);
module_tree.set_status(ModuleStatus::Fetching); module_tree.set_status(ModuleStatus::Fetching);
if top_level_module_fetch { match dynamic_module {
module_tree.append_handler(owner.clone(), ModuleIdentity::ModuleUrl(url.clone())); Some(module) => module_tree.append_dynamic_module_handler(
owner.clone(),
ModuleIdentity::ModuleUrl(url.clone()),
module,
),
None if top_level_module_fetch => {
module_tree.append_handler(owner.clone(), ModuleIdentity::ModuleUrl(url.clone()))
},
// do nothing if it's neither a dynamic module nor a top level module
None => {},
} }
if let Some(parent_identity) = parent_identity { if let Some(parent_identity) = parent_identity {
@ -1252,7 +1591,7 @@ pub fn fetch_single_module_script(
}; };
let document: Option<DomRoot<Document>> = match &owner { let document: Option<DomRoot<Document>> = match &owner {
ModuleOwner::Worker(_) => None, ModuleOwner::Worker(_) | ModuleOwner::DynamicModule(_) => None,
ModuleOwner::Window(script) => Some(document_from_node(&*script.root())), ModuleOwner::Window(script) => Some(document_from_node(&*script.root())),
}; };
@ -1260,9 +1599,9 @@ pub fn fetch_single_module_script(
let request = RequestBuilder::new(url.clone(), global.get_referrer()) let request = RequestBuilder::new(url.clone(), global.get_referrer())
.destination(destination.clone()) .destination(destination.clone())
.origin(global.origin().immutable().clone()) .origin(global.origin().immutable().clone())
.parser_metadata(parser_metadata) .parser_metadata(options.parser_metadata)
.integrity_metadata(integrity_metadata.clone()) .integrity_metadata(options.integrity_metadata.clone())
.credentials_mode(credentials_mode) .credentials_mode(options.credentials_mode)
.mode(mode); .mode(mode);
let context = Arc::new(Mutex::new(ModuleContext { let context = Arc::new(Mutex::new(ModuleContext {
@ -1271,7 +1610,7 @@ pub fn fetch_single_module_script(
metadata: None, metadata: None,
url: url.clone(), url: url.clone(),
destination: destination.clone(), destination: destination.clone(),
credentials_mode: credentials_mode.clone(), options,
status: Ok(()), status: Ok(()),
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource), resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
})); }));
@ -1293,26 +1632,41 @@ pub fn fetch_single_module_script(
}), }),
); );
if let Some(doc) = document { match document {
doc.fetch_async(LoadType::Script(url), request, action_sender); Some(doc) => doc.fetch_async(LoadType::Script(url), request, action_sender),
None => {
let _ = global
.resource_threads()
.sender()
.send(CoreResourceMsg::Fetch(
request,
FetchChannels::ResponseMsg(action_sender, None),
))
.unwrap();
},
} }
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
/// https://html.spec.whatwg.org/multipage/#fetch-an-inline-module-script-graph /// https://html.spec.whatwg.org/multipage/#fetch-an-inline-module-script-graph
pub fn fetch_inline_module_script( pub(crate) fn fetch_inline_module_script(
owner: ModuleOwner, owner: ModuleOwner,
module_script_text: Rc<DOMString>, module_script_text: Rc<DOMString>,
url: ServoUrl, url: ServoUrl,
script_id: ScriptId, script_id: ScriptId,
credentials_mode: CredentialsMode, options: ScriptFetchOptions,
) { ) {
let global = owner.global(); let global = owner.global();
let is_external = false; let is_external = false;
let module_tree = ModuleTree::new(url.clone(), is_external, HashSet::new()); let module_tree = ModuleTree::new(url.clone(), is_external, HashSet::new());
let compiled_module = let compiled_module = module_tree.compile_module_script(
module_tree.compile_module_script(&global, module_script_text, url.clone()); &global,
owner.clone(),
module_script_text,
url.clone(),
options.clone(),
);
match compiled_module { match compiled_module {
Ok(record) => { Ok(record) => {
@ -1333,7 +1687,7 @@ pub fn fetch_inline_module_script(
module_tree.fetch_module_descendants( module_tree.fetch_module_descendants(
&owner, &owner,
Destination::Script, Destination::Script,
credentials_mode, &options,
ModuleIdentity::ScriptId(script_id), ModuleIdentity::ScriptId(script_id),
); );
}, },

View file

@ -123,10 +123,6 @@ skip: true
skip: false skip: false
[json-module] [json-module]
skip: true skip: true
[module]
skip: false
[dynamic-import]
skip: true
[moving-between-documents] [moving-between-documents]
skip: true skip: true
[js] [js]