mirror of
https://github.com/servo/servo.git
synced 2025-07-22 23:03:42 +01:00
Implement Trusted types document write sinks (#36824)
Implements the Document.write algorithm covering Trusted HTML. Part of #36258 Signed-off-by: Tim van der Lippe <tvanderlippe@gmail.com> Signed-off-by: Tim van der Lippe <tvanderlippe@gmail.com>
This commit is contained in:
parent
43edab336a
commit
c00e0aae61
9 changed files with 142 additions and 107 deletions
|
@ -103,7 +103,9 @@ use crate::dom::bindings::codegen::Bindings::WindowBinding::{
|
|||
};
|
||||
use crate::dom::bindings::codegen::Bindings::XPathEvaluatorBinding::XPathEvaluatorMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::XPathNSResolverBinding::XPathNSResolver;
|
||||
use crate::dom::bindings::codegen::UnionTypes::{NodeOrString, StringOrElementCreationOptions};
|
||||
use crate::dom::bindings::codegen::UnionTypes::{
|
||||
NodeOrString, StringOrElementCreationOptions, TrustedHTMLOrString,
|
||||
};
|
||||
use crate::dom::bindings::error::{Error, ErrorInfo, ErrorResult, Fallible};
|
||||
use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
|
||||
use crate::dom::bindings::num::Finite;
|
||||
|
@ -184,6 +186,7 @@ use crate::dom::touch::Touch;
|
|||
use crate::dom::touchevent::TouchEvent as DomTouchEvent;
|
||||
use crate::dom::touchlist::TouchList;
|
||||
use crate::dom::treewalker::TreeWalker;
|
||||
use crate::dom::trustedhtml::TrustedHTML;
|
||||
use crate::dom::types::VisibilityStateEntry;
|
||||
use crate::dom::uievent::UIEvent;
|
||||
use crate::dom::virtualmethods::vtable_for;
|
||||
|
@ -3818,6 +3821,90 @@ impl Document {
|
|||
.Performance()
|
||||
.queue_entry(entry.upcast::<PerformanceEntry>(), can_gc);
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#document-write-steps>
|
||||
fn write(
|
||||
&self,
|
||||
text: Vec<TrustedHTMLOrString>,
|
||||
line_feed: bool,
|
||||
containing_class: &str,
|
||||
field: &str,
|
||||
can_gc: CanGc,
|
||||
) -> ErrorResult {
|
||||
// Step 1: Let string be the empty string.
|
||||
let mut strings: Vec<String> = Vec::with_capacity(text.len());
|
||||
// Step 2: Let isTrusted be false if text contains a string; otherwise true.
|
||||
let mut is_trusted = true;
|
||||
// Step 3: For each value of text:
|
||||
for value in text {
|
||||
match value {
|
||||
// Step 3.1: If value is a TrustedHTML object, then append value's associated data to string.
|
||||
TrustedHTMLOrString::TrustedHTML(trusted_html) => {
|
||||
strings.push(trusted_html.to_string().to_owned());
|
||||
},
|
||||
TrustedHTMLOrString::String(str_) => {
|
||||
// Step 2: Let isTrusted be false if text contains a string; otherwise true.
|
||||
is_trusted = false;
|
||||
// Step 3.2: Otherwise, append value to string.
|
||||
strings.push(str_.into());
|
||||
},
|
||||
};
|
||||
}
|
||||
let mut string = itertools::join(strings, "");
|
||||
// Step 4: If isTrusted is false, set string to the result of invoking the
|
||||
// Get Trusted Type compliant string algorithm with TrustedHTML,
|
||||
// this's relevant global object, string, sink, and "script".
|
||||
if !is_trusted {
|
||||
string = TrustedHTML::get_trusted_script_compliant_string(
|
||||
&self.global(),
|
||||
TrustedHTMLOrString::String(string.into()),
|
||||
containing_class,
|
||||
field,
|
||||
can_gc,
|
||||
)?;
|
||||
}
|
||||
// Step 5: If lineFeed is true, append U+000A LINE FEED to string.
|
||||
if line_feed {
|
||||
string.push('\n');
|
||||
}
|
||||
// Step 6: If document is an XML document, then throw an "InvalidStateError" DOMException.
|
||||
if !self.is_html_document() {
|
||||
return Err(Error::InvalidState);
|
||||
}
|
||||
|
||||
// Step 7: If document's throw-on-dynamic-markup-insertion counter is greater than 0,
|
||||
// then throw an "InvalidStateError" DOMException.
|
||||
if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
|
||||
return Err(Error::InvalidState);
|
||||
}
|
||||
|
||||
// Step 8: If document's active parser was aborted is true, then return.
|
||||
if !self.is_active() || self.active_parser_was_aborted.get() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let parser = match self.get_current_parser() {
|
||||
Some(ref parser) if parser.can_write() => DomRoot::from_ref(&**parser),
|
||||
// Step 9: If the insertion point is undefined, then:
|
||||
_ => {
|
||||
// Step 9.1: If document's unload counter is greater than 0 or
|
||||
// document's ignore-destructive-writes counter is greater than 0, then return.
|
||||
if self.is_prompting_or_unloading() ||
|
||||
self.ignore_destructive_writes_counter.get() > 0
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
// Step 9.2: Run the document open steps with document.
|
||||
self.Open(None, None, can_gc)?;
|
||||
self.get_current_parser().unwrap()
|
||||
},
|
||||
};
|
||||
|
||||
// Steps 10-11.
|
||||
parser.write(string.into(), can_gc);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn is_character_value_key(key: &Key) -> bool {
|
||||
|
@ -6408,54 +6495,17 @@ impl DocumentMethods<crate::DomTypeHolder> for Document {
|
|||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-document-write
|
||||
fn Write(&self, text: Vec<DOMString>, can_gc: CanGc) -> ErrorResult {
|
||||
if !self.is_html_document() {
|
||||
// Step 1.
|
||||
return Err(Error::InvalidState);
|
||||
}
|
||||
|
||||
// Step 2.
|
||||
if self.throw_on_dynamic_markup_insertion_counter.get() > 0 {
|
||||
return Err(Error::InvalidState);
|
||||
}
|
||||
|
||||
// Step 3 - what specifies the is_active() part here?
|
||||
if !self.is_active() || self.active_parser_was_aborted.get() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let parser = match self.get_current_parser() {
|
||||
Some(ref parser) if parser.can_write() => DomRoot::from_ref(&**parser),
|
||||
_ => {
|
||||
// Either there is no parser, which means the parsing ended;
|
||||
// or script nesting level is 0, which means the method was
|
||||
// called from outside a parser-executed script.
|
||||
if self.is_prompting_or_unloading() ||
|
||||
self.ignore_destructive_writes_counter.get() > 0
|
||||
{
|
||||
// Step 4.
|
||||
return Ok(());
|
||||
}
|
||||
// Step 5.
|
||||
self.Open(None, None, can_gc)?;
|
||||
self.get_current_parser().unwrap()
|
||||
},
|
||||
};
|
||||
|
||||
// Step 7.
|
||||
// TODO: handle reload override buffer.
|
||||
|
||||
// Steps 6-8.
|
||||
parser.write(text, can_gc);
|
||||
|
||||
// Step 9.
|
||||
Ok(())
|
||||
fn Write(&self, text: Vec<TrustedHTMLOrString>, can_gc: CanGc) -> ErrorResult {
|
||||
// The document.write(...text) method steps are to run the document write steps
|
||||
// with this, text, false, and "Document write".
|
||||
self.write(text, false, "Document", "write", can_gc)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-document-writeln
|
||||
fn Writeln(&self, mut text: Vec<DOMString>, can_gc: CanGc) -> ErrorResult {
|
||||
text.push("\n".into());
|
||||
self.Write(text, can_gc)
|
||||
fn Writeln(&self, text: Vec<TrustedHTMLOrString>, can_gc: CanGc) -> ErrorResult {
|
||||
// The document.writeln(...text) method steps are to run the document write steps
|
||||
// with this, text, true, and "Document writeln".
|
||||
self.write(text, true, "Document", "writeln", can_gc)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-document-close
|
||||
|
|
|
@ -357,16 +357,14 @@ impl ServoParser {
|
|||
}
|
||||
|
||||
/// Steps 6-8 of <https://html.spec.whatwg.org/multipage/#document.write()>
|
||||
pub(crate) fn write(&self, text: Vec<DOMString>, can_gc: CanGc) {
|
||||
pub(crate) fn write(&self, text: DOMString, can_gc: CanGc) {
|
||||
assert!(self.can_write());
|
||||
|
||||
if self.document.has_pending_parsing_blocking_script() {
|
||||
// There is already a pending parsing blocking script so the
|
||||
// parser is suspended, we just append everything to the
|
||||
// script input and abort these steps.
|
||||
for chunk in text {
|
||||
self.script_input.push_back(String::from(chunk).into());
|
||||
}
|
||||
self.script_input.push_back(String::from(text).into());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -376,9 +374,7 @@ impl ServoParser {
|
|||
assert!(self.script_input.is_empty());
|
||||
|
||||
let input = BufferQueue::default();
|
||||
for chunk in text {
|
||||
input.push_back(String::from(chunk).into());
|
||||
}
|
||||
input.push_back(String::from(text).into());
|
||||
|
||||
let profiler_chan = self
|
||||
.document
|
||||
|
|
|
@ -2,13 +2,19 @@
|
|||
* 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::TrustedHTMLBinding::TrustedHTMLMethods;
|
||||
use crate::dom::bindings::codegen::UnionTypes::TrustedHTMLOrString;
|
||||
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 +36,37 @@ impl TrustedHTML {
|
|||
pub(crate) fn new(data: String, global: &GlobalScope, can_gc: CanGc) -> DomRoot<Self> {
|
||||
reflect_dom_object(Box::new(Self::new_inherited(data)), global, can_gc)
|
||||
}
|
||||
|
||||
pub(crate) fn get_trusted_script_compliant_string(
|
||||
global: &GlobalScope,
|
||||
value: TrustedHTMLOrString,
|
||||
containing_class: &str,
|
||||
field: &str,
|
||||
can_gc: CanGc,
|
||||
) -> Fallible<String> {
|
||||
match value {
|
||||
TrustedHTMLOrString::String(value) => {
|
||||
let sink = format!("{} {}", containing_class, field);
|
||||
TrustedTypePolicyFactory::get_trusted_type_compliant_string(
|
||||
TrustedType::TrustedHTML,
|
||||
global,
|
||||
value.as_ref().to_owned(),
|
||||
&sink,
|
||||
"'script'",
|
||||
can_gc,
|
||||
)
|
||||
},
|
||||
|
||||
TrustedHTMLOrString::TrustedHTML(trusted_html) => Ok(trusted_html.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for TrustedHTML {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(&self.data)
|
||||
}
|
||||
}
|
||||
|
||||
impl TrustedHTMLMethods<crate::DomTypeHolder> for TrustedHTML {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue