mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Merge 7e61cee526
into 5ef66ce386
This commit is contained in:
commit
8dbcb49906
8 changed files with 133 additions and 60 deletions
|
@ -4299,7 +4299,14 @@ impl Document {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_csp_list(&self, csp_list: Option<CspList>) {
|
pub(crate) fn set_csp_list(&self, csp_list: Option<CspList>) {
|
||||||
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<CspList> {
|
pub(crate) fn get_csp_list(&self) -> Option<CspList> {
|
||||||
|
|
|
@ -2,19 +2,15 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use content_security_policy::{CspList, PolicyDisposition, PolicySource};
|
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
use html5ever::{LocalName, Prefix, local_name, ns};
|
use html5ever::{LocalName, Prefix};
|
||||||
use js::rust::HandleObject;
|
use js::rust::HandleObject;
|
||||||
|
|
||||||
use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
|
|
||||||
use crate::dom::bindings::inheritance::Castable;
|
use crate::dom::bindings::inheritance::Castable;
|
||||||
use crate::dom::bindings::root::DomRoot;
|
use crate::dom::bindings::root::DomRoot;
|
||||||
use crate::dom::document::Document;
|
use crate::dom::document::Document;
|
||||||
use crate::dom::element::Element;
|
|
||||||
use crate::dom::htmlelement::HTMLElement;
|
use crate::dom::htmlelement::HTMLElement;
|
||||||
use crate::dom::htmlmetaelement::HTMLMetaElement;
|
use crate::dom::node::{BindContext, Node};
|
||||||
use crate::dom::node::{BindContext, Node, NodeTraits, ShadowIncluding};
|
|
||||||
use crate::dom::userscripts::load_script;
|
use crate::dom::userscripts::load_script;
|
||||||
use crate::dom::virtualmethods::VirtualMethods;
|
use crate::dom::virtualmethods::VirtualMethods;
|
||||||
use crate::script_runtime::CanGc;
|
use crate::script_runtime::CanGc;
|
||||||
|
@ -53,48 +49,6 @@ impl HTMLHeadElement {
|
||||||
n.upcast::<Node>().set_weird_parser_insertion_mode();
|
n.upcast::<Node>().set_weird_parser_insertion_mode();
|
||||||
n
|
n
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://html.spec.whatwg.org/multipage/#attr-meta-http-equiv-content-security-policy>
|
|
||||||
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<CspList> = None;
|
|
||||||
let node = self.upcast::<Node>();
|
|
||||||
let candidates = node
|
|
||||||
.traverse_preorder(ShadowIncluding::No)
|
|
||||||
.filter_map(DomRoot::downcast::<Element>)
|
|
||||||
.filter(|elem| elem.is::<HTMLMetaElement>())
|
|
||||||
.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 {
|
impl VirtualMethods for HTMLHeadElement {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use content_security_policy::{CspList, PolicyDisposition, PolicySource};
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
use html5ever::{LocalName, Prefix, local_name, ns};
|
use html5ever::{LocalName, Prefix, local_name, ns};
|
||||||
use js::rust::HandleObject;
|
use js::rust::HandleObject;
|
||||||
|
@ -118,12 +119,47 @@ impl HTMLMetaElement {
|
||||||
/// <https://html.spec.whatwg.org/multipage/#attr-meta-http-equiv-content-security-policy>
|
/// <https://html.spec.whatwg.org/multipage/#attr-meta-http-equiv-content-security-policy>
|
||||||
fn apply_csp_list(&self) {
|
fn apply_csp_list(&self) {
|
||||||
if let Some(parent) = self.upcast::<Node>().GetParentElement() {
|
if let Some(parent) = self.upcast::<Node>().GetParentElement() {
|
||||||
if let Some(head) = parent.downcast::<HTMLHeadElement>() {
|
if parent.downcast::<HTMLHeadElement>().is_some() {
|
||||||
head.set_content_security_policy();
|
self.set_content_security_policy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <https://html.spec.whatwg.org/multipage/#attr-meta-http-equiv-content-security-policy>
|
||||||
|
pub(crate) fn set_content_security_policy(&self) {
|
||||||
|
let doc = self.owner_document();
|
||||||
|
|
||||||
|
let meta_element = self.upcast::<Element>();
|
||||||
|
|
||||||
|
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<CspList> = 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);
|
||||||
|
}
|
||||||
|
|
||||||
/// <https://html.spec.whatwg.org/multipage/#shared-declarative-refresh-steps>
|
/// <https://html.spec.whatwg.org/multipage/#shared-declarative-refresh-steps>
|
||||||
fn declarative_refresh(&self) {
|
fn declarative_refresh(&self) {
|
||||||
if !self.upcast::<Node>().is_in_a_document_tree() {
|
if !self.upcast::<Node>().is_in_a_document_tree() {
|
||||||
|
|
|
@ -821,15 +821,7 @@ impl ParserContext {
|
||||||
let Some(parser) = self.parser.as_ref().map(|p| p.root()) else {
|
let Some(parser) = self.parser.as_ref().map(|p| p.root()) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let new_csp_list = match parser.document.get_csp_list() {
|
parser.document.set_csp_list(Some(parent_csp_list.clone()));
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
18
tests/wpt/meta/MANIFEST.json
vendored
18
tests/wpt/meta/MANIFEST.json
vendored
|
@ -397319,6 +397319,10 @@
|
||||||
"062d823228a0bad1ed84fc432a262501e11a7d79",
|
"062d823228a0bad1ed84fc432a262501e11a7d79",
|
||||||
[]
|
[]
|
||||||
],
|
],
|
||||||
|
"meta-append-header.html.headers": [
|
||||||
|
"85de8bd415def35ca45c0abf74590cdfa393d0f4",
|
||||||
|
[]
|
||||||
|
],
|
||||||
"meta-outside-head.sub.html.sub.headers": [
|
"meta-outside-head.sub.html.sub.headers": [
|
||||||
"8e90073147a233a74727a3ba03307c1564dc3224",
|
"8e90073147a233a74727a3ba03307c1564dc3224",
|
||||||
[]
|
[]
|
||||||
|
@ -572954,6 +572958,13 @@
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"meta-append-header.html": [
|
||||||
|
"2b95e92fdb72b54b716ac51196acc93afab17f92",
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"meta-img-src.html": [
|
"meta-img-src.html": [
|
||||||
"bc7ffd66a70d78c4ae9f2cc19f8c2df70914243d",
|
"bc7ffd66a70d78c4ae9f2cc19f8c2df70914243d",
|
||||||
[
|
[
|
||||||
|
@ -572968,6 +572979,13 @@
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"meta-multiple-csp.html": [
|
||||||
|
"f09ead7f3e7588f88aadda68e72b1c9362d59910",
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"meta-outside-head.sub.html": [
|
"meta-outside-head.sub.html": [
|
||||||
"7a706c2fc5f5d21b76e7f62f224c3ff74c80ba79",
|
"7a706c2fc5f5d21b76e7f62f224c3ff74c80ba79",
|
||||||
[
|
[
|
||||||
|
|
32
tests/wpt/tests/content-security-policy/meta/meta-append-header.html
vendored
Normal file
32
tests/wpt/tests/content-security-policy/meta/meta-append-header.html
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="img-src 'none'">
|
||||||
|
<script nonce="abc" src="/resources/testharness.js"></script>
|
||||||
|
<script nonce="abc" src="/resources/testharnessreport.js"></script>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<script nonce="abc">
|
||||||
|
promise_test(t => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const img = document.createElement("img");
|
||||||
|
img.src = "/content-security-policy/support/fail.png";
|
||||||
|
|
||||||
|
img.onload = () => reject("Image loaded unexpectedly");
|
||||||
|
img.onerror = (e) => resolve()
|
||||||
|
|
||||||
|
document.body.appendChild(img);
|
||||||
|
});
|
||||||
|
}, "dynamic img-src is blocked by meta CSP");
|
||||||
|
|
||||||
|
promise_test(t => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const script = document.createElement("script");
|
||||||
|
script.src = "../resources/ran.js";
|
||||||
|
|
||||||
|
script.onload = () => reject("Script executed unexpectedly");
|
||||||
|
script.onerror = () => resolve();
|
||||||
|
|
||||||
|
document.body.appendChild(script);
|
||||||
|
});
|
||||||
|
}, "script without `abc` nonce is blocked by header CSP");
|
||||||
|
</script>
|
||||||
|
</body>
|
1
tests/wpt/tests/content-security-policy/meta/meta-append-header.html.headers
vendored
Normal file
1
tests/wpt/tests/content-security-policy/meta/meta-append-header.html.headers
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Content-Security-Policy: script-src 'nonce-abc'
|
33
tests/wpt/tests/content-security-policy/meta/meta-multiple-csp.html
vendored
Normal file
33
tests/wpt/tests/content-security-policy/meta/meta-multiple-csp.html
vendored
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'nonce-abc'">
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="img-src 'none'">
|
||||||
|
<script nonce="abc" src="/resources/testharness.js"></script>
|
||||||
|
<script nonce="abc" src="/resources/testharnessreport.js"></script>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<script nonce="abc">
|
||||||
|
promise_test(t => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const img = document.createElement("img");
|
||||||
|
img.src = "/content-security-policy/support/fail.png";
|
||||||
|
|
||||||
|
img.onload = () => reject("Image loaded unexpectedly");
|
||||||
|
img.onerror = (e) => resolve()
|
||||||
|
|
||||||
|
document.body.appendChild(img);
|
||||||
|
});
|
||||||
|
}, "dynamic img-src is blocked by meta CSP");
|
||||||
|
|
||||||
|
promise_test(t => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const script = document.createElement("script");
|
||||||
|
script.src = "../resources/ran.js";
|
||||||
|
|
||||||
|
script.onload = () => reject("Script executed unexpectedly");
|
||||||
|
script.onerror = () => resolve();
|
||||||
|
|
||||||
|
document.body.appendChild(script);
|
||||||
|
});
|
||||||
|
}, "script without `abc` nonce is blocked by meta CSP");
|
||||||
|
</script>
|
||||||
|
</body>
|
Loading…
Add table
Add a link
Reference in a new issue