diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index c040078f707..d92d5c124d1 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -149,7 +149,6 @@ use crate::dom::raredata::ElementRareData; use crate::dom::servoparser::ServoParser; use crate::dom::shadowroot::{IsUserAgentWidget, ShadowRoot}; use crate::dom::text::Text; -use crate::dom::types::TrustedTypePolicyFactory; use crate::dom::validation::Validatable; use crate::dom::validitystate::ValidationFlags; use crate::dom::virtualmethods::{VirtualMethods, vtable_for}; @@ -1961,35 +1960,6 @@ impl Element { .unwrap_or_else(|_| TrustedScriptURLOrUSVString::USVString(USVString(value.to_owned()))) } - pub(crate) fn set_trusted_type_url_attribute( - &self, - local_name: &LocalName, - value: TrustedScriptURLOrUSVString, - can_gc: CanGc, - ) -> Fallible<()> { - assert_eq!(*local_name, local_name.to_ascii_lowercase()); - let value = match value { - TrustedScriptURLOrUSVString::USVString(url) => { - let global = self.owner_global(); - // TODO(36258): Reflectively get the name of the class - let sink = format!("{} {}", "HTMLScriptElement", &local_name); - let result = TrustedTypePolicyFactory::get_trusted_type_compliant_string( - &global, - url.to_string(), - &sink, - "'script'", - can_gc, - ); - result? - }, - // This partially implements - // Step 1: If input is an instance of expectedType, return stringified input and abort these steps. - TrustedScriptURLOrUSVString::TrustedScriptURL(script_url) => script_url.to_string(), - }; - self.set_attribute(local_name, AttrValue::String(value), can_gc); - Ok(()) - } - pub(crate) fn get_string_attribute(&self, local_name: &LocalName) -> DOMString { match self.get_attribute(&ns!(), local_name) { Some(x) => x.Value(), diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index e7efbde9b1d..59b71543d6d 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -116,7 +116,7 @@ impl HTMLElement { /// `.outerText` in JavaScript.` /// /// - fn get_inner_outer_text(&self, can_gc: CanGc) -> DOMString { + pub(crate) fn get_inner_outer_text(&self, can_gc: CanGc) -> DOMString { let node = self.upcast::(); let window = node.owner_window(); let element = self.as_element(); @@ -134,6 +134,16 @@ impl HTMLElement { DOMString::from(text) } + + /// + pub(crate) fn set_inner_text(&self, input: DOMString, can_gc: CanGc) { + // Step 1: Let fragment be the rendered text fragment for value given element's node + // document. + let fragment = self.rendered_text_fragment(input, can_gc); + + // Step 2: Replace all with fragment within element. + Node::replace_all(Some(fragment.upcast()), self.upcast::(), can_gc); + } } impl HTMLElementMethods for HTMLElement { @@ -494,12 +504,7 @@ impl HTMLElementMethods for HTMLElement { /// fn SetInnerText(&self, input: DOMString, can_gc: CanGc) { - // Step 1: Let fragment be the rendered text fragment for value given element's node - // document. - let fragment = self.rendered_text_fragment(input, can_gc); - - // Step 2: Replace all with fragment within element. - Node::replace_all(Some(fragment.upcast()), self.upcast::(), can_gc); + self.set_inner_text(input, can_gc) } /// diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs index 58853f600d2..9d0ca807748 100644 --- a/components/script/dom/htmlscriptelement.rs +++ b/components/script/dom/htmlscriptelement.rs @@ -32,6 +32,7 @@ use net_traits::{ }; use servo_config::pref; use servo_url::{ImmutableOrigin, ServoUrl}; +use style::attr::AttrValue; use style::str::{HTML_SPACE_CHARACTERS, StaticStringVec}; use stylo_atoms::Atom; use uuid::Uuid; @@ -44,7 +45,9 @@ use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; use crate::dom::bindings::codegen::Bindings::HTMLScriptElementBinding::HTMLScriptElementMethods; use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use crate::dom::bindings::codegen::GenericBindings::HTMLElementBinding::HTMLElement_Binding::HTMLElementMethods; -use crate::dom::bindings::codegen::UnionTypes::TrustedScriptURLOrUSVString; +use crate::dom::bindings::codegen::UnionTypes::{ + TrustedScriptOrString, TrustedScriptURLOrUSVString, +}; use crate::dom::bindings::error::Fallible; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::refcounted::Trusted; @@ -64,6 +67,8 @@ use crate::dom::globalscope::GlobalScope; use crate::dom::htmlelement::HTMLElement; use crate::dom::node::{ChildrenMutation, CloneChildrenFlag, Node, NodeTraits}; use crate::dom::performanceresourcetiming::InitiatorType; +use crate::dom::trustedscript::TrustedScript; +use crate::dom::trustedscripturl::TrustedScriptURL; use crate::dom::virtualmethods::VirtualMethods; use crate::fetch::create_a_potential_cors_request; use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener}; @@ -667,7 +672,7 @@ impl HTMLScriptElement { // Step 5. Let source text be el's child text content. // Step 6. If el has no src attribute, and source text is the empty string, then return. - let text = self.Text(); + let text = self.text(); if text.is_empty() && !element.has_attribute(&local_name!("src")) { return; } @@ -1272,6 +1277,15 @@ impl HTMLScriptElement { let event = Event::new(window.upcast(), type_, bubbles, cancelable, can_gc); event.fire(self.upcast(), can_gc) } + + fn text(&self) -> DOMString { + match self.Text() { + TrustedScriptOrString::String(value) => value, + TrustedScriptOrString::TrustedScript(trusted_script) => { + DOMString::from(trusted_script.to_string()) + }, + } + } } impl VirtualMethods for HTMLScriptElement { @@ -1286,7 +1300,7 @@ impl VirtualMethods for HTMLScriptElement { if *attr.local_name() == local_name!("src") { if let AttributeMutation::Set(_) = mutation { if !self.parser_inserted.get() && self.upcast::().is_connected() { - self.prepare(CanGc::note()); + self.prepare(can_gc); } } } @@ -1344,10 +1358,25 @@ impl VirtualMethods for HTMLScriptElement { impl HTMLScriptElementMethods for HTMLScriptElement { // https://html.spec.whatwg.org/multipage/#dom-script-src - make_trusted_type_url_getter!(Src, "src"); + fn Src(&self) -> TrustedScriptURLOrUSVString { + let element = self.upcast::(); + element.get_trusted_type_url_attribute(&local_name!("src")) + } - // https://html.spec.whatwg.org/multipage/#dom-script-src - make_trusted_type_url_setter!(SetSrc, "src"); + /// + fn SetSrc(&self, value: TrustedScriptURLOrUSVString, can_gc: CanGc) -> Fallible<()> { + let element = self.upcast::(); + let local_name = &local_name!("src"); + let value = TrustedScriptURL::get_trusted_script_url_compliant_string( + &element.owner_global(), + value, + "HTMLScriptElement", + local_name, + can_gc, + )?; + element.set_attribute(local_name, AttrValue::String(value), can_gc); + Ok(()) + } // https://html.spec.whatwg.org/multipage/#dom-script-type make_getter!(Type, "type"); @@ -1416,14 +1445,77 @@ impl HTMLScriptElementMethods for HTMLScriptElement { // https://html.spec.whatwg.org/multipage/#dom-script-referrerpolicy make_setter!(SetReferrerPolicy, "referrerpolicy"); - // https://html.spec.whatwg.org/multipage/#dom-script-text - fn Text(&self) -> DOMString { - self.upcast::().child_text_content() + /// + fn InnerText(&self, can_gc: CanGc) -> TrustedScriptOrString { + // Step 1: Return the result of running get the text steps with this. + TrustedScriptOrString::String(self.upcast::().get_inner_outer_text(can_gc)) } - // https://html.spec.whatwg.org/multipage/#dom-script-text - fn SetText(&self, value: DOMString, can_gc: CanGc) { - self.upcast::().SetTextContent(Some(value), can_gc) + /// + fn SetInnerText(&self, input: TrustedScriptOrString, can_gc: CanGc) -> Fallible<()> { + // Step 1: Let value be the result of calling Get Trusted Type compliant string with TrustedScript, + // this's relevant global object, the given value, HTMLScriptElement innerText, and script. + let value = TrustedScript::get_trusted_script_compliant_string( + &self.owner_global(), + input, + "HTMLScriptElement", + "innerText", + can_gc, + )?; + // Step 3: Run set the inner text steps with this and value. + self.upcast::() + .set_inner_text(DOMString::from(value), can_gc); + Ok(()) + } + + /// + fn Text(&self) -> TrustedScriptOrString { + TrustedScriptOrString::String(self.upcast::().child_text_content()) + } + + /// + fn SetText(&self, value: TrustedScriptOrString, can_gc: CanGc) -> Fallible<()> { + // Step 1: Let value be the result of calling Get Trusted Type compliant string with TrustedScript, + // this's relevant global object, the given value, HTMLScriptElement text, and script. + let value = TrustedScript::get_trusted_script_compliant_string( + &self.owner_global(), + value, + "HTMLScriptElement", + "text", + can_gc, + )?; + // Step 2: Set this's script text value to the given value. + // TODO: Implement for https://w3c.github.io/trusted-types/dist/spec/#prepare-script-text + // Step 3: String replace all with the given value within this. + Node::string_replace_all(DOMString::from(value), self.upcast::(), can_gc); + Ok(()) + } + + /// + fn GetTextContent(&self) -> Option { + // Step 1: Return the result of running get text content with this. + Some(TrustedScriptOrString::String( + self.upcast::().GetTextContent()?, + )) + } + + /// + fn SetTextContent(&self, value: Option, can_gc: CanGc) -> Fallible<()> { + // Step 1: Let value be the result of calling Get Trusted Type compliant string with TrustedScript, + // this's relevant global object, the given value, HTMLScriptElement textContent, and script. + let value = TrustedScript::get_trusted_script_compliant_string( + &self.owner_global(), + value.unwrap_or(TrustedScriptOrString::String(DOMString::from(""))), + "HTMLScriptElement", + "textContent", + can_gc, + )?; + // Step 2: Set this's script text value to value. + // TODO: Implement for https://w3c.github.io/trusted-types/dist/spec/#prepare-script-text + // Step 3: Run set text content with this and value. + self.upcast::() + .SetTextContent(Some(DOMString::from(value)), can_gc); + Ok(()) } } diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs index 997341984c6..cc44497d0b9 100644 --- a/components/script/dom/macros.rs +++ b/components/script/dom/macros.rs @@ -121,32 +121,6 @@ macro_rules! make_url_setter( ); ); -#[macro_export] -macro_rules! make_trusted_type_url_getter( - ( $attr:ident, $htmlname:tt ) => ( - fn $attr(&self) -> TrustedScriptURLOrUSVString { - use $crate::dom::bindings::inheritance::Castable; - use $crate::dom::element::Element; - let element = self.upcast::(); - element.get_trusted_type_url_attribute(&html5ever::local_name!($htmlname)) - } - ); -); - -#[macro_export] -macro_rules! make_trusted_type_url_setter( - ( $attr:ident, $htmlname:tt ) => ( - fn $attr(&self, value: TrustedScriptURLOrUSVString, can_gc: CanGc) -> Fallible<()> { - use $crate::dom::bindings::inheritance::Castable; - use $crate::dom::element::Element; - use $crate::script_runtime::CanGc; - let element = self.upcast::(); - element.set_trusted_type_url_attribute(&html5ever::local_name!($htmlname), - value, can_gc) - } - ); -); - #[macro_export] macro_rules! make_form_action_getter( ( $attr:ident, $htmlname:tt ) => ( diff --git a/components/script/dom/trustedscript.rs b/components/script/dom/trustedscript.rs index 5ce51c24989..648fcc8c239 100644 --- a/components/script/dom/trustedscript.rs +++ b/components/script/dom/trustedscript.rs @@ -1,14 +1,19 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +use std::fmt; use dom_struct::dom_struct; use crate::dom::bindings::codegen::Bindings::TrustedScriptBinding::TrustedScriptMethods; +use crate::dom::bindings::codegen::UnionTypes::TrustedScriptOrString; +use crate::dom::bindings::error::Fallible; use crate::dom::bindings::reflector::{Reflector, reflect_dom_object}; use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::str::DOMString; use crate::dom::globalscope::GlobalScope; +use crate::dom::trustedtypepolicy::TrustedType; +use crate::dom::trustedtypepolicyfactory::TrustedTypePolicyFactory; use crate::script_runtime::CanGc; #[dom_struct] @@ -30,6 +35,37 @@ impl TrustedScript { pub(crate) fn new(data: String, global: &GlobalScope, can_gc: CanGc) -> DomRoot { reflect_dom_object(Box::new(Self::new_inherited(data)), global, can_gc) } + + pub(crate) fn get_trusted_script_compliant_string( + global: &GlobalScope, + value: TrustedScriptOrString, + containing_class: &str, + field: &str, + can_gc: CanGc, + ) -> Fallible { + match value { + TrustedScriptOrString::String(value) => { + let sink = format!("{} {}", containing_class, field); + TrustedTypePolicyFactory::get_trusted_type_compliant_string( + TrustedType::TrustedScript, + global, + value.as_ref().to_owned(), + &sink, + "'script'", + can_gc, + ) + }, + + TrustedScriptOrString::TrustedScript(trusted_script) => Ok(trusted_script.to_string()), + } + } +} + +impl fmt::Display for TrustedScript { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.data) + } } impl TrustedScriptMethods for TrustedScript { diff --git a/components/script/dom/trustedscripturl.rs b/components/script/dom/trustedscripturl.rs index ba1e0335abc..3f0aef248b3 100644 --- a/components/script/dom/trustedscripturl.rs +++ b/components/script/dom/trustedscripturl.rs @@ -7,10 +7,14 @@ use std::fmt; use dom_struct::dom_struct; use crate::dom::bindings::codegen::Bindings::TrustedScriptURLBinding::TrustedScriptURLMethods; +use crate::dom::bindings::codegen::UnionTypes::TrustedScriptURLOrUSVString; +use crate::dom::bindings::error::Fallible; use crate::dom::bindings::reflector::{Reflector, reflect_dom_object}; use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::str::DOMString; use crate::dom::globalscope::GlobalScope; +use crate::dom::trustedtypepolicy::TrustedType; +use crate::dom::trustedtypepolicyfactory::TrustedTypePolicyFactory; use crate::script_runtime::CanGc; #[dom_struct] @@ -32,6 +36,31 @@ impl TrustedScriptURL { pub(crate) fn new(data: String, global: &GlobalScope, can_gc: CanGc) -> DomRoot { reflect_dom_object(Box::new(Self::new_inherited(data)), global, can_gc) } + + pub(crate) fn get_trusted_script_url_compliant_string( + global: &GlobalScope, + value: TrustedScriptURLOrUSVString, + containing_class: &str, + field: &str, + can_gc: CanGc, + ) -> Fallible { + match value { + TrustedScriptURLOrUSVString::USVString(value) => { + let sink = format!("{} {}", containing_class, field); + TrustedTypePolicyFactory::get_trusted_type_compliant_string( + TrustedType::TrustedScriptURL, + global, + value.as_ref().to_owned(), + &sink, + "'script'", + can_gc, + ) + }, + TrustedScriptURLOrUSVString::TrustedScriptURL(trusted_script_url) => { + Ok(trusted_script_url.to_string()) + }, + } + } } impl fmt::Display for TrustedScriptURL { diff --git a/components/script/dom/trustedtypepolicy.rs b/components/script/dom/trustedtypepolicy.rs index 2ec5015eb88..d4def7269ed 100644 --- a/components/script/dom/trustedtypepolicy.rs +++ b/components/script/dom/trustedtypepolicy.rs @@ -7,6 +7,7 @@ use std::rc::Rc; use dom_struct::dom_struct; use js::jsapi::JSObject; use js::rust::HandleValue; +use strum_macros::IntoStaticStr; use crate::dom::bindings::callback::ExceptionHandling; use crate::dom::bindings::codegen::Bindings::TrustedTypePolicyBinding::TrustedTypePolicyMethods; @@ -38,6 +39,13 @@ pub struct TrustedTypePolicy { create_script_url: Option>, } +#[derive(Clone, IntoStaticStr)] +pub(crate) enum TrustedType { + TrustedHTML, + TrustedScript, + TrustedScriptURL, +} + impl TrustedTypePolicy { fn new_inherited(name: String, options: &TrustedTypePolicyOptions) -> Self { Self { @@ -59,51 +67,87 @@ impl TrustedTypePolicy { reflect_dom_object(Box::new(Self::new_inherited(name, options)), global, can_gc) } - // TODO(36258): Remove when we refactor get_trusted_type_policy_value to take an enum - // value to handle which callback to call. The callback should not be exposed outside - // of the policy object, but is currently used in TrustedPolicyFactory::process_value_with_default_policy - pub(crate) fn create_script_url(&self) -> Option> { - self.create_script_url.clone() + /// + fn check_callback_if_missing(throw_if_missing: bool) -> Fallible> { + // Step 3.1: If throwIfMissing throw a TypeError. + if throw_if_missing { + Err(Type("Cannot find type".to_owned())) + } else { + // Step 3.2: Else return null. + Ok(None) + } } - /// This does not take all arguments as specified. That's because the return type of the - /// trusted type function and object are not the same. 2 of the 3 string callbacks return - /// a DOMString, while the other one returns an USVString. Additionally, all three callbacks - /// have a unique type signature in WebIDL. - /// - /// To circumvent these type problems, rather than implementing the full functionality here, - /// part of the algorithm is implemented on the caller side. There, we only call the callback - /// and create the object. The rest of the machinery is ensuring the right values pass through - /// to the relevant callbacks. - /// /// - pub(crate) fn get_trusted_type_policy_value( + pub(crate) fn get_trusted_type_policy_value( &self, - policy_value_callback: PolicyCallback, + expected_type: TrustedType, + cx: JSContext, + input: DOMString, + arguments: Vec, throw_if_missing: bool, - ) -> Fallible> - where - S: AsRef, - PolicyCallback: FnOnce() -> Option>>, - { + can_gc: CanGc, + ) -> Fallible> { + rooted!(in(*cx) let this_object: *mut JSObject); // Step 1: Let functionName be a function name for the given trustedTypeName, based on the following table: - // Step 2: Let function be policy’s options[functionName]. - let function = policy_value_callback(); - match function { - // Step 3: If function is null, then: - None => { - // Step 3.1: If throwIfMissing throw a TypeError. - if throw_if_missing { - Err(Type("Cannot find type".to_owned())) - } else { - // Step 3.2: Else return null. - Ok(None) - } + match expected_type { + TrustedType::TrustedHTML => match &self.create_html { + // Step 3: If function is null, then: + None => TrustedTypePolicy::check_callback_if_missing(throw_if_missing), + // Step 2: Let function be policy’s options[functionName]. + Some(callback) => { + // Step 4: Let policyValue be the result of invoking function with value as a first argument, + // items of arguments as subsequent arguments, and callback **this** value set to null, + // rethrowing any exceptions. + callback + .Call_( + &this_object.handle(), + input, + arguments, + ExceptionHandling::Rethrow, + can_gc, + ) + .map(|result| result.map(|str| str.as_ref().to_owned())) + }, + }, + TrustedType::TrustedScript => match &self.create_script { + // Step 3: If function is null, then: + None => TrustedTypePolicy::check_callback_if_missing(throw_if_missing), + // Step 2: Let function be policy’s options[functionName]. + Some(callback) => { + // Step 4: Let policyValue be the result of invoking function with value as a first argument, + // items of arguments as subsequent arguments, and callback **this** value set to null, + // rethrowing any exceptions. + callback + .Call_( + &this_object.handle(), + input, + arguments, + ExceptionHandling::Rethrow, + can_gc, + ) + .map(|result| result.map(|str| str.as_ref().to_owned())) + }, + }, + TrustedType::TrustedScriptURL => match &self.create_script_url { + // Step 3: If function is null, then: + None => TrustedTypePolicy::check_callback_if_missing(throw_if_missing), + // Step 2: Let function be policy’s options[functionName]. + Some(callback) => { + // Step 4: Let policyValue be the result of invoking function with value as a first argument, + // items of arguments as subsequent arguments, and callback **this** value set to null, + // rethrowing any exceptions. + callback + .Call_( + &this_object.handle(), + input, + arguments, + ExceptionHandling::Rethrow, + can_gc, + ) + .map(|result| result.map(|str| str.as_ref().to_owned())) + }, }, - // Step 4: Let policyValue be the result of invoking function with value as a first argument, - // items of arguments as subsequent arguments, and callback **this** value set to null, - // rethrowing any exceptions. - Some(policy_value) => policy_value, } } @@ -118,27 +162,30 @@ impl TrustedTypePolicy { /// to the relevant callbacks. /// /// - pub(crate) fn create_trusted_type( + pub(crate) fn create_trusted_type( &self, - policy_value_callback: PolicyCallback, + expected_type: TrustedType, + cx: JSContext, + input: DOMString, + arguments: Vec, trusted_type_creation_callback: TrustedTypeCallback, + can_gc: CanGc, ) -> Fallible> where R: DomObject, - S: AsRef, - PolicyCallback: FnOnce() -> Option>>, TrustedTypeCallback: FnOnce(String) -> DomRoot, { // Step 1: Let policyValue be the result of executing Get Trusted Type policy value // with the same arguments as this algorithm and additionally true as throwIfMissing. - let policy_value = self.get_trusted_type_policy_value(policy_value_callback, true); + let policy_value = + self.get_trusted_type_policy_value(expected_type, cx, input, arguments, true, can_gc); match policy_value { // Step 2: If the algorithm threw an error, rethrow the error and abort the following steps. Err(error) => Err(error), Ok(policy_value) => { // Step 3: Let dataString be the result of stringifying policyValue. let data_string = match policy_value { - Some(value) => value.as_ref().into(), + Some(value) => value, // Step 4: If policyValue is null or undefined, set dataString to the empty string. None => "".to_owned(), }; @@ -164,22 +211,12 @@ impl TrustedTypePolicyMethods for TrustedTypePolicy { can_gc: CanGc, ) -> Fallible> { self.create_trusted_type( - || { - self.create_html.clone().map(|callback| { - rooted!(in(*cx) let this_object: *mut JSObject); - // Step 4: Let policyValue be the result of invoking function with value as a first argument, - // items of arguments as subsequent arguments, and callback **this** value set to null, - // rethrowing any exceptions. - callback.Call_( - &this_object.handle(), - input, - arguments, - ExceptionHandling::Rethrow, - can_gc, - ) - }) - }, + TrustedType::TrustedHTML, + cx, + input, + arguments, |data_string| TrustedHTML::new(data_string, &self.global(), can_gc), + can_gc, ) } /// @@ -191,22 +228,12 @@ impl TrustedTypePolicyMethods for TrustedTypePolicy { can_gc: CanGc, ) -> Fallible> { self.create_trusted_type( - || { - self.create_script.clone().map(|callback| { - rooted!(in(*cx) let this_object: *mut JSObject); - // Step 4: Let policyValue be the result of invoking function with value as a first argument, - // items of arguments as subsequent arguments, and callback **this** value set to null, - // rethrowing any exceptions. - callback.Call_( - &this_object.handle(), - input, - arguments, - ExceptionHandling::Rethrow, - can_gc, - ) - }) - }, + TrustedType::TrustedScript, + cx, + input, + arguments, |data_string| TrustedScript::new(data_string, &self.global(), can_gc), + can_gc, ) } /// @@ -218,22 +245,12 @@ impl TrustedTypePolicyMethods for TrustedTypePolicy { can_gc: CanGc, ) -> Fallible> { self.create_trusted_type( - || { - self.create_script_url.clone().map(|callback| { - rooted!(in(*cx) let this_object: *mut JSObject); - // Step 4: Let policyValue be the result of invoking function with value as a first argument, - // items of arguments as subsequent arguments, and callback **this** value set to null, - // rethrowing any exceptions. - callback.Call_( - &this_object.handle(), - input, - arguments, - ExceptionHandling::Rethrow, - can_gc, - ) - }) - }, + TrustedType::TrustedScriptURL, + cx, + input, + arguments, |data_string| TrustedScriptURL::new(data_string, &self.global(), can_gc), + can_gc, ) } } diff --git a/components/script/dom/trustedtypepolicyfactory.rs b/components/script/dom/trustedtypepolicyfactory.rs index 0dcc78b7cd0..0927446b904 100644 --- a/components/script/dom/trustedtypepolicyfactory.rs +++ b/components/script/dom/trustedtypepolicyfactory.rs @@ -6,11 +6,9 @@ use std::cell::RefCell; use content_security_policy::CheckResult; use dom_struct::dom_struct; use html5ever::{LocalName, Namespace, QualName, local_name, ns}; -use js::jsapi::JSObject; use js::jsval::NullValue; use js::rust::HandleValue; -use crate::dom::bindings::callback::ExceptionHandling; use crate::dom::bindings::codegen::Bindings::TrustedTypePolicyFactoryBinding::{ TrustedTypePolicyFactoryMethods, TrustedTypePolicyOptions, }; @@ -23,7 +21,7 @@ use crate::dom::globalscope::GlobalScope; use crate::dom::trustedhtml::TrustedHTML; use crate::dom::trustedscript::TrustedScript; use crate::dom::trustedscripturl::TrustedScriptURL; -use crate::dom::trustedtypepolicy::TrustedTypePolicy; +use crate::dom::trustedtypepolicy::{TrustedType, TrustedTypePolicy}; use crate::js::conversions::ToJSValConvertible; use crate::script_runtime::{CanGc, JSContext}; @@ -144,50 +142,40 @@ impl TrustedTypePolicyFactory { /// #[allow(unsafe_code)] pub(crate) fn process_value_with_default_policy( + expected_type: TrustedType, global: &GlobalScope, input: String, sink: &str, can_gc: CanGc, - ) -> Fallible>> { + ) -> Fallible> { // Step 1: Let defaultPolicy be the value of global’s trusted type policy factory's default policy. let global_policy_factory = global.trusted_types(can_gc); let default_policy = match global_policy_factory.default_policy.get() { - None => return Ok(Some(TrustedScriptURL::new(input, global, can_gc))), + None => return Ok(None), Some(default_policy) => default_policy, }; let cx = GlobalScope::get_cx(); // Step 2: Let policyValue be the result of executing Get Trusted Type policy value, // with the following arguments: + rooted!(in(*cx) let mut trusted_type_name_value = NullValue()); + unsafe { + let trusted_type_name: &'static str = expected_type.clone().into(); + trusted_type_name.to_jsval(*cx, trusted_type_name_value.handle_mut()); + } + + rooted!(in(*cx) let mut sink_value = NullValue()); + unsafe { + sink.to_jsval(*cx, sink_value.handle_mut()); + } + + let arguments = vec![trusted_type_name_value.handle(), sink_value.handle()]; let policy_value = default_policy.get_trusted_type_policy_value( - || { - // TODO(36258): support other trusted types as well by changing get_trusted_type_policy_value to accept - // the trusted type as enum and call the appropriate callback based on that. - default_policy.create_script_url().map(|callback| { - rooted!(in(*cx) let this_object: *mut JSObject); - rooted!(in(*cx) let mut trusted_type_name_value = NullValue()); - unsafe { - "TrustedScriptURL".to_jsval(*cx, trusted_type_name_value.handle_mut()); - } - - rooted!(in(*cx) let mut sink_value = NullValue()); - unsafe { - sink.to_jsval(*cx, sink_value.handle_mut()); - } - - let args = vec![trusted_type_name_value.handle(), sink_value.handle()]; - // Step 4: Let policyValue be the result of invoking function with value as a first argument, - // items of arguments as subsequent arguments, and callback **this** value set to null, - // rethrowing any exceptions. - callback.Call_( - &this_object.handle(), - DOMString::from(input.to_owned()), - args, - ExceptionHandling::Rethrow, - can_gc, - ) - }) - }, + expected_type, + cx, + DOMString::from(input.to_owned()), + arguments, false, + can_gc, ); let data_string = match policy_value { // Step 3: If the algorithm threw an error, rethrow the error and abort the following steps. @@ -196,14 +184,15 @@ impl TrustedTypePolicyFactory { // Step 4: If policyValue is null or undefined, return policyValue. None => return Ok(None), // Step 5: Let dataString be the result of stringifying policyValue. - Some(policy_value) => policy_value.as_ref().into(), + Some(policy_value) => policy_value, }, }; - Ok(Some(TrustedScriptURL::new(data_string, global, can_gc))) + Ok(Some(data_string)) } /// Step 1 is implemented by the caller /// pub(crate) fn get_trusted_type_compliant_string( + expected_type: TrustedType, global: &GlobalScope, input: String, sink: &str, @@ -224,6 +213,7 @@ impl TrustedTypePolicyFactory { // Step 4: Let convertedInput be the result of executing Process value with a default policy // with the same arguments as this algorithm. let converted_input = TrustedTypePolicyFactory::process_value_with_default_policy( + expected_type, global, input.clone(), sink, @@ -252,7 +242,7 @@ impl TrustedTypePolicyFactory { } }, // Step 8: Return stringified convertedInput. - Some(converted_input) => Ok((*converted_input).to_string()), + Some(converted_input) => Ok(converted_input), } // Step 7: Assert: convertedInput is an instance of expectedType. // TODO(https://github.com/w3c/trusted-types/issues/566): Implement when spec is resolved diff --git a/components/script_bindings/codegen/Bindings.conf b/components/script_bindings/codegen/Bindings.conf index 6396e3ced0c..36bb0c1b9f4 100644 --- a/components/script_bindings/codegen/Bindings.conf +++ b/components/script_bindings/codegen/Bindings.conf @@ -416,7 +416,7 @@ DOMInterfaces = { }, 'HTMLScriptElement': { - 'canGc': ['SetAsync', 'SetCrossOrigin', 'SetSrc', 'SetText'] + 'canGc': ['InnerText', 'SetAsync', 'SetCrossOrigin', 'SetInnerText', 'SetSrc', 'SetText', 'SetTextContent'] }, 'HTMLSelectElement': { diff --git a/components/script_bindings/webidls/HTMLScriptElement.webidl b/components/script_bindings/webidls/HTMLScriptElement.webidl index 6f02bb3cf47..2c7b398b7e3 100644 --- a/components/script_bindings/webidls/HTMLScriptElement.webidl +++ b/components/script_bindings/webidls/HTMLScriptElement.webidl @@ -21,8 +21,12 @@ interface HTMLScriptElement : HTMLElement { attribute boolean defer; [CEReactions] attribute DOMString? crossOrigin; - [CEReactions, Pure] - attribute DOMString text; + [CEReactions, SetterThrows] + attribute (TrustedScript or DOMString) innerText; + [CEReactions, Pure, SetterThrows] + attribute (TrustedScript or DOMString) text; + [CEReactions, SetterThrows] + attribute (TrustedScript or DOMString)? textContent; [CEReactions] attribute DOMString integrity; [CEReactions] diff --git a/tests/wpt/meta/trusted-types/HTMLElement-generic.html.ini b/tests/wpt/meta/trusted-types/HTMLElement-generic.html.ini index 13fbd908f76..8ed1a875db3 100644 --- a/tests/wpt/meta/trusted-types/HTMLElement-generic.html.ini +++ b/tests/wpt/meta/trusted-types/HTMLElement-generic.html.ini @@ -1,10 +1,4 @@ [HTMLElement-generic.html] - [TT enabled: script.src\n = String on a\n connected element\n ] - expected: FAIL - - [TT enabled: script.src\n = String on a\n non-connected element\n ] - expected: FAIL - [TT enabled: div.innerHTML\n = String on a\n connected element\n ] expected: FAIL @@ -17,30 +11,6 @@ [TT enabled: iframe.srcdoc\n = String on a\n non-connected element\n ] expected: FAIL - [TT enabled: script.text\n = String on a\n connected element\n ] - expected: FAIL - - [TT enabled: script.text\n = String on a\n non-connected element\n ] - expected: FAIL - - [TT enabled: script.innerText\n = String on a\n connected element\n ] - expected: FAIL - - [TT enabled: script.innerText\n = String on a\n non-connected element\n ] - expected: FAIL - - [TT enabled: script.textContent\n = String on a\n connected element\n ] - expected: FAIL - - [TT enabled: script.textContent\n = String on a\n non-connected element\n ] - expected: FAIL - - [TT enabled: script.src\n = String on a\n connected element\n after removing the "require-trusted-types-for 'script' directive] - expected: FAIL - - [TT enabled: script.src\n = String on a\n non-connected element\n after removing the "require-trusted-types-for 'script' directive] - expected: FAIL - [TT enabled: div.innerHTML\n = String on a\n connected element\n after removing the "require-trusted-types-for 'script' directive] expected: FAIL @@ -52,33 +22,3 @@ [TT enabled: iframe.srcdoc\n = String on a\n non-connected element\n after removing the "require-trusted-types-for 'script' directive] expected: FAIL - - [TT enabled: script.text\n = String on a\n connected element\n after removing the "require-trusted-types-for 'script' directive] - expected: FAIL - - [TT enabled: script.text\n = String on a\n non-connected element\n after removing the "require-trusted-types-for 'script' directive] - expected: FAIL - - [TT enabled: script.innerText\n = String on a\n connected element\n after removing the "require-trusted-types-for 'script' directive] - expected: FAIL - - [TT enabled: script.innerText\n = String on a\n non-connected element\n after removing the "require-trusted-types-for 'script' directive] - expected: FAIL - - [TT enabled: script.textContent\n = String on a\n connected element\n after removing the "require-trusted-types-for 'script' directive] - expected: FAIL - - [TT enabled: script.textContent\n = String on a\n non-connected element\n after removing the "require-trusted-types-for 'script' directive] - expected: FAIL - - [TT enabled: script.src\n = TrustedScript on a\n connected element\n ] - expected: FAIL - - [TT enabled: script.src\n = TrustedScript on a\n non-connected element\n ] - expected: FAIL - - [TT enabled: script.src\n = TrustedScript on a\n connected element\n after removing the "require-trusted-types-for 'script' directive] - expected: FAIL - - [TT enabled: script.src\n = TrustedScript on a\n non-connected element\n after removing the "require-trusted-types-for 'script' directive] - expected: FAIL diff --git a/tests/wpt/meta/trusted-types/block-string-assignment-to-HTMLElement-generic.html.ini b/tests/wpt/meta/trusted-types/block-string-assignment-to-HTMLElement-generic.html.ini index deb942557bf..ed3a70b31ab 100644 --- a/tests/wpt/meta/trusted-types/block-string-assignment-to-HTMLElement-generic.html.ini +++ b/tests/wpt/meta/trusted-types/block-string-assignment-to-HTMLElement-generic.html.ini @@ -1,7 +1,4 @@ [block-string-assignment-to-HTMLElement-generic.html] - [script.src accepts only TrustedScriptURL] - expected: FAIL - [div.innerHTML accepts only TrustedHTML] expected: FAIL @@ -13,12 +10,3 @@ [iframe.srcdoc accepts string and null after default policy was created] expected: FAIL - - [script.text accepts only TrustedScript] - expected: FAIL - - [script.innerText accepts only TrustedScript] - expected: FAIL - - [script.textContent accepts only TrustedScript] - expected: FAIL diff --git a/tests/wpt/meta/trusted-types/block-string-assignment-to-text-and-url-sinks.html.ini b/tests/wpt/meta/trusted-types/block-string-assignment-to-text-and-url-sinks.html.ini index 01b68adab9e..1e9f6e44f44 100644 --- a/tests/wpt/meta/trusted-types/block-string-assignment-to-text-and-url-sinks.html.ini +++ b/tests/wpt/meta/trusted-types/block-string-assignment-to-text-and-url-sinks.html.ini @@ -7,12 +7,3 @@ [Setting SVGScriptElement.innerHTML to a plain string] expected: FAIL - - [Setting HTMLScriptElement.innerText to a plain string] - expected: FAIL - - [Setting HTMLScriptElement.textContent to a plain string] - expected: FAIL - - [Setting HTMLScriptElement.text to a plain string] - expected: FAIL diff --git a/tests/wpt/meta/trusted-types/default-policy.html.ini b/tests/wpt/meta/trusted-types/default-policy.html.ini index ae7c1cae260..15588646951 100644 --- a/tests/wpt/meta/trusted-types/default-policy.html.ini +++ b/tests/wpt/meta/trusted-types/default-policy.html.ini @@ -3,15 +3,9 @@ [Count SecurityPolicyViolation events.] expected: TIMEOUT - [script.src no default policy] - expected: FAIL - [div.innerHTML no default policy] expected: FAIL - [script.text no default policy] - expected: FAIL - [div.innerHTML default] expected: FAIL @@ -26,18 +20,3 @@ [div.innerHTML typeerror] expected: FAIL - - [script.text default] - expected: FAIL - - [script.text null] - expected: FAIL - - [script.text throw] - expected: FAIL - - [script.text undefined] - expected: FAIL - - [script.text typeerror] - expected: FAIL diff --git a/tests/wpt/meta/trusted-types/empty-default-policy.html.ini b/tests/wpt/meta/trusted-types/empty-default-policy.html.ini index 123f9ae5aab..4f06e4c971f 100644 --- a/tests/wpt/meta/trusted-types/empty-default-policy.html.ini +++ b/tests/wpt/meta/trusted-types/empty-default-policy.html.ini @@ -5,6 +5,3 @@ [div.innerHTML default] expected: FAIL - - [script.text default] - expected: FAIL diff --git a/tests/wpt/meta/trusted-types/require-trusted-types-for-report-only.html.ini b/tests/wpt/meta/trusted-types/require-trusted-types-for-report-only.html.ini index 33b34fe9928..39ec281d5f2 100644 --- a/tests/wpt/meta/trusted-types/require-trusted-types-for-report-only.html.ini +++ b/tests/wpt/meta/trusted-types/require-trusted-types-for-report-only.html.ini @@ -1,9 +1,3 @@ [require-trusted-types-for-report-only.html] [Require trusted types for 'script' block create HTML.] expected: FAIL - - [Require trusted types for 'script' block create script.] - expected: FAIL - - [Require trusted types for 'script' block create script URL.] - expected: FAIL diff --git a/tests/wpt/meta/trusted-types/require-trusted-types-for.html.ini b/tests/wpt/meta/trusted-types/require-trusted-types-for.html.ini index 9299429a74c..38d5f9eb35a 100644 --- a/tests/wpt/meta/trusted-types/require-trusted-types-for.html.ini +++ b/tests/wpt/meta/trusted-types/require-trusted-types-for.html.ini @@ -1,9 +1,3 @@ [require-trusted-types-for.html] [Require trusted types for 'script' block create HTML.] expected: FAIL - - [Require trusted types for 'script' block create script.] - expected: FAIL - - [Require trusted types for 'script' block create script URL.] - expected: FAIL diff --git a/tests/wpt/meta/trusted-types/trusted-types-createHTMLDocument.html.ini b/tests/wpt/meta/trusted-types/trusted-types-createHTMLDocument.html.ini index 242959acbb3..cca7dc42f2b 100644 --- a/tests/wpt/meta/trusted-types/trusted-types-createHTMLDocument.html.ini +++ b/tests/wpt/meta/trusted-types/trusted-types-createHTMLDocument.html.ini @@ -1,25 +1,13 @@ [trusted-types-createHTMLDocument.html] - [Trusted Type assignment is blocked. (document)] - expected: FAIL - [Trusted Type instances created in the main doc can be used. (document)] expected: FAIL - [Trusted Type assignment is blocked. (createHTMLDocument)] - expected: FAIL - [Trusted Type instances created in the main doc can be used. (createHTMLDocument)] expected: FAIL - [Trusted Type assignment is blocked. (DOMParser)] - expected: FAIL - [Trusted Type instances created in the main doc can be used. (DOMParser)] expected: FAIL - [Trusted Type assignment is blocked. (XHR)] - expected: FAIL - [Trusted Type instances created in the main doc can be used. (XHR)] expected: FAIL diff --git a/tests/wpt/meta/trusted-types/trusted-types-report-only.html.ini b/tests/wpt/meta/trusted-types/trusted-types-report-only.html.ini index 89c8c2d46d3..253b126c18f 100644 --- a/tests/wpt/meta/trusted-types/trusted-types-report-only.html.ini +++ b/tests/wpt/meta/trusted-types/trusted-types-report-only.html.ini @@ -1,15 +1,6 @@ [trusted-types-report-only.html] - [Trusted Type violation report-only: assign string to script url] - expected: FAIL - [Trusted Type violation report-only: assign string to html] expected: FAIL - [Trusted Type violation report-only: assign string to script.src] - expected: FAIL - [Trusted Type violation report-only: assign string to script content] expected: FAIL - - [Trusted Type violation report: check report contents] - expected: FAIL diff --git a/tests/wpt/meta/trusted-types/trusted-types-reporting-for-HTMLScriptElement.html.ini b/tests/wpt/meta/trusted-types/trusted-types-reporting-for-HTMLScriptElement.html.ini deleted file mode 100644 index d374cd0978e..00000000000 --- a/tests/wpt/meta/trusted-types/trusted-types-reporting-for-HTMLScriptElement.html.ini +++ /dev/null @@ -1,12 +0,0 @@ -[trusted-types-reporting-for-HTMLScriptElement.html] - [Violation report for plain string (innerText)] - expected: FAIL - - [Violation report for plain string (textContent)] - expected: FAIL - - [Violation report for plain string (src)] - expected: FAIL - - [Violation report for plain string (text)] - expected: FAIL