LibWeb+LibXML: Cache the result of parsing the XHTML DTD and reuse it

There's no reason to parse this again and again every time we parse an
XHTML document.
This commit is contained in:
Ali Mohammad Pur 2024-10-12 23:13:24 +02:00 committed by Ali Mohammad Pur
parent 6a5bca1302
commit 24c2ad059b
5 changed files with 38 additions and 19 deletions

File diff suppressed because one or more lines are too long

View file

@ -21,7 +21,7 @@ enum class XMLScriptingSupport {
Enabled,
};
ErrorOr<ByteString> resolve_xml_resource(XML::SystemID const&, Optional<XML::PublicID> const&);
ErrorOr<Variant<ByteString, Vector<XML::MarkupDeclaration>>> resolve_xml_resource(XML::SystemID const&, Optional<XML::PublicID> const&);
class XMLDocumentBuilder final : public XML::Listener {
public:

View file

@ -573,15 +573,21 @@ ErrorOr<void, ParseError> Parser::parse_doctype_decl()
if (m_options.resolve_external_resource) {
auto resource_result = m_options.resolve_external_resource(doctype.external_id->system_id, doctype.external_id->public_id);
if (!resource_result.is_error()) {
StringView resolved_source = resource_result.value();
TemporaryChange source { m_source, resolved_source };
TemporaryChange lexer { m_lexer, LineTrackingLexer(m_source) };
auto declarations = TRY(parse_external_subset());
if (!m_lexer.is_eof()) {
return parse_error(
m_lexer.current_position(),
ByteString::formatted("Failed to resolve external subset '{}': garbage after declarations", doctype.external_id->system_id.system_literal));
}
auto declarations = TRY(resource_result.release_value().visit(
[&](ByteString resolved_source) -> ErrorOr<Vector<MarkupDeclaration>, ParseError> {
TemporaryChange source { m_source, resolved_source.view() };
TemporaryChange lexer { m_lexer, LineTrackingLexer(m_source) };
auto declarations = TRY(parse_external_subset());
if (!m_lexer.is_eof()) {
return parse_error(
m_lexer.current_position(),
ByteString::formatted("Failed to resolve external subset '{}': garbage after declarations", doctype.external_id->system_id.system_literal));
}
return declarations;
},
[&](Vector<MarkupDeclaration> declarations) -> ErrorOr<Vector<MarkupDeclaration>, ParseError> {
return declarations;
}));
doctype.markup_declarations.extend(move(declarations));
}
}
@ -1755,7 +1761,10 @@ ErrorOr<ByteString, ParseError> Parser::resolve_reference(EntityReference const&
if (result.is_error())
return parse_error(m_lexer.position_for(0), ByteString::formatted("Failed to resolve external entity '{}': {}", reference.name, result.error()));
resolved = result.release_value();
if (!result.value().has<ByteString>())
return parse_error(m_lexer.position_for(0), ByteString::formatted("Failed to resolve external entity '{}': Resource is of the wrong type", reference.name));
resolved = result.release_value().get<ByteString>();
return {};
}));
break;

View file

@ -49,7 +49,7 @@ public:
bool preserve_cdata { true };
bool preserve_comments { false };
bool treat_errors_as_fatal { true };
Function<ErrorOr<ByteString>(SystemID const&, Optional<PublicID> const&)> resolve_external_resource {};
Function<ErrorOr<Variant<ByteString, Vector<MarkupDeclaration>>>(SystemID const&, Optional<PublicID> const&)> resolve_external_resource {};
};
Parser(StringView source, Options options)
@ -70,6 +70,8 @@ public:
Vector<ParseError> const& parse_error_causes() const { return m_parse_errors; }
ErrorOr<Vector<MarkupDeclaration>, ParseError> parse_external_subset();
private:
struct EntityReference {
Name name;
@ -138,7 +140,6 @@ private:
ErrorOr<StringView, ParseError> parse_system_id_literal();
ErrorOr<StringView, ParseError> parse_cdata_section();
ErrorOr<ByteString, ParseError> parse_attribute_value_inner(StringView disallow);
ErrorOr<Vector<MarkupDeclaration>, ParseError> parse_external_subset();
ErrorOr<void, ParseError> parse_text_declaration();
ErrorOr<void, ParseError> expect(StringView);

View file

@ -362,7 +362,7 @@ static auto parse(StringView contents)
contents,
{
.preserve_comments = true,
.resolve_external_resource = [&](XML::SystemID const& system_id, Optional<XML::PublicID> const&) -> ErrorOr<ByteString> {
.resolve_external_resource = [&](XML::SystemID const& system_id, Optional<XML::PublicID> const&) -> ErrorOr<Variant<ByteString, Vector<XML::MarkupDeclaration>>> {
auto base = URL::create_with_file_scheme(s_path);
auto url = URL::Parser::basic_parse(system_id.system_literal, base);
if (!url.is_valid())