0

[Sanitizer] Properly recurse into <template> contents.

Fix Sanitizer to properly recurse into template contents. Also update
tests (& test support files) to take template contents into account.

Bug: 356601280
Change-Id: Idb81d0f01afe7dcc1ce5d13d719b0515d1ef4752
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6234275
Reviewed-by: Yifan Luo <lyf@chromium.org>
Commit-Queue: Daniel Vogelheim <vogelheim@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1419925}
This commit is contained in:
Daniel Vogelheim
2025-02-13 08:52:01 -08:00
committed by Chromium LUCI CQ
parent 80095c3395
commit 0df99989cd
3 changed files with 75 additions and 3 deletions
third_party/blink
renderer
core
sanitizer
web_tests

@ -14,6 +14,7 @@
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/dom/node_traversal.h"
#include "third_party/blink/renderer/core/html/html_template_element.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/sanitizer/sanitizer_builtins.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
@ -307,6 +308,17 @@ void Sanitizer::SanitizeElement(Element* element) const {
element->removeAttribute(name);
}
}
// Recurse into template and (later) shadow root content.
// TODO(vogelheim): Also implement shadow root support, once that's settled
// down.
// TODO(vogelheim): Merge this code with the case in SanitizeUnsafe.
if (IsA<HTMLTemplateElement>(element)) {
Node* content = To<HTMLTemplateElement>(element)->content();
if (content) {
SanitizeUnsafe(content);
}
}
}
void Sanitizer::SanitizeSafe(Node* root) const {
@ -320,8 +332,17 @@ void Sanitizer::SanitizeSafe(Node* root) const {
}
void Sanitizer::SanitizeUnsafe(Node* root) const {
enum { kKeep, kKeepElement, kDrop, kReplaceWithChildren } action = kKeep;
// Recurse into template and (later) shadow root content.
// TODO(vogelheim): Also implement shadow root support, once that's settled
// down.
if (IsA<HTMLTemplateElement>(root)) {
Node* content = To<HTMLTemplateElement>(root)->content();
if (content) {
SanitizeUnsafe(content);
}
}
enum { kKeep, kKeepElement, kDrop, kReplaceWithChildren } action = kKeep;
Node* node = NodeTraversal::Next(*root);
while (node) {
switch (node->getNodeType()) {

@ -586,3 +586,46 @@ test<div>p</div>tt<p>div</p><test>test</test>
| <div>
| <b>
#data
<template><div>Hello</div></template>
#config
{}
#document
| <template>
| content
| <div>
| "Hello"
#data
<template><div>Hello</div></template>
#config
{ "elements": ["div"]}
#document
#data
<template><div>Hello</div></template>
#config
{ "elements": ["template"]}
#document
| <template>
| content
#data
<template><div>Hello</div></template>
#config
{ "elements": ["div", "template"]}
#document
| <template>
| content
| <div>
| "Hello"
#data
<template><div>Hello</div></template>
#config
{ "elements": ["template"], "replaceWithChildrenElements": ["div"]}
#document
| <template>
| content
| "Hello"

@ -206,11 +206,13 @@ function assert_subtree_equals(node1, node2) {
current1 = tree1.nextNode();
current2 = tree2.nextNode();
if (!current1) break;
// Conceptually, we only want to check whether a.isEqualNode(b). But that
// yields terrible error messages ("expected true but got false"). With
// this being a test suite and all, let's invest a bit of effort into nice
// error messages.
if (current1 && !current1.isEqualNode(current2)) {
if (!current1.isEqualNode(current2)) {
let breadcrumbs = "";
let current = current1;
while (current) {
@ -222,7 +224,13 @@ function assert_subtree_equals(node1, node2) {
assert_true(current1.isEqualNode(current2),
`${current1}.isEqual(${current2}) fails. Path: ${breadcrumbs}.`);
}
} while (current1);
// NodeIterator does not recurse into template contents. So we need to do
// this manually.
if (is_html_template(current1) && is_html_template(current2)) {
assert_subtree_equals(current1.content, current2.content);
}
} while (current1);
// Ensure that both iterators have come to an end.
assert_false(!!current2, "Additional nodes at the of node2.");