diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 68efa07537c..a83629b4046 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -4299,7 +4299,14 @@ impl Document { } pub(crate) fn set_csp_list(&self, csp_list: Option) { - self.policy_container.borrow_mut().set_csp_list(csp_list); + if let Some(new_list) = csp_list { + let mut current = self.get_csp_list(); + match current { + Some(ref mut existing) => existing.append(new_list), + None => current = Some(new_list), + } + self.policy_container.borrow_mut().set_csp_list(current); + } } pub(crate) fn get_csp_list(&self) -> Option { diff --git a/components/script/dom/htmlheadelement.rs b/components/script/dom/htmlheadelement.rs index 7b2d715318f..9289163a195 100644 --- a/components/script/dom/htmlheadelement.rs +++ b/components/script/dom/htmlheadelement.rs @@ -2,19 +2,15 @@ * 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 content_security_policy::{CspList, PolicyDisposition, PolicySource}; use dom_struct::dom_struct; -use html5ever::{LocalName, Prefix, local_name, ns}; +use html5ever::{LocalName, Prefix}; use js::rust::HandleObject; -use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::root::DomRoot; use crate::dom::document::Document; -use crate::dom::element::Element; use crate::dom::htmlelement::HTMLElement; -use crate::dom::htmlmetaelement::HTMLMetaElement; -use crate::dom::node::{BindContext, Node, NodeTraits, ShadowIncluding}; +use crate::dom::node::{BindContext, Node}; use crate::dom::userscripts::load_script; use crate::dom::virtualmethods::VirtualMethods; use crate::script_runtime::CanGc; @@ -53,48 +49,6 @@ impl HTMLHeadElement { n.upcast::().set_weird_parser_insertion_mode(); n } - - /// - pub(crate) fn set_content_security_policy(&self) { - let doc = self.owner_document(); - - if doc.GetHead().as_deref() != Some(self) { - return; - } - - let mut csp_list: Option = None; - let node = self.upcast::(); - let candidates = node - .traverse_preorder(ShadowIncluding::No) - .filter_map(DomRoot::downcast::) - .filter(|elem| elem.is::()) - .filter(|elem| { - elem.get_string_attribute(&local_name!("http-equiv")) - .to_ascii_lowercase() == - *"content-security-policy" - }) - .filter(|elem| { - elem.get_attribute(&ns!(), &local_name!("content")) - .is_some() - }); - - for meta in candidates { - if let Some(ref content) = meta.get_attribute(&ns!(), &local_name!("content")) { - let content = content.value(); - let content_val = content.trim(); - if !content_val.is_empty() { - let policies = - CspList::parse(content_val, PolicySource::Meta, PolicyDisposition::Enforce); - match csp_list { - Some(ref mut csp_list) => csp_list.append(policies), - None => csp_list = Some(policies), - } - } - } - } - - doc.set_csp_list(csp_list); - } } impl VirtualMethods for HTMLHeadElement { diff --git a/components/script/dom/htmlmetaelement.rs b/components/script/dom/htmlmetaelement.rs index e94a5e1ff33..875d790c60c 100644 --- a/components/script/dom/htmlmetaelement.rs +++ b/components/script/dom/htmlmetaelement.rs @@ -2,6 +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 content_security_policy::{CspList, PolicyDisposition, PolicySource}; use dom_struct::dom_struct; use html5ever::{LocalName, Prefix, local_name, ns}; use js::rust::HandleObject; @@ -118,12 +119,47 @@ impl HTMLMetaElement { /// fn apply_csp_list(&self) { if let Some(parent) = self.upcast::().GetParentElement() { - if let Some(head) = parent.downcast::() { - head.set_content_security_policy(); + if parent.downcast::().is_some() { + self.set_content_security_policy(); } } } + /// + pub(crate) fn set_content_security_policy(&self) { + let doc = self.owner_document(); + + let meta_element = self.upcast::(); + + if meta_element + .get_string_attribute(&local_name!("http-equiv")) + .to_ascii_lowercase() != + *"content-security-policy" || + meta_element + .get_attribute(&ns!(), &local_name!("content")) + .is_none() + { + return; + } + + let mut csp_list: Option = None; + + if let Some(ref content) = meta_element.get_attribute(&ns!(), &local_name!("content")) { + let content = content.value(); + let content_val = content.trim(); + if !content_val.is_empty() { + let policies = + CspList::parse(content_val, PolicySource::Meta, PolicyDisposition::Enforce); + match csp_list { + Some(ref mut csp_list) => csp_list.append(policies), + None => csp_list = Some(policies), + } + } + } + + doc.set_csp_list(csp_list); + } + /// fn declarative_refresh(&self) { if !self.upcast::().is_in_a_document_tree() { diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs index 9e45124522a..fa55545aecd 100644 --- a/components/script/dom/servoparser/mod.rs +++ b/components/script/dom/servoparser/mod.rs @@ -821,15 +821,7 @@ impl ParserContext { let Some(parser) = self.parser.as_ref().map(|p| p.root()) else { return; }; - let new_csp_list = match parser.document.get_csp_list() { - None => parent_csp_list.clone(), - Some(original_csp_list) => { - let mut appended_csp_list = original_csp_list.clone(); - appended_csp_list.append(parent_csp_list.clone()); - appended_csp_list.to_owned() - }, - }; - parser.document.set_csp_list(Some(new_csp_list)); + parser.document.set_csp_list(Some(parent_csp_list.clone())); } } diff --git a/tests/wpt/meta/MANIFEST.json b/tests/wpt/meta/MANIFEST.json index deff780986e..91f9258c508 100644 --- a/tests/wpt/meta/MANIFEST.json +++ b/tests/wpt/meta/MANIFEST.json @@ -397319,6 +397319,10 @@ "062d823228a0bad1ed84fc432a262501e11a7d79", [] ], + "meta-append-header.html.headers": [ + "85de8bd415def35ca45c0abf74590cdfa393d0f4", + [] + ], "meta-outside-head.sub.html.sub.headers": [ "8e90073147a233a74727a3ba03307c1564dc3224", [] @@ -572954,6 +572958,13 @@ {} ] ], + "meta-append-header.html": [ + "2b95e92fdb72b54b716ac51196acc93afab17f92", + [ + null, + {} + ] + ], "meta-img-src.html": [ "bc7ffd66a70d78c4ae9f2cc19f8c2df70914243d", [ @@ -572968,6 +572979,13 @@ {} ] ], + "meta-multiple-csp.html": [ + "f09ead7f3e7588f88aadda68e72b1c9362d59910", + [ + null, + {} + ] + ], "meta-outside-head.sub.html": [ "7a706c2fc5f5d21b76e7f62f224c3ff74c80ba79", [ diff --git a/tests/wpt/tests/content-security-policy/meta/meta-append-header.html b/tests/wpt/tests/content-security-policy/meta/meta-append-header.html new file mode 100644 index 00000000000..2b95e92fdb7 --- /dev/null +++ b/tests/wpt/tests/content-security-policy/meta/meta-append-header.html @@ -0,0 +1,32 @@ + + + + + + + + diff --git a/tests/wpt/tests/content-security-policy/meta/meta-append-header.html.headers b/tests/wpt/tests/content-security-policy/meta/meta-append-header.html.headers new file mode 100644 index 00000000000..85de8bd415d --- /dev/null +++ b/tests/wpt/tests/content-security-policy/meta/meta-append-header.html.headers @@ -0,0 +1 @@ +Content-Security-Policy: script-src 'nonce-abc' diff --git a/tests/wpt/tests/content-security-policy/meta/meta-multiple-csp.html b/tests/wpt/tests/content-security-policy/meta/meta-multiple-csp.html new file mode 100644 index 00000000000..f09ead7f3e7 --- /dev/null +++ b/tests/wpt/tests/content-security-policy/meta/meta-multiple-csp.html @@ -0,0 +1,33 @@ + + + + + + + + +