Skip to content

v2: msc_xml.c prints libxml2 errors to stderr and discards the parse reason #3680

Open

Description

@fzipi

What

apache2/msc_xml.c on v2/master has neither of the two libxml2 error-handling changes that just went into v3 (#3677 and #3679):

  1. libxml2 parser errors go to stderr. Both push parser contexts (msc_xml.c L250 and L257) are created without XML_PARSE_NOERROR | XML_PARSE_NOWARNING, and nothing installs an error handler. libxml2 therefore prints body.xml:1: parser error : ... plus the context lines through its default handler, which under Apache ends up in the error log without the usual [date] [module:level] [pid] prefix. This is the v2 version of REQBODY_ERROR "Extra content at the end of the document" after 3.0.15 update #3563, and it has always been there rather than being a regression.
  2. The reason is discarded. On failure the engine reports the fixed strings XML: Failed to parse document. / XML: Failed to parse document for ARGS. (L276, L288, L327, L339), so REQBODY_ERROR_MSG never says whether it was a tag mismatch, extra content after the root element, an empty document, and so on.

The original design kept the reason: xml_receive_sax_error() at L204 formats lastError.message (line N offset M) into the debug log, but the block that wires it up (L236-L247) is commented out, so the function is dead code.

Proposal

Same two changes as v3, in one or two commits:

  • After each xmlCreatePushParserCtxt(), call xmlCtxtUseOptions(ctx, XML_PARSE_NOWARNING | XML_PARSE_NOERROR). This is the call that works on every libxml2 version; OR-ing ctx->options directly is a no-op before libxml2 2.13 (see fix: silence libxml2 parser errors on every libxml2 version #3677 for the measurements).
  • At the four failure sites, build *error_msg from xmlCtxtGetLastError(ctx) (message, line, int2), trimming the trailing newline, with the fixed string as the fallback when there is no message. In xml_complete() read it before xmlFreeParserCtxt(). Reuse or delete the dead xml_receive_sax_error() rather than keeping a third variant.

xmlCtxtGetLastError() keeps working under XML_PARSE_NOERROR, is available since libxml2 2.6, and is not deprecated in 2.15.

Test

tests/regression/ has no XML parser error case today. Add one under tests/regression/target/ that posts a body with a tag mismatch, sets ctl:requestBodyProcessor=XML, and matches REQBODY_ERROR_MSG with @contains Opening and ending tag mismatch. The Perl runner auto-discovers new .t files.

References

v3 counterparts: #3677 (silence stderr), #3679 (surface the message). Background: #3563, #3678.

Activity

  1. self-assigned this
    on Oct 13, 2026
  2. fzipi commented on Oct 13, 2026

    @fzipi
    CollaboratorAuthor

    PR #3681 implements both parts.

    One correction to point 1 above: under Apache 2.4 (worker MPM) with libxml2 2.9.14 I could not observe libxml2's body.xml:N: parser error lines in the error log even before the change, although httpd's stderr is the error log. The nginx report in #3563 did show them. So for the Apache module the XML_PARSE_NOERROR flag is parity with v3 rather than a measured fix; the surfaced message (point 2) is the part that changes observable behavior, and it is what the new regression test asserts.

    Also noted in the PR: a v2 XML parse failure still answers HTTP 500 before phase 2, so a rule on REQBODY_ERROR_MSG cannot act on it yet. That is the same question as the multipart change in #3658.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions