fix(domparser): preserve XML content types

Extract an independently mergeable topic from wpt-misc-fix at
a70a96f9d1.

Append only the XML content-type regression to the baseline test module.
Use empty XML to exercise the existing parser-error-document path; the original undeclared-prefix input requires a separate namespace parser fix. Content-type and error-document assertions are retained.

Source commits:
- c8eed633ac

Validation:
- cargo fmt --all
- cargo clippy --workspace --all-targets --all-features -- -D warnings
- cargo nextest run --no-fail-fast
This commit is contained in:
ldm0
2026-09-10 05:45:51 +08:00
committed by Donough Liu
parent e194c2add8
commit 23a488be68
2 changed files with 65 additions and 3 deletions
+31 -3
View File
@@ -188,7 +188,13 @@ pub(super) fn parse_detached_document_from_string<'s>(
} else {
materialize_xml_parser_error_document(parsed)
};
build_detached_document(scope, parsed, DetachedDocumentKind::Xml, false)
build_detached_document_with_content_type(
scope,
parsed,
DetachedDocumentKind::Xml,
false,
Some(mime),
)
}
fn materialize_xml_parser_error_document(parsed: NativeDom) -> NativeDom {
@@ -398,11 +404,33 @@ fn build_detached_document<'s>(
kind: DetachedDocumentKind,
expose_declarative_shadow_roots: bool,
) -> Option<v8::Local<'s, v8::Object>> {
build_detached_document_from_dom_host(
build_detached_document_with_content_type(
scope,
DomHost::from_dom(parsed),
parsed,
kind,
expose_declarative_shadow_roots,
None,
)
}
fn build_detached_document_with_content_type<'s>(
scope: &mut v8::PinScope<'s, '_>,
parsed: NativeDom,
kind: DetachedDocumentKind,
expose_declarative_shadow_roots: bool,
content_type: Option<&str>,
) -> Option<v8::Local<'s, v8::Object>> {
let _ = expose_declarative_shadow_roots;
let kind = match kind {
DetachedDocumentKind::Html => "html",
DetachedDocumentKind::Xml => "xml",
};
build_detached_document_object_from_dom_host_with_content_type(
scope,
kind,
DomHost::from_dom(parsed),
content_type,
None,
)
}
@@ -8699,3 +8699,37 @@ fn detached_domparser_adopted_nodes_follow_live_tree_for_children_text_and_mutat
r#"{"beforeRemoval":{"firstChildIsHeld":true,"childParentIsForeignRoot":true,"childNodesLength":2,"lastChildType":3,"textContent":"xy","containsHeldChild":true},"afterRemoval":{"removedIsHeld":true,"removedParentIsNull":true,"childNodesLength":1,"firstChildType":3,"textContent":"y","liveBodyText":"y"}}"#
);
}
#[test]
fn domparser_xml_preserves_requested_content_type_for_success_and_error_documents() {
let mut vm = new_storage_test_vm("https://domparser-xml-content-type.test/");
let result = vm
.eval(
r#"
(() => {
const parser = new DOMParser();
return JSON.stringify([
"text/xml",
"application/xml",
"application/xhtml+xml",
"image/svg+xml"
].map(contentType => {
const valid = parser.parseFromString("<root/>", contentType);
const invalid = parser.parseFromString("", contentType);
return [
valid.contentType,
invalid.contentType,
invalid.documentElement.localName
];
}));
})()
"#,
)
.expect("DOMParser XML content type probe should evaluate");
assert_eq!(
result,
r#"[["text/xml","text/xml","html"],["application/xml","application/xml","html"],["application/xhtml+xml","application/xhtml+xml","html"],["image/svg+xml","image/svg+xml","html"]]"#
);
}