diff options
author | bors-servo <servo-ops@mozilla.com> | 2020-07-19 09:29:50 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-19 09:29:50 -0400 |
commit | 086556e706bbb65790e7fb9a918bf7e8051171e0 (patch) | |
tree | fa6ad280c0e2d2be02e0a75071514cb9337c3d46 | |
parent | ccff00742f42a62b3004f27fdd02cfa0b388d745 (diff) | |
parent | 419cd53561e4abaadc78b2cfea55e0bf0edfb36c (diff) | |
download | servo-086556e706bbb65790e7fb9a918bf7e8051171e0.tar.gz servo-086556e706bbb65790e7fb9a918bf7e8051171e0.zip |
Auto merge of #27026 - CYBAI:dynamic-module, r=jdm
Introduce dynamic module
---
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix #25439
- [x] There are tests for these changes
36 files changed, 813 insertions, 440 deletions
diff --git a/Cargo.lock b/Cargo.lock index b20275dddf3..687e507b21d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3572,7 +3572,7 @@ dependencies = [ [[package]] name = "mozjs" version = "0.13.0" -source = "git+https://github.com/servo/rust-mozjs#0caf5549cddbb34ad16abf35fb6bfbff824a4d14" +source = "git+https://github.com/servo/rust-mozjs#716dede8811ed525d9aab1e44cea392609b35d0a" dependencies = [ "cc", "lazy_static", diff --git a/components/script/devtools.rs b/components/script/devtools.rs index 2aad7d101c7..cb5dfa27b7f 100644 --- a/components/script/devtools.rs +++ b/components/script/devtools.rs @@ -16,6 +16,7 @@ use crate::dom::element::Element; use crate::dom::globalscope::GlobalScope; use crate::dom::node::{window_from_node, Node, ShadowIncluding}; use crate::realms::enter_realm; +use crate::script_module::ScriptFetchOptions; use crate::script_thread::Documents; use devtools_traits::{AutoMargins, ComputedNodeLayout, TimelineMarkerType}; use devtools_traits::{EvaluateJSReply, Modification, NodeInfo, TimelineMarker}; @@ -34,7 +35,14 @@ pub fn handle_evaluate_js(global: &GlobalScope, eval: String, reply: IpcSender<E let cx = global.get_cx(); let _ac = enter_realm(global); rooted!(in(*cx) let mut rval = UndefinedValue()); - global.evaluate_script_on_global_with_result(&eval, "<eval>", rval.handle_mut(), 1); + global.evaluate_script_on_global_with_result( + &eval, + "<eval>", + rval.handle_mut(), + 1, + ScriptFetchOptions::default_classic_script(&global), + global.api_base_url(), + ); if rval.is_undefined() { EvaluateJSReply::VoidValue diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index ec8974b6cbd..6c6e0ed6618 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -47,6 +47,10 @@ DOMInterfaces = { 'inRealms': ['PromiseAttribute', 'PromiseNativeHandler'], }, +'DynamicModuleOwner': { + 'inRealms': ['PromiseAttribute'], +}, + 'URL': { 'weakReferenceable': True, }, diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 121e96b4a0e..92d6ebcb7bf 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -77,12 +77,13 @@ use hyper::Method; use hyper::StatusCode; use indexmap::IndexMap; use ipc_channel::ipc::{IpcReceiver, IpcSender}; -use js::glue::{CallObjectTracer, CallValueTracer}; -use js::jsapi::{GCTraceKindToAscii, Heap, JSObject, JSTracer, JobQueue, TraceKind}; +use js::glue::{CallObjectTracer, CallStringTracer, CallValueTracer}; +use js::jsapi::{GCTraceKindToAscii, Heap, JSObject, JSString, JSTracer, JobQueue, TraceKind}; use js::jsval::JSVal; use js::rust::{GCMethods, Handle, Runtime}; use js::typedarray::TypedArray; use js::typedarray::TypedArrayElement; +use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use media::WindowGLContext; use metrics::{InteractiveMetrics, InteractiveWindow}; use mime::Mime; @@ -94,7 +95,7 @@ use msg::constellation_msg::{ServiceWorkerId, ServiceWorkerRegistrationId}; use net_traits::filemanager_thread::RelativePos; use net_traits::image::base::{Image, ImageMetadata}; use net_traits::image_cache::{ImageCache, PendingImageId}; -use net_traits::request::{Referrer, Request, RequestBuilder}; +use net_traits::request::{CredentialsMode, ParserMetadata, Referrer, Request, RequestBuilder}; use net_traits::response::HttpsState; use net_traits::response::{Response, ResponseBody}; use net_traits::storage_thread::StorageType; @@ -134,6 +135,7 @@ use std::borrow::Cow; use std::cell::{Cell, RefCell, UnsafeCell}; use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; use std::hash::{BuildHasher, Hash}; +use std::mem; use std::ops::{Deref, DerefMut, Range}; use std::path::PathBuf; use std::rc::Rc; @@ -252,6 +254,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 fn trace(&self, trc: *mut JSTracer) { (**self).trace(trc) @@ -323,6 +337,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 fn trace(&self, trc: *mut JSTracer) { trace_jsval(trc, "heap value", self); @@ -534,6 +557,8 @@ unsafe_no_jsmanaged_fields!(StyleSharedRwLock); unsafe_no_jsmanaged_fields!(USVString); unsafe_no_jsmanaged_fields!(Referrer); unsafe_no_jsmanaged_fields!(ReferrerPolicy); +unsafe_no_jsmanaged_fields!(CredentialsMode); +unsafe_no_jsmanaged_fields!(ParserMetadata); unsafe_no_jsmanaged_fields!(Response); unsafe_no_jsmanaged_fields!(ResponseBody); unsafe_no_jsmanaged_fields!(ResourceThreads); @@ -1068,6 +1093,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> { fn default() -> RootedTraceableBox<T> { RootedTraceableBox::new(T::default()) diff --git a/components/script/dom/dynamicmoduleowner.rs b/components/script/dom/dynamicmoduleowner.rs new file mode 100644 index 00000000000..50fc71fbd79 --- /dev/null +++ b/components/script/dom/dynamicmoduleowner.rs @@ -0,0 +1,54 @@ +/* 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::codegen::Bindings::DynamicModuleOwnerBinding::DynamicModuleOwnerMethods; +use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; +use crate::dom::bindings::root::DomRoot; +use crate::dom::globalscope::GlobalScope; +use crate::dom::promise::Promise; +use dom_struct::dom_struct; +use std::rc::Rc; +use uuid::Uuid; + +/// An unique id for dynamic module +#[derive(Clone, Copy, Debug, Eq, Hash, JSTraceable, PartialEq)] +pub struct DynamicModuleId(pub Uuid); + +#[dom_struct] +pub struct DynamicModuleOwner { + reflector_: Reflector, + + #[ignore_malloc_size_of = "Rc"] + promise: Rc<Promise>, + + /// Unique id for each dynamic module + #[ignore_malloc_size_of = "Defined in uuid"] + id: DynamicModuleId, +} + +impl DynamicModuleOwner { + #[allow(unrooted_must_root)] + fn new_inherited(promise: Rc<Promise>, id: DynamicModuleId) -> Self { + DynamicModuleOwner { + reflector_: Reflector::new(), + promise, + id, + } + } + + #[allow(unrooted_must_root)] + pub fn new(global: &GlobalScope, promise: Rc<Promise>, id: DynamicModuleId) -> DomRoot<Self> { + reflect_dom_object( + Box::new(DynamicModuleOwner::new_inherited(promise, id)), + global, + ) + } +} + +impl DynamicModuleOwnerMethods for DynamicModuleOwner { + // https://html.spec.whatwg.org/multipage/#integration-with-the-javascript-module-system:import() + fn Promise(&self) -> Rc<Promise> { + self.promise.clone() + } +} diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index 5db5942fe0d..a6427224882 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -2,7 +2,7 @@ * 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::cell::DomRefCell; +use crate::dom::bindings::cell::{DomRefCell, RefMut}; use crate::dom::bindings::codegen::Bindings::BroadcastChannelBinding::BroadcastChannelMethods; use crate::dom::bindings::codegen::Bindings::EventSourceBinding::EventSourceBinding::EventSourceMethods; use crate::dom::bindings::codegen::Bindings::GPUValidationErrorBinding::GPUError; @@ -55,7 +55,8 @@ use crate::dom::workerglobalscope::WorkerGlobalScope; use crate::dom::workletglobalscope::WorkletGlobalScope; use crate::microtask::{Microtask, MicrotaskQueue, UserMicrotask}; use crate::realms::{enter_realm, AlreadyInRealm, InRealm}; -use crate::script_module::ModuleTree; +use crate::script_module::{DynamicModuleList, ModuleTree}; +use crate::script_module::{ModuleScript, ScriptFetchOptions}; use crate::script_runtime::{ CommonScriptMsg, ContextForRequestInterrupt, JSContext as SafeJSContext, ScriptChan, ScriptPort, }; @@ -81,13 +82,16 @@ use embedder_traits::EmbedderMsg; use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::router::ROUTER; use js::glue::{IsWrapper, UnwrapObjectDynamic}; +use js::jsapi::Compile1; +use js::jsapi::SetScriptPrivate; use js::jsapi::{CurrentGlobalOrNull, GetNonCCWObjectGlobal}; use js::jsapi::{HandleObject, Heap}; use js::jsapi::{JSContext, JSObject}; +use js::jsval::PrivateValue; use js::jsval::{JSVal, UndefinedValue}; use js::panic::maybe_resume_unwind; use js::rust::transform_str_to_source_text; -use js::rust::wrappers::Evaluate2; +use js::rust::wrappers::{JS_ExecuteScript, JS_GetScriptPrivate}; use js::rust::{get_object_class, CompileOptionsWrapper, ParentRuntime, Runtime}; use js::rust::{HandleValue, MutableHandleValue}; use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL}; @@ -306,6 +310,9 @@ pub struct GlobalScope { /// The stack of active group labels for the Console APIs. 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. @@ -757,6 +764,7 @@ impl GlobalScope { frozen_supported_performance_entry_types: DomRefCell::new(Default::default()), https_state: Cell::new(HttpsState::None), console_group_stack: DomRefCell::new(Vec::new()), + dynamic_modules: DomRefCell::new(DynamicModuleList::new()), } } @@ -2537,8 +2545,21 @@ impl GlobalScope { } /// Evaluate JS code on this global scope. - pub fn evaluate_js_on_global_with_result(&self, code: &str, rval: MutableHandleValue) -> bool { - self.evaluate_script_on_global_with_result(code, "", rval, 1) + pub fn evaluate_js_on_global_with_result( + &self, + code: &str, + rval: MutableHandleValue, + fetch_options: ScriptFetchOptions, + script_base_url: ServoUrl, + ) -> bool { + self.evaluate_script_on_global_with_result( + code, + "", + rval, + 1, + fetch_options, + script_base_url, + ) } /// Evaluate a JS script on this global scope. @@ -2549,6 +2570,8 @@ impl GlobalScope { filename: &str, rval: MutableHandleValue, line_number: u32, + fetch_options: ScriptFetchOptions, + script_base_url: ServoUrl, ) -> bool { let metadata = profile_time::TimerMetadata { url: if filename.is_empty() { @@ -2570,26 +2593,59 @@ impl GlobalScope { let ar = enter_realm(&*self); let _aes = AutoEntryScript::new(self); - let options = - unsafe { CompileOptionsWrapper::new(*cx, filename.as_ptr(), line_number) }; - - debug!("evaluating Dom string"); - let result = unsafe { - Evaluate2( - *cx, - options.ptr, - &mut transform_str_to_source_text(code), - rval, - ) - }; - if !result { - debug!("error evaluating Dom string"); - unsafe { report_pending_exception(*cx, true, InRealm::Entered(&ar)) }; - } + unsafe { + let options = CompileOptionsWrapper::new(*cx, filename.as_ptr(), line_number); - maybe_resume_unwind(); - result + debug!("compiling Dom string"); + rooted!(in(*cx) let compiled_script = + Compile1( + *cx, + options.ptr, + &mut transform_str_to_source_text(code), + ) + ); + + if compiled_script.is_null() { + debug!("error compiling Dom string"); + report_pending_exception(*cx, true, InRealm::Entered(&ar)); + return false; + } + + rooted!(in(*cx) let mut script_private = UndefinedValue()); + JS_GetScriptPrivate(*compiled_script, script_private.handle_mut()); + + // When `ScriptPrivate` for the compiled script is undefined, + // we need to set it so that it can be used in dynamic import context. + if script_private.is_undefined() { + debug!("Set script private for {}", script_base_url); + + let module_script_data = Rc::new(ModuleScript::new( + script_base_url, + fetch_options, + // We can't initialize an module owner here because + // the executing context of script might be different + // from the dynamic import script's executing context. + None, + )); + + SetScriptPrivate( + *compiled_script, + &PrivateValue(Rc::into_raw(module_script_data) as *const _), + ); + } + + debug!("evaluating Dom string"); + let result = JS_ExecuteScript(*cx, compiled_script.handle(), rval); + + if !result { + debug!("error evaluating Dom string"); + report_pending_exception(*cx, true, InRealm::Entered(&ar)); + } + + maybe_resume_unwind(); + result + } }, ) } @@ -2991,6 +3047,10 @@ impl GlobalScope { pub(crate) fn pop_console_group(&self) { 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 { diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs index b70e83d5a33..2ad7444f7f4 100644 --- a/components/script/dom/htmlscriptelement.rs +++ b/components/script/dom/htmlscriptelement.rs @@ -28,7 +28,7 @@ use crate::dom::virtualmethods::VirtualMethods; use crate::fetch::create_a_potential_cors_request; use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener}; 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 dom_struct::dom_struct; use encoding_rs::Encoding; @@ -37,8 +37,9 @@ 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}; -use net_traits::ReferrerPolicy; +use net_traits::request::{ + CorsSettings, CredentialsMode, Destination, ParserMetadata, RequestBuilder, +}; use net_traits::{FetchMetadata, FetchResponseListener, Metadata, NetworkError}; use net_traits::{ResourceFetchTiming, ResourceTimingType}; use servo_atoms::Atom; @@ -155,24 +156,37 @@ pub struct ScriptOrigin { text: Rc<DOMString>, url: ServoUrl, external: bool, + fetch_options: ScriptFetchOptions, type_: ScriptType, } impl ScriptOrigin { - pub fn internal(text: Rc<DOMString>, url: ServoUrl, type_: ScriptType) -> ScriptOrigin { + pub fn internal( + text: Rc<DOMString>, + url: ServoUrl, + fetch_options: ScriptFetchOptions, + type_: ScriptType, + ) -> ScriptOrigin { ScriptOrigin { text: text, url: url, external: false, + fetch_options, type_, } } - pub fn external(text: Rc<DOMString>, url: ServoUrl, type_: ScriptType) -> ScriptOrigin { + pub fn external( + text: Rc<DOMString>, + url: ServoUrl, + fetch_options: ScriptFetchOptions, + type_: ScriptType, + ) -> ScriptOrigin { ScriptOrigin { text: text, url: url, external: true, + fetch_options, type_, } } @@ -201,6 +215,8 @@ struct ClassicContext { url: ServoUrl, /// Indicates whether the request failed, and why status: Result<(), NetworkError>, + /// The fetch options of the script + fetch_options: ScriptFetchOptions, /// Timing object for this resource resource_timing: ResourceFetchTiming, } @@ -261,6 +277,7 @@ impl FetchResponseListener for ClassicContext { ScriptOrigin::external( Rc::new(DOMString::from(source_text)), metadata.final_url, + self.fetch_options.clone(), ScriptType::Classic, ) }); @@ -322,15 +339,22 @@ pub(crate) fn script_fetch_request( cors_setting: Option<CorsSettings>, origin: ImmutableOrigin, pipeline_id: PipelineId, - referrer: Referrer, - referrer_policy: Option<ReferrerPolicy>, - integrity_metadata: String, + options: ScriptFetchOptions, ) -> RequestBuilder { - create_a_potential_cors_request(url, Destination::Script, cors_setting, None, referrer) - .origin(origin) - .pipeline_id(Some(pipeline_id)) - .referrer_policy(referrer_policy) - .integrity_metadata(integrity_metadata) + // We intentionally ignore options' credentials_mode member for classic scripts. + // The mode is initialized by create_a_potential_cors_request. + create_a_potential_cors_request( + url, + 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> @@ -339,7 +363,7 @@ fn fetch_a_classic_script( kind: ExternalScriptKind, url: ServoUrl, cors_setting: Option<CorsSettings>, - integrity_metadata: String, + options: ScriptFetchOptions, character_encoding: &'static Encoding, ) { let doc = document_from_node(script); @@ -350,9 +374,7 @@ fn fetch_a_classic_script( cors_setting, doc.origin().immutable().clone(), script.global().pipeline_id(), - script.global().get_referrer(), - doc.get_referrer_policy(), - integrity_metadata, + options.clone(), ); // TODO: Step 3, Add custom steps to perform fetch @@ -365,6 +387,7 @@ fn fetch_a_classic_script( metadata: None, url: url.clone(), status: Ok(()), + fetch_options: options, resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource), })); @@ -400,7 +423,7 @@ impl HTMLScriptElement { let was_parser_inserted = self.parser_inserted.get(); self.parser_inserted.set(false); - // Step 3. + // Step 4. let element = self.upcast::<Element>(); let asynch = element.has_attribute(&local_name!("async")); // Note: confusingly, this is done if the element does *not* have an "async" attribute. @@ -408,13 +431,13 @@ impl HTMLScriptElement { self.non_blocking.set(true); } - // Step 4-5. + // Step 5-6. let text = self.Text(); if text.is_empty() && !element.has_attribute(&local_name!("src")) { return; } - // Step 6. + // Step 7. if !self.upcast::<Node>().is_connected() { return; } @@ -432,26 +455,26 @@ impl HTMLScriptElement { self.non_blocking.set(false); } - // Step 9. + // Step 10. self.already_started.set(true); - // Step 10. + // Step 12. let doc = document_from_node(self); if self.parser_inserted.get() && &*self.parser_document != &*doc { return; } - // Step 11. + // Step 13. if !doc.is_scripting_enabled() { return; } - // Step 12 + // Step 14 if element.has_attribute(&local_name!("nomodule")) && script_type == ScriptType::Classic { return; } - // Step 13. + // Step 15. if !element.has_attribute(&local_name!("src")) && doc.should_elements_inline_type_behavior_be_blocked( &element, @@ -463,7 +486,7 @@ impl HTMLScriptElement { return; } - // Step 14. + // Step 16. if script_type == ScriptType::Classic { let for_attribute = element.get_attribute(&ns!(), &local_name!("for")); let event_attribute = element.get_attribute(&ns!(), &local_name!("event")); @@ -485,31 +508,31 @@ impl HTMLScriptElement { } } - // Step 15. + // Step 17. let encoding = element .get_attribute(&ns!(), &local_name!("charset")) .and_then(|charset| Encoding::for_label(charset.value().as_bytes())) .unwrap_or_else(|| doc.encoding()); - // Step 16. + // Step 18. let cors_setting = cors_setting_for_element(element); - // Step 17. - let credentials_mode = match script_type { - ScriptType::Classic => None, - ScriptType::Module => Some(reflect_cross_origin_attribute(element).map_or( + // Step 19. + let module_credentials_mode = match script_type { + ScriptType::Classic => CredentialsMode::CredentialsSameOrigin, + ScriptType::Module => reflect_cross_origin_attribute(element).map_or( CredentialsMode::CredentialsSameOrigin, |attr| match &*attr { "use-credentials" => CredentialsMode::Include, "anonymous" => 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 integrity_val = im_attribute.as_ref().map(|a| a.value()); let integrity_metadata = match integrity_val { @@ -517,30 +540,43 @@ impl HTMLScriptElement { 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. let base_url = doc.base_url(); 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(); - // Step 24.2. + // Step 26.2. if src.is_empty() { self.queue_error_event(); 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) { Ok(url) => url, Err(_) => { @@ -550,7 +586,7 @@ impl HTMLScriptElement { }, }; - // Step 24.6. + // Step 26.6. match script_type { ScriptType::Classic => { // Preparation for step 26. @@ -572,14 +608,7 @@ impl HTMLScriptElement { }; // Step 24.6. - fetch_a_classic_script( - self, - kind, - url, - cors_setting, - integrity_metadata.to_owned(), - encoding, - ); + fetch_a_classic_script(self, kind, url, cors_setting, options, encoding); // Step 23. match kind { @@ -596,8 +625,7 @@ impl HTMLScriptElement { ModuleOwner::Window(Trusted::new(self)), url.clone(), Destination::Script, - integrity_metadata.to_owned(), - credentials_mode.unwrap(), + options, ); if !asynch && was_parser_inserted { @@ -610,19 +638,20 @@ impl HTMLScriptElement { }, } } else { - // Step 25. + // Step 27. assert!(!text.is_empty()); let text_rc = Rc::new(text); - // Step 25-1. & 25-2. + // Step 27-1. & 27-2. let result = Ok(ScriptOrigin::internal( Rc::clone(&text_rc), base_url.clone(), + options.clone(), script_type.clone(), )); - // Step 25-2. + // Step 27-2. match script_type { ScriptType::Classic => { if was_parser_inserted && @@ -630,10 +659,10 @@ impl HTMLScriptElement { .map_or(false, |parser| parser.script_nesting_level() <= 1) && 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)); } else { - // Step 26.i: otherwise. + // Step 27.i: otherwise. self.execute(result); } }, @@ -654,7 +683,7 @@ impl HTMLScriptElement { text_rc, base_url.clone(), self.id.clone(), - credentials_mode.unwrap(), + options, ); }, } @@ -855,6 +884,8 @@ impl HTMLScriptElement { script.url.as_str(), rval.handle_mut(), line_number, + script.fetch_options.clone(), + script.url.clone(), ); } diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index 3047ce2c983..698cff979c9 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -295,6 +295,7 @@ pub mod domrectreadonly; pub mod domstringlist; pub mod domstringmap; pub mod domtokenlist; +pub mod dynamicmoduleowner; pub mod element; pub mod errorevent; pub mod event; diff --git a/components/script/dom/servoparser/prefetch.rs b/components/script/dom/servoparser/prefetch.rs index 6d7d6c24e2c..4de7e765b0c 100644 --- a/components/script/dom/servoparser/prefetch.rs +++ b/components/script/dom/servoparser/prefetch.rs @@ -7,6 +7,7 @@ use crate::dom::bindings::trace::JSTraceable; 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::script_module::ScriptFetchOptions; use crate::stylesheet_loader::stylesheet_fetch_request; use html5ever::buffer_queue::BufferQueue; use html5ever::tokenizer::states::RawKind; @@ -22,6 +23,8 @@ use html5ever::LocalName; use js::jsapi::JSTracer; use msg::constellation_msg::PipelineId; use net_traits::request::CorsSettings; +use net_traits::request::CredentialsMode; +use net_traits::request::ParserMetadata; use net_traits::request::Referrer; use net_traits::CoreResourceMsg; use net_traits::FetchChannels; @@ -110,9 +113,14 @@ impl TokenSink for PrefetchSink { cors_setting, self.origin.clone(), self.pipeline_id, - self.referrer.clone(), - self.referrer_policy, - integrity_metadata, + ScriptFetchOptions { + referrer: self.referrer.clone(), + referrer_policy: self.referrer_policy, + integrity_metadata, + cryptographic_nonce: String::new(), + credentials_mode: CredentialsMode::CredentialsSameOrigin, + parser_metadata: ParserMetadata::ParserInserted, + }, ); let _ = self .resource_threads diff --git a/components/script/dom/userscripts.rs b/components/script/dom/userscripts.rs index 4e9cc59d27f..a004e0fe6b8 100644 --- a/components/script/dom/userscripts.rs +++ b/components/script/dom/userscripts.rs @@ -7,6 +7,7 @@ use crate::dom::bindings::refcounted::Trusted; use crate::dom::globalscope::GlobalScope; use crate::dom::htmlheadelement::HTMLHeadElement; use crate::dom::node::document_from_node; +use crate::script_module::ScriptFetchOptions; use js::jsval::UndefinedValue; use std::fs::{read_dir, File}; use std::io::Read; @@ -38,13 +39,15 @@ pub fn load_script(head: &HTMLHeadElement) { let mut contents = vec![]; f.read_to_end(&mut contents).unwrap(); let script_text = String::from_utf8_lossy(&contents); - win.upcast::<GlobalScope>() - .evaluate_script_on_global_with_result( - &script_text, - &file.to_string_lossy(), - rval.handle_mut(), - 1, - ); + let global = win.upcast::<GlobalScope>(); + global.evaluate_script_on_global_with_result( + &script_text, + &file.to_string_lossy(), + rval.handle_mut(), + 1, + ScriptFetchOptions::default_classic_script(&global), + global.api_base_url(), + ); } })); } diff --git a/components/script/dom/webidls/DynamicModuleOwner.webidl b/components/script/dom/webidls/DynamicModuleOwner.webidl new file mode 100644 index 00000000000..924481d491b --- /dev/null +++ b/components/script/dom/webidls/DynamicModuleOwner.webidl @@ -0,0 +1,13 @@ +/* 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/. */ + +/** + * This is defined for [`Dynamic Module`](https://html.spec.whatwg.org/multipage/#fetch-an-import()-module-script-graph) + * so that we can hold a traceable owner for those dynamic modules which don't hold a owner. + */ + +[NoInterfaceObject, Exposed=Window] +interface DynamicModuleOwner { + readonly attribute Promise<any> promise; +}; diff --git a/components/script/dom/workletglobalscope.rs b/components/script/dom/workletglobalscope.rs index 88b8a13708b..47e6315c940 100644 --- a/components/script/dom/workletglobalscope.rs +++ b/components/script/dom/workletglobalscope.rs @@ -11,6 +11,7 @@ use crate::dom::paintworkletglobalscope::PaintWorkletTask; use crate::dom::testworkletglobalscope::TestWorkletGlobalScope; use crate::dom::testworkletglobalscope::TestWorkletTask; use crate::dom::worklet::WorkletExecutor; +use crate::script_module::ScriptFetchOptions; use crate::script_runtime::JSContext; use crate::script_thread::MainThreadScriptMsg; use crossbeam_channel::Sender; @@ -88,10 +89,14 @@ impl WorkletGlobalScope { /// Evaluate a JS script in this global. pub fn evaluate_js(&self, script: &str) -> bool { - debug!("Evaluating Dom."); + debug!("Evaluating Dom in a worklet."); rooted!(in (*self.globalscope.get_cx()) let mut rval = UndefinedValue()); - self.globalscope - .evaluate_js_on_global_with_result(&*script, rval.handle_mut()) + self.globalscope.evaluate_js_on_global_with_result( + &*script, + rval.handle_mut(), + ScriptFetchOptions::default_classic_script(&self.globalscope), + self.globalscope.api_base_url(), + ) } /// Register a paint worklet to the script thread. diff --git a/components/script/script_module.rs b/components/script/script_module.rs index 5e8ce59564a..55b4c0d3562 100644 --- a/components/script/script_module.rs +++ b/components/script/script_module.rs @@ -19,6 +19,7 @@ use crate::dom::bindings::settings_stack::AutoIncumbentScript; use crate::dom::bindings::str::DOMString; use crate::dom::bindings::trace::RootedTraceableBox; use crate::dom::document::Document; +use crate::dom::dynamicmoduleowner::{DynamicModuleId, DynamicModuleOwner}; use crate::dom::element::Element; use crate::dom::globalscope::GlobalScope; use crate::dom::htmlscriptelement::{HTMLScriptElement, ScriptId}; @@ -43,12 +44,13 @@ use ipc_channel::router::ROUTER; use js::jsapi::Handle as RawHandle; use js::jsapi::HandleObject; use js::jsapi::HandleValue as RawHandleValue; -use js::jsapi::{CompileModule, ExceptionStackBehavior}; +use js::jsapi::Value; +use js::jsapi::{CompileModule, ExceptionStackBehavior, FinishDynamicModuleImport}; use js::jsapi::{GetModuleResolveHook, JSRuntime, SetModuleResolveHook}; use js::jsapi::{GetRequestedModules, SetModuleMetadataHook}; use js::jsapi::{Heap, JSContext, JS_ClearPendingException, SetModulePrivate}; 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::{SetModuleDynamicImportHook, SetScriptPrivateReferenceHooks}; use js::jsval::{JSVal, PrivateValue, UndefinedValue}; @@ -60,17 +62,21 @@ use js::rust::CompileOptionsWrapper; use js::rust::{Handle, HandleValue, IntoHandle}; use mime::Mime; use net_traits::request::{CredentialsMode, Destination, ParserMetadata}; -use net_traits::request::{RequestBuilder, RequestMode}; -use net_traits::{FetchMetadata, Metadata}; +use net_traits::request::{Referrer, RequestBuilder, RequestMode}; +use net_traits::IpcSend; +use net_traits::{CoreResourceMsg, FetchChannels}; +use net_traits::{FetchMetadata, Metadata, ReferrerPolicy}; use net_traits::{FetchResponseListener, NetworkError}; use net_traits::{ResourceFetchTiming, ResourceTimingType}; use servo_url::ServoUrl; use std::collections::{HashMap, HashSet}; use std::ffi; +use std::mem; use std::rc::Rc; use std::str::FromStr; use std::sync::{Arc, Mutex}; use url::ParseError as UrlParseError; +use uuid::Uuid; #[allow(unsafe_code)] unsafe fn gen_type_error(global: &GlobalScope, string: String) -> RethrowError { @@ -107,8 +113,24 @@ impl Clone for RethrowError { } } -struct ModuleScript { +pub(crate) struct ModuleScript { base_url: ServoUrl, + options: ScriptFetchOptions, + owner: Option<ModuleOwner>, +} + +impl ModuleScript { + pub fn new( + base_url: ServoUrl, + options: ScriptFetchOptions, + owner: Option<ModuleOwner>, + ) -> Self { + ModuleScript { + base_url, + options, + owner, + } + } } /// Identity for a module which will be @@ -119,7 +141,7 @@ struct ModuleScript { /// module identity so that we can get module tree /// from a descendant no matter the parent is an /// inline script or a external script -#[derive(Clone, Eq, Hash, JSTraceable, PartialEq)] +#[derive(Clone, Debug, Eq, Hash, JSTraceable, PartialEq)] pub enum ModuleIdentity { ScriptId(ScriptId), ModuleUrl(ServoUrl), @@ -306,15 +328,57 @@ impl ModuleTree { // 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` - pub fn append_handler(&self, owner: ModuleOwner, module_identity: ModuleIdentity) { + fn append_handler( + &self, + owner: ModuleOwner, + module_identity: ModuleIdentity, + fetch_options: ScriptFetchOptions, + ) { + let this = owner.clone(); + let identity = module_identity.clone(); + let options = fetch_options.clone(); + + let handler = PromiseNativeHandler::new( + &owner.global(), + Some(ModuleHandler::new(Box::new( + task!(fetched_resolve: move || { + this.notify_owner_to_finish(identity, options); + }), + ))), + 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.notify_owner_to_finish(identity); + this.finish_dynamic_module(identity, module_id); }), ))), None, @@ -351,8 +415,10 @@ impl ModuleTree { fn compile_module_script( &self, global: &GlobalScope, + owner: ModuleOwner, module_script_text: Rc<DOMString>, url: ServoUrl, + options: ScriptFetchOptions, ) -> Result<ModuleObject, RethrowError> { let module: Vec<u16> = module_script_text.encode_utf16().collect(); @@ -385,13 +451,11 @@ impl ModuleTree { )))); } - let module_script_data = Box::new(ModuleScript { - base_url: url.clone(), - }); + let module_script_data = Rc::new(ModuleScript::new(url.clone(), options, Some(owner))); SetModulePrivate( module_script.get(), - &PrivateValue(Box::into_raw(module_script_data) as *const _), + &PrivateValue(Rc::into_raw(module_script_data) as *const _), ); debug!("module script of {} compile done", url); @@ -640,7 +704,7 @@ impl ModuleTree { &self, owner: &ModuleOwner, destination: Destination, - credentials_mode: CredentialsMode, + options: &ScriptFetchOptions, parent_identity: ModuleIdentity, ) { debug!("Start to load dependencies of {}", self.url.clone()); @@ -713,17 +777,18 @@ impl ModuleTree { // Step 1. assert!(visited_urls.get(&url).is_some()); + let options = options.descendant_fetch_options(); + // Step 2. fetch_single_module_script( owner.clone(), url.clone(), visited_urls.clone(), destination.clone(), - ParserMetadata::NotParserInserted, - "".to_owned(), // integrity - credentials_mode.clone(), + options, Some(parent_identity.clone()), false, + None, ); } }, @@ -822,10 +887,11 @@ impl Callback for ModuleHandler { /// The owner of the module /// It can be `worker` or `script` element #[derive(Clone)] -pub enum ModuleOwner { +pub(crate) enum ModuleOwner { #[allow(dead_code)] Worker(TrustedWorkerAddress), Window(Trusted<HTMLScriptElement>), + DynamicModule(Trusted<DynamicModuleOwner>), } impl ModuleOwner { @@ -833,12 +899,18 @@ impl ModuleOwner { match &self { ModuleOwner::Worker(worker) => (*worker.root().clone()).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, + fetch_options: ScriptFetchOptions, + ) { match &self { ModuleOwner::Worker(_) => unimplemented!(), + ModuleOwner::DynamicModule(_) => unimplemented!(), ModuleOwner::Window(script) => { let global = self.global(); @@ -854,11 +926,13 @@ impl ModuleOwner { ModuleIdentity::ModuleUrl(script_src) => Ok(ScriptOrigin::external( Rc::clone(&module_tree.get_text().borrow()), script_src.clone(), + fetch_options, ScriptType::Module, )), ModuleIdentity::ScriptId(_) => Ok(ScriptOrigin::internal( Rc::clone(&module_tree.get_text().borrow()), document.base_url().clone(), + fetch_options, ScriptType::Module, )), }, @@ -880,6 +954,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. @@ -894,8 +1042,8 @@ struct ModuleContext { url: ServoUrl, /// Destination of current module context destination: Destination, - /// Credentials Mode of current module context - credentials_mode: CredentialsMode, + /// Options for the current script fetch + options: ScriptFetchOptions, /// Indicates whether the request failed, and why status: Result<(), NetworkError>, /// Timing object for this resource @@ -982,6 +1130,7 @@ impl FetchResponseListener for ModuleContext { Ok(ScriptOrigin::external( Rc::new(DOMString::from(source_text)), meta.final_url, + self.options.clone(), ScriptType::Module, )) }); @@ -1005,8 +1154,10 @@ impl FetchResponseListener for ModuleContext { let compiled_module = module_tree.compile_module_script( &global, + self.owner.clone(), resp_mod_script.text(), self.url.clone(), + self.options.clone(), ); match compiled_module { @@ -1020,7 +1171,7 @@ impl FetchResponseListener for ModuleContext { module_tree.fetch_module_descendants( &self.owner, self.destination.clone(), - self.credentials_mode.clone(), + &self.options, ModuleIdentity::ModuleUrl(self.url.clone()), ); }, @@ -1065,9 +1216,176 @@ pub unsafe fn EnsureModuleHooksInitialized(rt: *mut JSRuntime) { SetModuleResolveHook(rt, Some(HostResolveImportedModule)); SetModuleMetadataHook(rt, Some(HostPopulateImportMeta)); - SetScriptPrivateReferenceHooks(rt, None, None); + SetScriptPrivateReferenceHooks( + rt, + Some(host_add_ref_top_level_script), + Some(host_release_top_level_script), + ); + SetModuleDynamicImportHook(rt, Some(host_import_module_dynamically)); +} + +#[allow(unsafe_code)] +unsafe extern "C" fn host_add_ref_top_level_script(value: *const Value) { + let val = Rc::from_raw((*value).to_private() as *const ModuleScript); + mem::forget(val.clone()); + mem::forget(val); +} + +#[allow(unsafe_code)] +unsafe extern "C" fn host_release_top_level_script(value: *const Value) { + let _val = Rc::from_raw((*value).to_private() as *const ModuleScript); +} + +#[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, JSTraceable, MallocSizeOf)] +/// <https://html.spec.whatwg.org/multipage/#script-fetch-options> +pub 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> + pub 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); + } - SetModuleDynamicImportHook(rt, None); + let dynamic_module_id = DynamicModuleId(Uuid::new_v4()); + + // Step 3. + let owner = match unsafe { module_script_from_reference_private(&reference_private) } { + Some(module_data) if module_data.owner.is_some() => module_data.owner.clone().unwrap(), + _ => 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)] @@ -1085,7 +1403,7 @@ unsafe extern "C" fn HostResolveImportedModule( let mut base_url = global_scope.api_base_url(); // 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 { base_url = data.base_url.clone(); } @@ -1131,7 +1449,7 @@ unsafe extern "C" fn HostPopulateImportMeta( let global_scope = GlobalScope::from_context(cx, InRealm::Already(&in_realm_proof)); // 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(), None => global_scope.api_base_url(), }; @@ -1153,12 +1471,11 @@ unsafe extern "C" fn HostPopulateImportMeta( } /// 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, url: ServoUrl, destination: Destination, - integrity_metadata: String, - credentials_mode: CredentialsMode, + options: ScriptFetchOptions, ) { let mut visited_urls = HashSet::new(); visited_urls.insert(url.clone()); @@ -1169,25 +1486,71 @@ pub fn fetch_external_module_script( url, visited_urls, destination, - ParserMetadata::NotParserInserted, - integrity_metadata, - credentials_mode, + options, None, 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 -pub fn fetch_single_module_script( +fn fetch_single_module_script( owner: ModuleOwner, url: ServoUrl, visited_urls: HashSet<ServoUrl>, destination: Destination, - parser_metadata: ParserMetadata, - integrity_metadata: String, - credentials_mode: CredentialsMode, + options: ScriptFetchOptions, parent_identity: Option<ModuleIdentity>, top_level_module_fetch: bool, + dynamic_module: Option<RootedTraceableBox<DynamicModule>>, ) { { // Step 1. @@ -1201,8 +1564,19 @@ pub fn fetch_single_module_script( debug!("Meet a fetched url {} and its status is {:?}", url, status); - if top_level_module_fetch { - module_tree.append_handler(owner.clone(), ModuleIdentity::ModuleUrl(url.clone())); + match dynamic_module { + 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()), + options, + ), + // do nothing if it's neither a dynamic module nor a top level module + None => {}, } if let Some(parent_identity) = parent_identity { @@ -1230,8 +1604,19 @@ pub fn fetch_single_module_script( let module_tree = ModuleTree::new(url.clone(), is_external, visited_urls); module_tree.set_status(ModuleStatus::Fetching); - if top_level_module_fetch { - module_tree.append_handler(owner.clone(), ModuleIdentity::ModuleUrl(url.clone())); + match dynamic_module { + 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()), + options.clone(), + ), + // do nothing if it's neither a dynamic module nor a top level module + None => {}, } if let Some(parent_identity) = parent_identity { @@ -1252,7 +1637,7 @@ pub fn fetch_single_module_script( }; let document: Option<DomRoot<Document>> = match &owner { - ModuleOwner::Worker(_) => None, + ModuleOwner::Worker(_) | ModuleOwner::DynamicModule(_) => None, ModuleOwner::Window(script) => Some(document_from_node(&*script.root())), }; @@ -1260,9 +1645,9 @@ pub fn fetch_single_module_script( let request = RequestBuilder::new(url.clone(), global.get_referrer()) .destination(destination.clone()) .origin(global.origin().immutable().clone()) - .parser_metadata(parser_metadata) - .integrity_metadata(integrity_metadata.clone()) - .credentials_mode(credentials_mode) + .parser_metadata(options.parser_metadata) + .integrity_metadata(options.integrity_metadata.clone()) + .credentials_mode(options.credentials_mode) .mode(mode); let context = Arc::new(Mutex::new(ModuleContext { @@ -1271,7 +1656,7 @@ pub fn fetch_single_module_script( metadata: None, url: url.clone(), destination: destination.clone(), - credentials_mode: credentials_mode.clone(), + options, status: Ok(()), resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource), })); @@ -1293,30 +1678,49 @@ pub fn fetch_single_module_script( }), ); - if let Some(doc) = document { - doc.fetch_async(LoadType::Script(url), request, action_sender); + match document { + 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)] /// 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, module_script_text: Rc<DOMString>, url: ServoUrl, script_id: ScriptId, - credentials_mode: CredentialsMode, + options: ScriptFetchOptions, ) { let global = owner.global(); let is_external = false; let module_tree = ModuleTree::new(url.clone(), is_external, HashSet::new()); - let compiled_module = - module_tree.compile_module_script(&global, module_script_text, url.clone()); + let compiled_module = module_tree.compile_module_script( + &global, + owner.clone(), + module_script_text, + url.clone(), + options.clone(), + ); match compiled_module { Ok(record) => { - module_tree.append_handler(owner.clone(), ModuleIdentity::ScriptId(script_id.clone())); + module_tree.append_handler( + owner.clone(), + ModuleIdentity::ScriptId(script_id.clone()), + options.clone(), + ); module_tree.set_record(record); // We need to set `module_tree` into inline module map in case @@ -1333,7 +1737,7 @@ pub fn fetch_inline_module_script( module_tree.fetch_module_descendants( &owner, Destination::Script, - credentials_mode, + &options, ModuleIdentity::ScriptId(script_id), ); }, @@ -1341,7 +1745,7 @@ pub fn fetch_inline_module_script( module_tree.set_rethrow_error(exception); module_tree.set_status(ModuleStatus::Finished); global.set_inline_module_map(script_id.clone(), module_tree); - owner.notify_owner_to_finish(ModuleIdentity::ScriptId(script_id)); + owner.notify_owner_to_finish(ModuleIdentity::ScriptId(script_id), options); }, } } diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index c07c43b04f2..b5ea3f619a6 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -63,6 +63,7 @@ use crate::dom::workletglobalscope::WorkletGlobalScopeInit; use crate::fetch::FetchCanceller; use crate::microtask::{Microtask, MicrotaskQueue}; use crate::realms::enter_realm; +use crate::script_module::ScriptFetchOptions; use crate::script_runtime::{ get_reports, new_rt_and_cx, ContextForRequestInterrupt, JSContext, Runtime, ScriptPort, }; @@ -3718,7 +3719,12 @@ impl ScriptThread { // Script source is ready to be evaluated (11.) let _ac = enter_realm(global_scope); rooted!(in(*global_scope.get_cx()) let mut jsval = UndefinedValue()); - global_scope.evaluate_js_on_global_with_result(&script_source, jsval.handle_mut()); + global_scope.evaluate_js_on_global_with_result( + &script_source, + jsval.handle_mut(), + ScriptFetchOptions::default_classic_script(&global_scope), + global_scope.api_base_url(), + ); load_data.js_eval_result = if jsval.get().is_string() { unsafe { diff --git a/components/script/timers.rs b/components/script/timers.rs index 5e236f07494..ebc0bd8874c 100644 --- a/components/script/timers.rs +++ b/components/script/timers.rs @@ -12,6 +12,7 @@ use crate::dom::eventsource::EventSourceTimeoutCallback; use crate::dom::globalscope::GlobalScope; use crate::dom::testbinding::TestBindingCallback; use crate::dom::xmlhttprequest::XHRTimeoutCallback; +use crate::script_module::ScriptFetchOptions; use crate::script_thread::ScriptThread; use euclid::Length; use ipc_channel::ipc::IpcSender; @@ -541,7 +542,13 @@ impl JsTimerTask { let global = this.global(); let cx = global.get_cx(); rooted!(in(*cx) let mut rval = UndefinedValue()); - global.evaluate_js_on_global_with_result(code_str, rval.handle_mut()); + // FIXME(cybai): Use base url properly by saving private reference for timers (#27260) + global.evaluate_js_on_global_with_result( + code_str, + rval.handle_mut(), + ScriptFetchOptions::default_classic_script(&global), + global.api_base_url(), + ); }, InternalTimerCallback::FunctionTimerCallback(ref function, ref arguments) => { let arguments = self.collect_heap_args(arguments); diff --git a/components/script/webdriver_handlers.rs b/components/script/webdriver_handlers.rs index 1e094ec086c..1d36337f5eb 100644 --- a/components/script/webdriver_handlers.rs +++ b/components/script/webdriver_handlers.rs @@ -38,6 +38,7 @@ use crate::dom::nodelist::NodeList; use crate::dom::window::Window; use crate::dom::xmlserializer::XMLSerializer; use crate::realms::enter_realm; +use crate::script_module::ScriptFetchOptions; use crate::script_runtime::JSContext as SafeJSContext; use crate::script_thread::{Documents, ScriptThread}; use cookie::Cookie; @@ -297,9 +298,13 @@ pub fn handle_execute_script( let result = unsafe { let cx = window.get_cx(); rooted!(in(*cx) let mut rval = UndefinedValue()); - window - .upcast::<GlobalScope>() - .evaluate_js_on_global_with_result(&eval, rval.handle_mut()); + let global = window.upcast::<GlobalScope>(); + global.evaluate_js_on_global_with_result( + &eval, + rval.handle_mut(), + ScriptFetchOptions::default_classic_script(&global), + global.api_base_url(), + ); jsval_to_webdriver(*cx, &window.upcast::<GlobalScope>(), rval.handle()) }; @@ -323,9 +328,13 @@ pub fn handle_execute_async_script( let cx = window.get_cx(); window.set_webdriver_script_chan(Some(reply)); rooted!(in(*cx) let mut rval = UndefinedValue()); - window - .upcast::<GlobalScope>() - .evaluate_js_on_global_with_result(&eval, rval.handle_mut()); + let global = window.upcast::<GlobalScope>(); + global.evaluate_js_on_global_with_result( + &eval, + rval.handle_mut(), + ScriptFetchOptions::default_classic_script(&global), + global.api_base_url(), + ); }, None => { reply diff --git a/tests/wpt/include.ini b/tests/wpt/include.ini index 6125495f93f..295202b2205 100644 --- a/tests/wpt/include.ini +++ b/tests/wpt/include.ini @@ -123,10 +123,6 @@ skip: true skip: false [json-module] skip: true - [module] - skip: false - [dynamic-import] - skip: true [moving-between-documents] skip: true [js] diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-fetch-error.sub.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-fetch-error.sub.html.ini deleted file mode 100644 index aada536b93f..00000000000 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-fetch-error.sub.html.ini +++ /dev/null @@ -1,50 +0,0 @@ -[dynamic-imports-fetch-error.sub.html] - expected: ERROR - [import() must reject when there is a 500] - expected: FAIL - - [import() must reject with a different error object for each import when there is a 500 of a dependency] - expected: FAIL - - [import() must reject when there is a cross-origin module dependency (without CORS)] - expected: FAIL - - [import() must reject with a different error object for each import when there is a 404 of a dependency] - expected: FAIL - - [import() must reject with a different error object for each import when there is a 404] - expected: FAIL - - [import() must reject when there is a cross-origin module (without CORS)] - expected: FAIL - - [import() must reject when there is a wrong MIME type] - expected: FAIL - - [import() must reject when there is a wrong MIME type of a dependency] - expected: FAIL - - [import() must reject with a different error object for each import when there is a 500] - expected: FAIL - - [import() must reject when there is a 500 of a dependency] - expected: FAIL - - [import() must reject with a different error object for each import when there is a wrong MIME type of a dependency] - expected: FAIL - - [import() must reject with a different error object for each import when there is a cross-origin module dependency (without CORS)] - expected: FAIL - - [import() must reject when there is a 404 of a dependency] - expected: FAIL - - [import() must reject with a different error object for each import when there is a cross-origin module (without CORS)] - expected: FAIL - - [import() must reject when there is a 404] - expected: FAIL - - [import() must reject with a different error object for each import when there is a wrong MIME type] - expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html.ini index 9bf433d43e6..db977449d0c 100644 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html.ini +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html.ini @@ -1,32 +1,4 @@ [dynamic-imports-script-error.html] - expected: ERROR - [import() must reject with different error objects for each import when there is a bad module specifier] - expected: FAIL - - [import() must reject with the same error object for each import when there is a evaluation error] - expected: FAIL - - [import() must reject when there is a bad module specifier in a dependency] - expected: FAIL - [import() must reject with different error objects for each import when there is a instantiation error] expected: FAIL - [import() must reject when there is a parse error] - expected: FAIL - - [import() must reject with the same error object for each import when there is a bad module specifier in a dependency] - expected: FAIL - - [import() must reject when there is a instantiation error] - expected: FAIL - - [import() must reject when there is a bad module specifier] - expected: FAIL - - [import() must reject with the same error object for each import when there is a parse error] - expected: FAIL - - [import()ing a module with an evaluation error must stop evaluation] - expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports.html.ini deleted file mode 100644 index 39ef1381174..00000000000 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[dynamic-imports.html] - type: testharness - [Dynamic imports should resolve module.] - expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/inline-event-handler.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/inline-event-handler.html.ini deleted file mode 100644 index 97ce0f4bdf9..00000000000 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/inline-event-handler.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[inline-event-handler.html] - type: testharness - expected: ERROR - [dynamic import should work when triggered from inline event handlers] - expected: TIMEOUT - diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-classic.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-classic.html.ini deleted file mode 100644 index 5373a884194..00000000000 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-classic.html.ini +++ /dev/null @@ -1,11 +0,0 @@ -[propagate-nonce-external-classic.html] - type: testharness - [Untitled] - expected: FAIL - - [propagate-nonce-external-classic] - expected: FAIL - - [Dynamically imported module should eval when imported from script w/ a valid nonce.] - expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-module.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-module.html.ini deleted file mode 100644 index 19b6b4f76d3..00000000000 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-module.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[propagate-nonce-external-module.html] - type: testharness - [Dynamically imported module should eval when imported from script w/ a valid nonce.] - expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-classic.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-classic.html.ini deleted file mode 100644 index 5c6e23a8ed4..00000000000 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-classic.html.ini +++ /dev/null @@ -1,11 +0,0 @@ -[propagate-nonce-inline-classic.html] - type: testharness - [Untitled] - expected: FAIL - - [propagate-nonce-inline-classic] - expected: FAIL - - [Dynamically imported module should eval when imported from script w/ a valid nonce.] - expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-module.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-module.html.ini deleted file mode 100644 index d340495515a..00000000000 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-module.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[propagate-nonce-inline-module.html] - type: testharness - [Dynamically imported module should eval when imported from script w/ a valid nonce.] - expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic.html.ini index 7b9d519d6d9..70d72a9a06b 100644 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic.html.ini +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic.html.ini @@ -1,19 +1,3 @@ [string-compilation-base-url-external-classic.html] - [import() inside compiled strings uses the script base URL inside a classic script that is loaded from a file] - expected: FAIL - - [Function should successfully import] - expected: FAIL - [setTimeout should successfully import] expected: FAIL - - [inline-event-handlers-UA-code should successfully import] - expected: FAIL - - [eval should successfully import] - expected: FAIL - - [reflected-inline-event-handlers should successfully import] - expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module.html.ini index b4c24671932..0954867d07d 100644 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module.html.ini +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module.html.ini @@ -1,16 +1,4 @@ [string-compilation-base-url-external-module.html] - [Function should successfully import] - expected: FAIL - [setTimeout should successfully import] expected: FAIL - [inline-event-handlers-UA-code should successfully import] - expected: FAIL - - [eval should successfully import] - expected: FAIL - - [reflected-inline-event-handlers should successfully import] - expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-classic.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-classic.html.ini deleted file mode 100644 index 787bbafc365..00000000000 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-classic.html.ini +++ /dev/null @@ -1,19 +0,0 @@ -[string-compilation-base-url-inline-classic.html] - [import() inside compiled strings uses the script base URL (= document base URL) inside an inline classic script] - expected: FAIL - - [inline event handlers triggered via UA code should successfully import] - expected: FAIL - - [setTimeout should successfully import] - expected: FAIL - - [reflected inline event handlers should successfully import] - expected: FAIL - - [the Function constructor should successfully import] - expected: FAIL - - [eval should successfully import] - expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module.html.ini deleted file mode 100644 index 6c352df6734..00000000000 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module.html.ini +++ /dev/null @@ -1,16 +0,0 @@ -[string-compilation-base-url-inline-module.html] - [inline event handlers triggered via UA code should successfully import] - expected: FAIL - - [setTimeout should successfully import] - expected: FAIL - - [reflected inline event handlers should successfully import] - expected: FAIL - - [the Function constructor should successfully import] - expected: FAIL - - [eval should successfully import] - expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-classic.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-classic.html.ini deleted file mode 100644 index e09b7a95c36..00000000000 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-classic.html.ini +++ /dev/null @@ -1,20 +0,0 @@ -[string-compilation-classic.html] - type: testharness - [import() inside compiled strings inside a classic script] - expected: FAIL - - [inline event handlers triggered via UA code should successfully import] - expected: FAIL - - [setTimeout should successfully import] - expected: FAIL - - [reflected inline event handlers should successfully import] - expected: FAIL - - [the Function constructor should successfully import] - expected: FAIL - - [eval should successfully import] - expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-module.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-module.html.ini deleted file mode 100644 index d01aeb85915..00000000000 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-module.html.ini +++ /dev/null @@ -1,17 +0,0 @@ -[string-compilation-module.html] - type: testharness - [inline event handlers triggered via UA code should successfully import] - expected: FAIL - - [setTimeout should successfully import] - expected: FAIL - - [reflected inline event handlers should successfully import] - expected: FAIL - - [the Function constructor should successfully import] - expected: FAIL - - [eval should successfully import] - expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-classic.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-classic.html.ini index 1ae15077ac8..eb1b085a006 100644 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-classic.html.ini +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-classic.html.ini @@ -1,22 +1,4 @@ [string-compilation-nonce-classic.html] - [setTimeout must inherit the nonce from the triggering script, thus execute] - expected: FAIL - - [direct eval must inherit the nonce from the triggering script, thus execute] - expected: FAIL - - [indirect eval must inherit the nonce from the triggering script, thus execute] - expected: FAIL - - [the Function constructor must inherit the nonce from the triggering script, thus execute] - expected: FAIL - - [reflected inline event handlers must inherit the nonce from the triggering script, thus execute] - expected: NOTRUN - - [inline event handlers triggered via UA code must inherit the nonce from the triggering script, thus execute] - expected: NOTRUN - [inline event handlers triggered via UA code must not inherit the nonce from the triggering script, thus fail] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-module.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-module.html.ini index d0e18d62c00..e476dc488a8 100644 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-module.html.ini +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-module.html.ini @@ -1,19 +1,7 @@ [string-compilation-nonce-module.html] - [the Function constructor must inherit the nonce from the triggering script, thus execute] - expected: FAIL - - [direct eval must inherit the nonce from the triggering script, thus execute] - expected: FAIL - - [setTimeout must inherit the nonce from the triggering script, thus execute] - expected: FAIL - [inline event handlers triggered via UA code must not inherit the nonce from the triggering script, thus fail] expected: FAIL - [indirect eval must inherit the nonce from the triggering script, thus execute] - expected: FAIL - [reflected inline event handlers must not inherit the nonce from the triggering script, thus fail] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-of-promise-result.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-of-promise-result.html.ini deleted file mode 100644 index 588cf57c9df..00000000000 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-of-promise-result.html.ini +++ /dev/null @@ -1,7 +0,0 @@ -[string-compilation-of-promise-result.html] - [Evaled the script via eval, successful import] - expected: FAIL - - [Evaled the script via Function, successful import] - expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-other-document.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-other-document.html.ini index 0b0ad99e049..a23db3c316a 100644 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-other-document.html.ini +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-other-document.html.ini @@ -1,16 +1,3 @@ [string-compilation-other-document.html] - [inline event handlers triggered by JS should successfully import] - expected: FAIL - [setTimeout should successfully import] expected: FAIL - - [reflected inline event handlers should successfully import] - expected: FAIL - - [the Function constructor should successfully import] - expected: FAIL - - [eval should successfully import] - expected: FAIL - diff --git a/tests/wpt/metadata/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import.html.ini b/tests/wpt/metadata/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import.html.ini index 30c8d2fd9d5..4c158e72ba2 100644 --- a/tests/wpt/metadata/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import.html.ini +++ b/tests/wpt/metadata/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import.html.ini @@ -1,5 +1,4 @@ [module-dynamic-import.html] - expected: TIMEOUT [document.write in an imported module] - expected: TIMEOUT + expected: FAIL |