script/dom/html/
htmlheadelement.rs1use content_security_policy::{CspList, PolicyDisposition, PolicySource};
6use dom_struct::dom_struct;
7use html5ever::{LocalName, Prefix, local_name, ns};
8use js::rust::HandleObject;
9
10use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
11use crate::dom::bindings::inheritance::Castable;
12use crate::dom::bindings::root::DomRoot;
13use crate::dom::document::Document;
14use crate::dom::element::Element;
15use crate::dom::html::htmlelement::HTMLElement;
16use crate::dom::html::htmlmetaelement::HTMLMetaElement;
17use crate::dom::node::{BindContext, Node, NodeTraits, ShadowIncluding};
18use crate::dom::userscripts::load_script;
19use crate::dom::virtualmethods::VirtualMethods;
20use crate::script_runtime::CanGc;
21
22#[dom_struct]
23pub(crate) struct HTMLHeadElement {
24 htmlelement: HTMLElement,
25}
26
27impl HTMLHeadElement {
28 fn new_inherited(
29 local_name: LocalName,
30 prefix: Option<Prefix>,
31 document: &Document,
32 ) -> HTMLHeadElement {
33 HTMLHeadElement {
34 htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
35 }
36 }
37
38 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
39 pub(crate) fn new(
40 local_name: LocalName,
41 prefix: Option<Prefix>,
42 document: &Document,
43 proto: Option<HandleObject>,
44 can_gc: CanGc,
45 ) -> DomRoot<HTMLHeadElement> {
46 let n = Node::reflect_node_with_proto(
47 Box::new(HTMLHeadElement::new_inherited(local_name, prefix, document)),
48 document,
49 proto,
50 can_gc,
51 );
52
53 n.upcast::<Node>().set_weird_parser_insertion_mode();
54 n
55 }
56
57 pub(crate) fn set_content_security_policy(&self) {
59 let doc = self.owner_document();
60
61 if doc.GetHead().as_deref() != Some(self) {
62 return;
63 }
64
65 let mut csp_list: Option<CspList> = None;
66 let node = self.upcast::<Node>();
67 let candidates = node
68 .traverse_preorder(ShadowIncluding::No)
69 .filter_map(DomRoot::downcast::<Element>)
70 .filter(|elem| elem.is::<HTMLMetaElement>())
71 .filter(|elem| {
72 elem.get_string_attribute(&local_name!("http-equiv"))
73 .to_ascii_lowercase() ==
74 *"content-security-policy"
75 })
76 .filter(|elem| {
77 elem.get_attribute(&ns!(), &local_name!("content"))
78 .is_some()
79 });
80
81 for meta in candidates {
82 if let Some(ref content) = meta.get_attribute(&ns!(), &local_name!("content")) {
83 let content = content.value();
84 let content_val = content.trim();
85 if !content_val.is_empty() {
86 let policies =
87 CspList::parse(content_val, PolicySource::Meta, PolicyDisposition::Enforce);
88 match csp_list {
89 Some(ref mut csp_list) => csp_list.append(policies),
90 None => csp_list = Some(policies),
91 }
92 }
93 }
94 }
95
96 doc.set_csp_list(csp_list);
97 }
98}
99
100impl VirtualMethods for HTMLHeadElement {
101 fn super_type(&self) -> Option<&dyn VirtualMethods> {
102 Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
103 }
104 fn bind_to_tree(&self, context: &BindContext, can_gc: CanGc) {
105 if let Some(s) = self.super_type() {
106 s.bind_to_tree(context, can_gc);
107 }
108 load_script(self);
109 }
110}