script: Add or remove elements in sanitizer (#44481)

Implement the `allowElement`, `removeElement` and
`replaceElementWithChildren` methods of the `Sanitizer` interface, which
add or remove elements in a sanitizer.

Specification:
- https://wicg.github.io/sanitizer-api/#dom-sanitizer-allowelement
- https://wicg.github.io/sanitizer-api/#dom-sanitizer-removeelement
-
https://wicg.github.io/sanitizer-api/#dom-sanitizer-replaceelementwithchildren

Testing: Covered by WPT tests in `sanitizer-api/` subdirectory.
Additionally, some tests in `sanitizer-basic-filtering.tentative.html`
are changed from ERROR to FAIL because of this implementation.
Fixes: Part of #43948

---------

Signed-off-by: Kingsley Yung <kingsley@kkoyung.dev>
This commit is contained in:
Kingsley Yung
2026-04-24 23:07:01 +08:00
committed by GitHub
parent 93ae710c07
commit 430105468f
7 changed files with 842 additions and 90 deletions

View File

@@ -19,9 +19,10 @@ use crate::dom::bindings::codegen::Bindings::SanitizerBinding::{
use crate::dom::bindings::codegen::UnionTypes::SanitizerConfigOrSanitizerPresets;
use crate::dom::bindings::domname::is_valid_attribute_local_name;
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto_and_cx};
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_proto_and_cx};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::types::Console;
use crate::dom::window::Window;
#[dom_struct]
@@ -190,12 +191,291 @@ impl SanitizerMethods<crate::DomTypeHolder> for Sanitizer {
// Step 10. Return config.
(*config).clone()
}
/// <https://wicg.github.io/sanitizer-api/#dom-sanitizer-allowelement>
fn AllowElement(&self, element: SanitizerElementWithAttributes) -> bool {
// Step 1. Let configuration be thiss configuration.
let mut configuration = self.configuration.borrow_mut();
// Step 2. Assert: configuration is valid.
assert!(configuration.is_valid());
// Step 3. Set element to the result of canonicalize a sanitizer element with attributes
// with element.
let mut element = element.canonicalize();
// Step 4. If configuration["elements"] exists:
if configuration.elements.is_some() {
// Step 4.1. Set modified to the result of remove element from
// configuration["replaceWithChildrenElements"].
let modified = if let Some(replace_with_children_elements) =
&mut configuration.replaceWithChildrenElements
{
replace_with_children_elements.remove_item(&element)
} else {
false
};
// Step 4.2. Comment: We need to make sure the per-element attributes do not overlap
// with global attributes.
match &configuration.attributes {
// Step 4.3. If configuration["attributes"] exists:
Some(configuration_attributes) => {
// Step 4.3.1. If element["attributes"] exists:
if let Some(element_attributes) = element.attributes_mut() {
// Step 4.3.1.1. Set element["attributes"] to remove duplicates from
// element["attributes"].
element_attributes.remove_duplicates();
// Step 4.3.1.2. Set element["attributes"] to the difference of
// element["attributes"] and configuration["attributes"].
element_attributes.difference(configuration_attributes);
// Step 4.3.1.3. If configuration["dataAttributes"] is true:
if configuration.dataAttributes == Some(true) {
// Step 4.3.1.3.1. Remove all items item from element["attributes"]
// where item is a custom data attribute.
element_attributes.retain(|attribute| {
!is_custom_data_attribute(
&attribute.name().str(),
attribute
.namespace()
.map(|namespace| namespace.str())
.as_deref(),
)
});
}
}
// Step 4.3.2. If element["removeAttributes"] exists:
if let Some(element_remove_attributes) = element.remove_attributes_mut() {
// Step 4.3.2.1. set element["removeattributes"] to remove duplicates from
// element["removeattributes"].
element_remove_attributes.remove_duplicates();
// Step 4.3.2.2. set element["removeattributes"] to the intersection of
// element["removeattributes"] and configuration["attributes"].
element_remove_attributes.intersection(configuration_attributes);
}
},
// Step 4.4. Otherwise:
None => {
// NOTE: To avoid borrowing `element` again at Step 4.4.1.2 and 4.4.1.3 after
// borrowing `element` mutably at the beginning of Step 4.4.1, we clone
// element["attributes"] first, and call `set_attributes` at the end of Step
// 4.4.1 to put it back into `element`.
// Step 4.4.1. If element["attributes"] exists:
if let Some(mut element_attributes) = element.attributes_mut().cloned() {
// Step 4.4.1.1. Set element["attributes"] to remove duplicates from
// element["attributes"].
element_attributes.remove_duplicates();
// Step 4.4.1.2. Set element["attributes"] to the difference of
// element["attributes"] and element["removeAttributes"] with default « ».
element_attributes
.difference(element.remove_attributes().unwrap_or_default());
// Step 4.4.1.3. Remove element["removeAttributes"].
element.set_remove_attributes(None);
// Step 4.4.1.4. Set element["attributes"] to the difference of
// element["attributes"] and configuration["removeAttributes"].
element_attributes.difference(
configuration
.removeAttributes
.as_deref()
.unwrap_or_default(),
);
element.set_attributes(Some(element_attributes));
}
// Step 4.4.2. If element["removeAttributes"] exists:
if let Some(mut element_remove_attributes) = element.remove_attributes_mut() {
// Step 4.4.2.1. Set element["removeAttributes"] to remove duplicates from
// element["removeAttributes"].
element_remove_attributes = element_remove_attributes.remove_duplicates();
// Step 4.4.2.2. Set element["removeAttributes"] to the difference of
// element["removeAttributes"] and configuration["removeAttributes"].
element_remove_attributes.difference(
configuration
.removeAttributes
.as_deref()
.unwrap_or_default(),
);
}
},
}
// Step 4.5. If configuration["elements"] does not contain element:
let configuration_elements = configuration
.elements
.as_mut()
.expect("Guaranteed by Step 4");
if !configuration_elements.contains_item(&element) {
// Step 4.5.1. Comment: This is the case with a global allow-list that does not yet
// contain element.
// Step 4.5.2. Append element to configuration["elements"].
configuration_elements.push(element.clone());
// Step 4.5.3. Return true.
return true;
}
// Step 4.6. Comment: This is the case with a global allow-list that already contains
// element.
// Step 4.7. Let current element be the item in configuration["elements"] where
// item["name"] equals element["name"] and item["namespace"] equals
// element["namespace"].
let current_element = configuration_elements
.iter()
.find(|item| {
item.name() == element.name() && item.namespace() == element.namespace()
})
.expect("Guaranteed by Step 4.5 and Step 4.5.2");
// Step 4.8. If element equals current element then return modified.
if element == *current_element {
return modified;
}
// Step 4.9. Remove element from configuration["elements"].
configuration_elements.remove_item(&element);
// Step 4.10. Append element to configuration["elements"]
configuration_elements.push(element);
// Step 4.11. Return true.
true
}
// Step 5. Otherwise:
else {
// Step 5.1. If element["attributes"] exists or element["removeAttributes"] with default
// « » is not empty:
if element.attributes().is_some() ||
!element.remove_attributes().unwrap_or_default().is_empty()
{
// Step 5.1.1. The user agent may report a warning to the console that this
// operation is not supported.
Console::internal_warn(
&self.global(),
"Do not support adding an element with attributes to a sanitizer \
whose configuration[\"elements\"] does not exist."
.into(),
);
// Step 5.1.2. Return false.
return false;
}
// Step 5.2. Set modified to the result of remove element from
// configuration["replaceWithChildrenElements"].
let modified = if let Some(replace_with_children_elements) =
&mut configuration.replaceWithChildrenElements
{
replace_with_children_elements.remove_item(&element)
} else {
false
};
// Step 5.3. If configuration["removeElements"] does not contain element:
if !configuration
.removeElements
.as_ref()
.is_some_and(|configuration_remove_elements| {
configuration_remove_elements.contains_item(&element)
})
{
// Step 5.3.1. Comment: This is the case with a global remove-list that does not
// contain element.
// Step 5.3.2. Return modified.
return modified;
}
// Step 5.4. Comment: This is the case with a global remove-list that contains element.
// Step 5.5. Remove element from configuration["removeElements"].
if let Some(configuration_remove_elements) = &mut configuration.removeElements {
configuration_remove_elements.remove_item(&element);
}
// Step 5.6. Return true.
true
}
}
/// <https://wicg.github.io/sanitizer-api/#dom-sanitizer-removeelement>
fn RemoveElement(&self, element: SanitizerElement) -> bool {
// Remove an element with element and thiss configuration.
self.configuration.borrow_mut().remove_element(element)
}
/// <https://wicg.github.io/sanitizer-api/#dom-sanitizer-replaceelementwithchildren>
fn ReplaceElementWithChildren(&self, element: SanitizerElement) -> bool {
// Step 1. Let configuration be thiss configuration.
let mut configuration = self.configuration.borrow_mut();
// Step 2. Assert: configuration is valid.
assert!(configuration.is_valid());
// Step 3. Set element to the result of canonicalize a sanitizer element with element.
let element = element.canonicalize();
// Step 4. If the built-in non-replaceable elements list contains element:
if built_in_non_replaceable_elements_list().contains_item(&element) {
// Step 4.1. Return false.
return false;
}
// Step 5. If configuration["replaceWithChildrenElements"] contains element:
if configuration
.replaceWithChildrenElements
.as_ref()
.is_some_and(|configuration_replace_with_children_elements| {
configuration_replace_with_children_elements.contains_item(&element)
})
{
// Step 5.1. Return false.
return false;
}
// Step 6. Remove element from configuration["removeElements"].
if let Some(configuration_remove_elements) = &mut configuration.removeElements {
configuration_remove_elements.remove_item(&element);
}
// Step 7. Remove element from configuration["elements"] list.
if let Some(configuration_elements) = &mut configuration.elements {
configuration_elements.remove_item(&element);
}
// Step 8. Add element to configuration["replaceWithChildrenElements"].
if let Some(configuration_replace_with_children_elements) =
&mut configuration.replaceWithChildrenElements
{
configuration_replace_with_children_elements.add_item(element);
} else {
configuration.replaceWithChildrenElements = Some(vec![element]);
}
// Step 9. Return true.
true
}
}
trait SanitizerConfigAlgorithm {
/// <https://wicg.github.io/sanitizer-api/#sanitizerconfig-valid>
fn is_valid(&self) -> bool;
/// <https://wicg.github.io/sanitizer-api/#sanitizer-remove-an-element>
fn remove_element(&mut self, element: SanitizerElement) -> bool;
/// <https://wicg.github.io/sanitizer-api/#sanitizer-canonicalize-the-configuration>
fn canonicalize(&mut self, allow_comments_pis_and_data_attributes: bool);
}
@@ -310,7 +590,7 @@ impl SanitizerConfigAlgorithm for SanitizerConfig {
for element in config_replace_with_children_elements {
// Step 15.1.1. If the built-in non-replaceable elements list contains element, then
// return false.
if built_in_non_replaceable_elements_list().contains_name(element) {
if built_in_non_replaceable_elements_list().contains_item(element) {
return false;
}
}
@@ -388,7 +668,7 @@ impl SanitizerConfigAlgorithm for SanitizerConfig {
.remove_attributes()
.unwrap_or_default()
.iter()
.all(|entry| config_attributes.contains_name(entry))
.all(|entry| config_attributes.contains_item(entry))
{
return false;
}
@@ -502,6 +782,72 @@ impl SanitizerConfigAlgorithm for SanitizerConfig {
true
}
/// <https://wicg.github.io/sanitizer-api/#sanitizer-remove-an-element>
fn remove_element(&mut self, element: SanitizerElement) -> bool {
// Step 1. Assert: configuration is valid.
assert!(self.is_valid());
// Step 2. Set element to the result of canonicalize a sanitizer element with element.
let element = element.canonicalize();
// Step 3. Set modified to the result of remove element from
// configuration["replaceWithChildrenElements"].
let modified = if let Some(configuration_replace_with_children_elements) =
&mut self.replaceWithChildrenElements
{
configuration_replace_with_children_elements.remove_item(&element)
} else {
false
};
// Step 4. If configuration["elements"] exists:
if let Some(configuration_elements) = &mut self.elements {
// Step 4.1. If configuration["elements"] contains element:
if configuration_elements.contains_item(&element) {
// Step 4.1.1. Comment: We have a global allow list and it contains element.
// Step 4.1.2. Remove element from configuration["elements"].
configuration_elements.remove_item(&element);
// Step 4.1.3. Return true.
return true;
}
// Step 4.2. Comment: We have a global allow list and it does not contain element.
// Step 4.3. Return modified.
modified
}
// Step 5. Otherwise:
else {
// Step 5.1. If configuration["removeElements"] contains element:
if self
.removeElements
.as_mut()
.is_some_and(|configuration_remove_elements| {
configuration_remove_elements.contains_item(&element)
})
{
// Step 5.1.1. Comment: We have a global remove list and it already contains element.
// Step 5.1.2. Return modified.
return modified;
}
// Step 5.2. Comment: We have a global remove list and it does not contain element.
// Step 5.3. Add element to configuration["removeElements"].
if let Some(configuration_remove_elements) = &mut self.removeElements {
configuration_remove_elements.add_item(element);
} else {
self.removeElements = Some(vec![element]);
}
// Step 5.4. Return true.
true
}
}
/// <https://wicg.github.io/sanitizer-api/#sanitizer-canonicalize-the-configuration>
fn canonicalize(&mut self, allow_comments_pis_and_data_attributes: bool) {
// Step 1. If neither configuration["elements"] nor configuration["removeElements"] exist,
@@ -803,7 +1149,7 @@ where
T: NameMember + Canonicalization + Clone,
{
/// <https://wicg.github.io/sanitizer-api/#sanitizerconfig-contains>
fn contains_name<S: NameMember>(&self, other: &S) -> bool;
fn contains_item<S: NameMember>(&self, other: &S) -> bool;
/// <https://wicg.github.io/sanitizer-api/#sanitizerconfig-has-duplicates>
fn has_duplicates(&self) -> bool;
@@ -821,7 +1167,7 @@ where
T: NameMember + Canonicalization + Clone,
{
/// <https://wicg.github.io/sanitizer-api/#sanitizerconfig-contains>
fn contains_name<S: NameMember>(&self, other: &S) -> bool {
fn contains_item<S: NameMember>(&self, other: &S) -> bool {
// A Sanitizer name list contains an item if there exists an entry of list that is an
// ordered map, and where item["name"] equals entry["name"] and item["namespace"] equals
// entry["namespace"].
@@ -872,6 +1218,107 @@ where
}
}
/// Supporting algorithms on lists of elements and lists of attributes, from the specification.
trait NameVec<T>
where
T: NameMember + Canonicalization + Clone,
{
/// <https://wicg.github.io/sanitizer-api/#sanitizerconfig-remove>
fn remove_item<S: NameMember>(&mut self, item: &S) -> bool;
/// <https://wicg.github.io/sanitizer-api/#sanitizerconfig-add>
fn add_item(&mut self, name: T);
/// <https://wicg.github.io/sanitizer-api/#sanitizerconfig-remove-duplicates>
fn remove_duplicates(&mut self) -> &mut Self;
/// Set itself to the set intersection of itself and another list.
///
/// <https://infra.spec.whatwg.org/#set-intersection>
fn intersection<S>(&mut self, others: &[S])
where
S: NameMember + Canonicalization + Clone;
/// <https://infra.spec.whatwg.org/#set-difference>
fn difference(&mut self, others: &[T]);
}
impl<T> NameVec<T> for Vec<T>
where
T: NameMember + Canonicalization + Clone,
{
/// <https://wicg.github.io/sanitizer-api/#sanitizerconfig-remove>
fn remove_item<S: NameMember>(&mut self, item: &S) -> bool {
// Step 1. Set removed to false.
let mut removed = false;
// Step 2. For each entry of list:
// Step 2.1. If item["name"] equals entry["name"] and item["namespace"] equals entry["namespace"]:
// Step 2.1.1. Remove item entry from list.
// Step 2.1.2. Set removed to true.
self.retain(|entry| {
let matched = item.name() == entry.name() && item.namespace() == entry.namespace();
if matched {
removed = true;
}
!matched
});
// Step 3. Return removed.
removed
}
/// <https://wicg.github.io/sanitizer-api/#sanitizerconfig-add>
fn add_item(&mut self, name: T) {
// Step 1. If list contains name, then return.
if self.contains_item(&name) {
return;
};
// Step 2. Append name to list.
self.push(name);
}
/// <https://wicg.github.io/sanitizer-api/#sanitizerconfig-remove-duplicates>
fn remove_duplicates(&mut self) -> &mut Self {
// Step 1. Let result be « ».
// Step 2. For each entry of list, add entry to result.
// Step 3. Return result.
self.sort_by(|item_a, item_b| item_a.compare(item_b));
self.dedup_by_key(|item| (item.name().clone(), item.namespace().cloned()));
self
}
/// Set itself to the set intersection of itself and another list.
///
/// <https://infra.spec.whatwg.org/#set-intersection>
fn intersection<S>(&mut self, others: &[S])
where
S: NameMember + Canonicalization + Clone,
{
// The intersection of ordered sets A and B, is the result of creating a new ordered set set
// and, for each item of A, if B contains item, appending item to set.
self.retain(|item| {
others
.iter()
.any(|other| other.name() == item.name() && other.namespace() == item.namespace())
})
}
/// Set itself to the set difference of itself and another list.
///
/// <https://infra.spec.whatwg.org/#set-difference>
fn difference(&mut self, others: &[T]) {
// The difference of ordered sets A and B, is the result of creating a new ordered set set
// and, for each item of A, if B does not contain item, appending item to set.
self.retain(|item| {
!others
.iter()
.any(|other| other.name() == item.name() && other.namespace() == item.namespace())
})
}
}
/// Helper functions for accessing the "name" and "namespace" members of
/// [`SanitizerElementWithAttributes`], [`SanitizerElement`] and [`SanitizerAttribute`].
trait NameMember: Sized {

View File

@@ -1171,21 +1171,21 @@ Dictionaries = {
},
'SanitizerAttributeNamespace': {
'derives': ['Clone', 'MallocSizeOf']
},
'SanitizerElementNamespace': {
'derives': ['Clone', 'MallocSizeOf'],
},
'SanitizerElementNamespaceWithAttributes': {
'derives': ['Clone', 'MallocSizeOf'],
'derives': ['Clone', 'MallocSizeOf', 'PartialEq']
},
'SanitizerConfig': {
'derives': ['Clone', 'MallocSizeOf']
},
'SanitizerElementNamespace': {
'derives': ['Clone', 'MallocSizeOf', 'PartialEq'],
},
'SanitizerElementNamespaceWithAttributes': {
'derives': ['Clone', 'MallocSizeOf', 'PartialEq'],
},
'ScrollOptions': {
'derives': ['Clone'],
},
@@ -1230,15 +1230,15 @@ Unions = {
},
'StringOrSanitizerAttributeNamespace': {
'derives': ['Clone', 'MallocSizeOf'],
'derives': ['Clone', 'MallocSizeOf', 'PartialEq'],
},
'StringOrSanitizerElementNamespace': {
'derives': ['Clone', 'MallocSizeOf'],
'derives': ['Clone', 'MallocSizeOf', 'PartialEq'],
},
'StringOrSanitizerElementNamespaceWithAttributes': {
'derives': ['Clone', 'MallocSizeOf'],
'derives': ['Clone', 'MallocSizeOf', 'PartialEq'],
},
'RangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict': {

View File

@@ -20,9 +20,9 @@ interface Sanitizer {
SanitizerConfig get();
// Modify a Sanitizer's lists and fields:
// boolean allowElement(SanitizerElementWithAttributes element);
// boolean removeElement(SanitizerElement element);
// boolean replaceElementWithChildren(SanitizerElement element);
boolean allowElement(SanitizerElementWithAttributes element);
boolean removeElement(SanitizerElement element);
boolean replaceElementWithChildren(SanitizerElement element);
// boolean allowAttribute(SanitizerAttribute attribute);
// boolean removeAttribute(SanitizerAttribute attribute);
// boolean setComments(boolean allow);

View File

@@ -1,13 +1,4 @@
[idlharness.https.window.html]
[Sanitizer interface: operation allowElement(SanitizerElementWithAttributes)]
expected: FAIL
[Sanitizer interface: operation removeElement(SanitizerElement)]
expected: FAIL
[Sanitizer interface: operation replaceElementWithChildren(SanitizerElement)]
expected: FAIL
[Sanitizer interface: operation allowAttribute(SanitizerAttribute)]
expected: FAIL
@@ -23,24 +14,6 @@
[Sanitizer interface: operation removeUnsafe()]
expected: FAIL
[Sanitizer interface: new Sanitizer({}) must inherit property "allowElement(SanitizerElementWithAttributes)" with the proper type]
expected: FAIL
[Sanitizer interface: calling allowElement(SanitizerElementWithAttributes) on new Sanitizer({}) with too few arguments must throw TypeError]
expected: FAIL
[Sanitizer interface: new Sanitizer({}) must inherit property "removeElement(SanitizerElement)" with the proper type]
expected: FAIL
[Sanitizer interface: calling removeElement(SanitizerElement) on new Sanitizer({}) with too few arguments must throw TypeError]
expected: FAIL
[Sanitizer interface: new Sanitizer({}) must inherit property "replaceElementWithChildren(SanitizerElement)" with the proper type]
expected: FAIL
[Sanitizer interface: calling replaceElementWithChildren(SanitizerElement) on new Sanitizer({}) with too few arguments must throw TypeError]
expected: FAIL
[Sanitizer interface: new Sanitizer({}) must inherit property "allowAttribute(SanitizerAttribute)" with the proper type]
expected: FAIL

View File

@@ -1,5 +1,4 @@
[sanitizer-basic-filtering.tentative.html]
expected: ERROR
[setHTML testcase text/0, "text"]
expected: FAIL
@@ -29,3 +28,378 @@
[ShadowRoot.setHTMLUnsafe testcase elements/1, "<div><p>Hello <b>World!</b>"]
expected: FAIL
[parseHTML testcase elements/1, "<div><p>Hello <b>World!</b>"]
expected: FAIL
[parseHTMLUnsafe testcase elements/1, "<div><p>Hello <b>World!</b>"]
expected: FAIL
[setHTML testcase elements/2, "<div><p>Hello <b>World!</b>"]
expected: FAIL
[setHTMLUnsafe testcase elements/2, "<div><p>Hello <b>World!</b>"]
expected: FAIL
[ShadowRoot.setHTML testcase elements/2, "<div><p>Hello <b>World!</b>"]
expected: FAIL
[ShadowRoot.setHTMLUnsafe testcase elements/2, "<div><p>Hello <b>World!</b>"]
expected: FAIL
[parseHTML testcase elements/2, "<div><p>Hello <b>World!</b>"]
expected: FAIL
[parseHTMLUnsafe testcase elements/2, "<div><p>Hello <b>World!</b>"]
expected: FAIL
[setHTML testcase elements/3, "<div><p>Hello <b>World!</b>"]
expected: FAIL
[setHTMLUnsafe testcase elements/3, "<div><p>Hello <b>World!</b>"]
expected: FAIL
[ShadowRoot.setHTML testcase elements/3, "<div><p>Hello <b>World!</b>"]
expected: FAIL
[ShadowRoot.setHTMLUnsafe testcase elements/3, "<div><p>Hello <b>World!</b>"]
expected: FAIL
[parseHTML testcase elements/3, "<div><p>Hello <b>World!</b>"]
expected: FAIL
[parseHTMLUnsafe testcase elements/3, "<div><p>Hello <b>World!</b>"]
expected: FAIL
[setHTML testcase elements/4, "<div><p>Hello <b>World!</b>"]
expected: FAIL
[setHTMLUnsafe testcase elements/4, "<div><p>Hello <b>World!</b>"]
expected: FAIL
[ShadowRoot.setHTML testcase elements/4, "<div><p>Hello <b>World!</b>"]
expected: FAIL
[ShadowRoot.setHTMLUnsafe testcase elements/4, "<div><p>Hello <b>World!</b>"]
expected: FAIL
[parseHTML testcase elements/4, "<div><p>Hello <b>World!</b>"]
expected: FAIL
[parseHTMLUnsafe testcase elements/4, "<div><p>Hello <b>World!</b>"]
expected: FAIL
[setHTML testcase attributes/0, "<p id="hello" style="font-weight: bold">x"]
expected: FAIL
[ShadowRoot.setHTML testcase attributes/0, "<p id="hello" style="font-weight: bold">x"]
expected: FAIL
[parseHTML testcase attributes/0, "<p id="hello" style="font-weight: bold">x"]
expected: FAIL
[setHTML testcase attributes/1, "<p id="hello" style="font-weight: bold">x"]
expected: FAIL
[setHTMLUnsafe testcase attributes/1, "<p id="hello" style="font-weight: bold">x"]
expected: FAIL
[ShadowRoot.setHTML testcase attributes/1, "<p id="hello" style="font-weight: bold">x"]
expected: FAIL
[ShadowRoot.setHTMLUnsafe testcase attributes/1, "<p id="hello" style="font-weight: bold">x"]
expected: FAIL
[parseHTML testcase attributes/1, "<p id="hello" style="font-weight: bold">x"]
expected: FAIL
[parseHTMLUnsafe testcase attributes/1, "<p id="hello" style="font-weight: bold">x"]
expected: FAIL
[setHTML testcase attributes/2, "<p id="hello" style="font-weight: bold">x"]
expected: FAIL
[setHTMLUnsafe testcase attributes/2, "<p id="hello" style="font-weight: bold">x"]
expected: FAIL
[ShadowRoot.setHTML testcase attributes/2, "<p id="hello" style="font-weight: bold">x"]
expected: FAIL
[ShadowRoot.setHTMLUnsafe testcase attributes/2, "<p id="hello" style="font-weight: bold">x"]
expected: FAIL
[parseHTML testcase attributes/2, "<p id="hello" style="font-weight: bold">x"]
expected: FAIL
[parseHTMLUnsafe testcase attributes/2, "<p id="hello" style="font-weight: bold">x"]
expected: FAIL
[setHTML testcase attributes-per-element/0, "<div style="font-weight: bold" class="bourgeoisie">"]
expected: FAIL
[setHTMLUnsafe testcase attributes-per-element/0, "<div style="font-weight: bold" class="bourgeoisie">"]
expected: FAIL
[ShadowRoot.setHTML testcase attributes-per-element/0, "<div style="font-weight: bold" class="bourgeoisie">"]
expected: FAIL
[ShadowRoot.setHTMLUnsafe testcase attributes-per-element/0, "<div style="font-weight: bold" class="bourgeoisie">"]
expected: FAIL
[parseHTML testcase attributes-per-element/0, "<div style="font-weight: bold" class="bourgeoisie">"]
expected: FAIL
[parseHTMLUnsafe testcase attributes-per-element/0, "<div style="font-weight: bold" class="bourgeoisie">"]
expected: FAIL
[setHTML testcase attributes-per-element/1, "<div style="font-weight: bold" class="bourgeoisie">"]
expected: FAIL
[setHTMLUnsafe testcase attributes-per-element/1, "<div style="font-weight: bold" class="bourgeoisie">"]
expected: FAIL
[ShadowRoot.setHTML testcase attributes-per-element/1, "<div style="font-weight: bold" class="bourgeoisie">"]
expected: FAIL
[ShadowRoot.setHTMLUnsafe testcase attributes-per-element/1, "<div style="font-weight: bold" class="bourgeoisie">"]
expected: FAIL
[parseHTML testcase attributes-per-element/1, "<div style="font-weight: bold" class="bourgeoisie">"]
expected: FAIL
[parseHTMLUnsafe testcase attributes-per-element/1, "<div style="font-weight: bold" class="bourgeoisie">"]
expected: FAIL
[setHTML testcase comments/0, "a <!-- comment --> b"]
expected: FAIL
[ShadowRoot.setHTML testcase comments/0, "a <!-- comment --> b"]
expected: FAIL
[parseHTML testcase comments/0, "a <!-- comment --> b"]
expected: FAIL
[setHTML testcase comments/1, "a <!-- comment --> b"]
expected: FAIL
[setHTMLUnsafe testcase comments/1, "a <!-- comment --> b"]
expected: FAIL
[ShadowRoot.setHTML testcase comments/1, "a <!-- comment --> b"]
expected: FAIL
[ShadowRoot.setHTMLUnsafe testcase comments/1, "a <!-- comment --> b"]
expected: FAIL
[parseHTML testcase comments/1, "a <!-- comment --> b"]
expected: FAIL
[parseHTMLUnsafe testcase comments/1, "a <!-- comment --> b"]
expected: FAIL
[setHTML testcase dataAttributes/0, "<p data-x="1" data-y="2" data-z="3">"]
expected: FAIL
[ShadowRoot.setHTML testcase dataAttributes/0, "<p data-x="1" data-y="2" data-z="3">"]
expected: FAIL
[parseHTML testcase dataAttributes/0, "<p data-x="1" data-y="2" data-z="3">"]
expected: FAIL
[setHTML testcase dataAttributes/1, "<p data-x="1" data-y="2" data-z="3">"]
expected: FAIL
[setHTMLUnsafe testcase dataAttributes/1, "<p data-x="1" data-y="2" data-z="3">"]
expected: FAIL
[ShadowRoot.setHTML testcase dataAttributes/1, "<p data-x="1" data-y="2" data-z="3">"]
expected: FAIL
[ShadowRoot.setHTMLUnsafe testcase dataAttributes/1, "<p data-x="1" data-y="2" data-z="3">"]
expected: FAIL
[parseHTML testcase dataAttributes/1, "<p data-x="1" data-y="2" data-z="3">"]
expected: FAIL
[parseHTMLUnsafe testcase dataAttributes/1, "<p data-x="1" data-y="2" data-z="3">"]
expected: FAIL
[setHTML testcase dataAttributes/2, "<p data-x="1" data-y="2" data-z="3">"]
expected: FAIL
[setHTMLUnsafe testcase dataAttributes/2, "<p data-x="1" data-y="2" data-z="3">"]
expected: FAIL
[ShadowRoot.setHTML testcase dataAttributes/2, "<p data-x="1" data-y="2" data-z="3">"]
expected: FAIL
[ShadowRoot.setHTMLUnsafe testcase dataAttributes/2, "<p data-x="1" data-y="2" data-z="3">"]
expected: FAIL
[parseHTML testcase dataAttributes/2, "<p data-x="1" data-y="2" data-z="3">"]
expected: FAIL
[parseHTMLUnsafe testcase dataAttributes/2, "<p data-x="1" data-y="2" data-z="3">"]
expected: FAIL
[setHTML testcase namespaces/0, "<svg><rect></svg><math><mi>x"]
expected: FAIL
[ShadowRoot.setHTML testcase namespaces/0, "<svg><rect></svg><math><mi>x"]
expected: FAIL
[parseHTML testcase namespaces/0, "<svg><rect></svg><math><mi>x"]
expected: FAIL
[setHTML testcase namespaces/1, "<svg><rect>"]
expected: FAIL
[setHTMLUnsafe testcase namespaces/1, "<svg><rect>"]
expected: FAIL
[ShadowRoot.setHTML testcase namespaces/1, "<svg><rect>"]
expected: FAIL
[ShadowRoot.setHTMLUnsafe testcase namespaces/1, "<svg><rect>"]
expected: FAIL
[parseHTML testcase namespaces/1, "<svg><rect>"]
expected: FAIL
[parseHTMLUnsafe testcase namespaces/1, "<svg><rect>"]
expected: FAIL
[setHTML testcase namespaces/2, "<svg><rect>"]
expected: FAIL
[ShadowRoot.setHTML testcase namespaces/2, "<svg><rect>"]
expected: FAIL
[parseHTML testcase namespaces/2, "<svg><rect>"]
expected: FAIL
[setHTML testcase namespaces/3, "<svg><rect>"]
expected: FAIL
[setHTMLUnsafe testcase namespaces/3, "<svg><rect>"]
expected: FAIL
[ShadowRoot.setHTML testcase namespaces/3, "<svg><rect>"]
expected: FAIL
[ShadowRoot.setHTMLUnsafe testcase namespaces/3, "<svg><rect>"]
expected: FAIL
[parseHTML testcase namespaces/3, "<svg><rect>"]
expected: FAIL
[parseHTMLUnsafe testcase namespaces/3, "<svg><rect>"]
expected: FAIL
[setHTML testcase namespaces/4, "<math><mi>x"]
expected: FAIL
[setHTMLUnsafe testcase namespaces/4, "<math><mi>x"]
expected: FAIL
[ShadowRoot.setHTML testcase namespaces/4, "<math><mi>x"]
expected: FAIL
[ShadowRoot.setHTMLUnsafe testcase namespaces/4, "<math><mi>x"]
expected: FAIL
[parseHTML testcase namespaces/4, "<math><mi>x"]
expected: FAIL
[parseHTMLUnsafe testcase namespaces/4, "<math><mi>x"]
expected: FAIL
[setHTML testcase namespaces/5, "<math><mi>x"]
expected: FAIL
[ShadowRoot.setHTML testcase namespaces/5, "<math><mi>x"]
expected: FAIL
[parseHTML testcase namespaces/5, "<math><mi>x"]
expected: FAIL
[setHTML testcase namespaces/6, "<math><mi>x"]
expected: FAIL
[setHTMLUnsafe testcase namespaces/6, "<math><mi>x"]
expected: FAIL
[ShadowRoot.setHTML testcase namespaces/6, "<math><mi>x"]
expected: FAIL
[ShadowRoot.setHTMLUnsafe testcase namespaces/6, "<math><mi>x"]
expected: FAIL
[parseHTML testcase namespaces/6, "<math><mi>x"]
expected: FAIL
[parseHTMLUnsafe testcase namespaces/6, "<math><mi>x"]
expected: FAIL
[setHTML testcase namespaces/7, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
expected: FAIL
[ShadowRoot.setHTML testcase namespaces/7, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
expected: FAIL
[parseHTML testcase namespaces/7, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
expected: FAIL
[setHTML testcase namespaces/8, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
expected: FAIL
[setHTMLUnsafe testcase namespaces/8, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
expected: FAIL
[ShadowRoot.setHTML testcase namespaces/8, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
expected: FAIL
[ShadowRoot.setHTMLUnsafe testcase namespaces/8, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
expected: FAIL
[parseHTML testcase namespaces/8, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
expected: FAIL
[parseHTMLUnsafe testcase namespaces/8, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
expected: FAIL
[setHTML testcase namespaces/9, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
expected: FAIL
[setHTMLUnsafe testcase namespaces/9, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
expected: FAIL
[ShadowRoot.setHTML testcase namespaces/9, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
expected: FAIL
[ShadowRoot.setHTMLUnsafe testcase namespaces/9, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
expected: FAIL
[parseHTML testcase namespaces/9, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
expected: FAIL
[parseHTMLUnsafe testcase namespaces/9, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
expected: FAIL
[setHTML testcase defaults-with-attributes-per-element/0, "<div start=1 value=5 lang=en><ol start=1 value=5 lang=en><li start=1 value=5 lang=en>xx"]
expected: FAIL
[setHTMLUnsafe testcase defaults-with-attributes-per-element/0, "<div start=1 value=5 lang=en><ol start=1 value=5 lang=en><li start=1 value=5 lang=en>xx"]
expected: FAIL
[ShadowRoot.setHTML testcase defaults-with-attributes-per-element/0, "<div start=1 value=5 lang=en><ol start=1 value=5 lang=en><li start=1 value=5 lang=en>xx"]
expected: FAIL
[ShadowRoot.setHTMLUnsafe testcase defaults-with-attributes-per-element/0, "<div start=1 value=5 lang=en><ol start=1 value=5 lang=en><li start=1 value=5 lang=en>xx"]
expected: FAIL
[parseHTML testcase defaults-with-attributes-per-element/0, "<div start=1 value=5 lang=en><ol start=1 value=5 lang=en><li start=1 value=5 lang=en>xx"]
expected: FAIL
[parseHTMLUnsafe testcase defaults-with-attributes-per-element/0, "<div start=1 value=5 lang=en><ol start=1 value=5 lang=en><li start=1 value=5 lang=en>xx"]
expected: FAIL

View File

@@ -5,23 +5,8 @@
[SanitizerConfig dataAttributes field.]
expected: FAIL
[Test elements addition.]
expected: FAIL
[Test elements removal.]
expected: FAIL
[Test elements replacewithchildren.]
expected: FAIL
[Test attribute addition.]
expected: FAIL
[Test attribute removal.]
expected: FAIL
[Test attribute-per-element sets (i.e. overwrites).]
expected: FAIL
[Test removeAttribute-per-element sets (i.e. overwrites).]
expected: FAIL

View File

@@ -28,30 +28,3 @@
[sanitizer.removeAttribute() with global removeAttributes and element's removeAttributes]
expected: FAIL
[sanitizer.removeElement() with global elements]
expected: FAIL
[sanitizer.removeElement() with global removeElements]
expected: FAIL
[sanitizer.replaceElementWithChildren() with global elements]
expected: FAIL
[sanitizer.replaceElementWithChildren() with global removeElements]
expected: FAIL
[sanitizer.allowElement() with global elements]
expected: FAIL
[sanitizer.allowElement() with global removeElements]
expected: FAIL
[sanitizer.allowElement() with global elements and attributes]
expected: FAIL
[sanitizer.allowElement() with global elements and removeAttributes]
expected: FAIL
[sanitizer.replaceElementWithChildren does not allow 'html' element.]
expected: FAIL