mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-29 04:09:13 +00:00
LibWeb: Don't crash when appending to an XML document template element
When the XML parser appends child nodes to a template element, it must actually append the template element's contents. This special behavior caused us to return to the wrong parent element after adding child nodes to a template element, leading to a crash.
This commit is contained in:
parent
7cc718f1c1
commit
80ccb12a12
Notes:
github-actions[bot]
2025-07-14 07:16:52 +00:00
Author: https://github.com/tcl3
Commit: 80ccb12a12
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5429
Reviewed-by: https://github.com/gmta ✅
Reviewed-by: https://github.com/shannonbooth
4 changed files with 54 additions and 1 deletions
|
@ -53,6 +53,7 @@ ErrorOr<Variant<ByteString, Vector<XML::MarkupDeclaration>>> resolve_xml_resourc
|
|||
|
||||
XMLDocumentBuilder::XMLDocumentBuilder(DOM::Document& document, XMLScriptingSupport scripting_support)
|
||||
: m_document(document)
|
||||
, m_template_node_stack(document.realm().heap())
|
||||
, m_current_node(m_document)
|
||||
, m_scripting_support(scripting_support)
|
||||
{
|
||||
|
@ -148,6 +149,7 @@ void XMLDocumentBuilder::element_start(const XML::Name& name, HashMap<XML::Name,
|
|||
}
|
||||
if (m_current_node->is_html_template_element()) {
|
||||
// When an XML parser would append a node to a template element, it must instead append it to the template element's template contents (a DocumentFragment node).
|
||||
m_template_node_stack.append(*m_current_node);
|
||||
MUST(static_cast<HTML::HTMLTemplateElement&>(*m_current_node).content()->append_child(node));
|
||||
} else {
|
||||
MUST(m_current_node->append_child(node));
|
||||
|
@ -229,7 +231,12 @@ void XMLDocumentBuilder::element_end(const XML::Name& name)
|
|||
script_element.process_the_script_element();
|
||||
};
|
||||
|
||||
m_current_node = m_current_node->parent_node();
|
||||
auto* parent = m_current_node->parent_node();
|
||||
if (parent->is_document_fragment()) {
|
||||
auto template_parent_node = m_template_node_stack.take_last();
|
||||
parent = template_parent_node.ptr();
|
||||
}
|
||||
m_current_node = parent;
|
||||
}
|
||||
|
||||
void XMLDocumentBuilder::text(StringView data)
|
||||
|
@ -267,6 +274,7 @@ void XMLDocumentBuilder::document_end()
|
|||
// NOTE: Noop.
|
||||
|
||||
// Set the insertion point to undefined.
|
||||
m_template_node_stack.clear();
|
||||
m_current_node = nullptr;
|
||||
|
||||
// Update the current document readiness to "interactive".
|
||||
|
|
|
@ -41,6 +41,7 @@ private:
|
|||
Optional<FlyString> namespace_for_name(XML::Name const&);
|
||||
|
||||
GC::Ref<DOM::Document> m_document;
|
||||
GC::RootVector<GC::Ref<DOM::Node>> m_template_node_stack;
|
||||
GC::Ptr<DOM::Node> m_current_node;
|
||||
XMLScriptingSupport m_scripting_support { XMLScriptingSupport::Enabled };
|
||||
bool m_has_error { false };
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 3 tests
|
||||
|
||||
3 Pass
|
||||
Pass XMLHttpRequest: template element parsing
|
||||
Pass XMLHttpRequest: template element parsing 1
|
||||
Pass XMLHttpRequest: template element parsing 2
|
36
Tests/LibWeb/Text/input/wpt-import/xhr/template-element.html
Normal file
36
Tests/LibWeb/Text/input/wpt-import/xhr/template-element.html
Normal file
|
@ -0,0 +1,36 @@
|
|||
<!doctype html>
|
||||
<title>XMLHttpRequest: template element parsing</title>
|
||||
<script src=../resources/testharness.js></script>
|
||||
<script src=../resources/testharnessreport.js></script>
|
||||
<div id=log></div>
|
||||
<script>
|
||||
async_test(t => {
|
||||
const client = new XMLHttpRequest
|
||||
client.open("GET", "data:text/xml,<template xmlns='http://www.w3.org/1999/xhtml'><test/></template>")
|
||||
client.send()
|
||||
client.onload = t.step_func_done(() => {
|
||||
assert_equals(client.responseXML.documentElement.childElementCount, 0)
|
||||
assert_equals(client.responseXML.documentElement.content.firstChild.localName, "test")
|
||||
})
|
||||
})
|
||||
|
||||
async_test(t => {
|
||||
const client = new XMLHttpRequest
|
||||
client.open("GET", "data:text/xml,<template><test/></template>")
|
||||
client.send()
|
||||
client.onload = t.step_func_done(() => {
|
||||
assert_equals(client.responseXML.documentElement.childElementCount, 1)
|
||||
assert_equals(client.responseXML.documentElement.firstChild.localName, "test")
|
||||
})
|
||||
})
|
||||
|
||||
async_test(t => {
|
||||
const client = new XMLHttpRequest
|
||||
client.open("GET", "data:text/xml,<template xmlns='http://www.w3.org/2000/svg'><test/></template>")
|
||||
client.send()
|
||||
client.onload = t.step_func_done(() => {
|
||||
assert_equals(client.responseXML.documentElement.childElementCount, 1)
|
||||
assert_equals(client.responseXML.documentElement.firstChild.localName, "test")
|
||||
})
|
||||
})
|
||||
</script>
|
Loading…
Add table
Add a link
Reference in a new issue