You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
v2: msc_xml.c prints libxml2 errors to stderr and discards the parse reason #3680
apache2/msc_xml.c on v2/master has neither of the two libxml2 error-handling changes that just went into v3 (#3677 and #3679):
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.
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.
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.
Activity
fzipi commentedon Oct 13, 2026
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 errorlines 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 theXML_PARSE_NOERRORflag 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_MSGcannot act on it yet. That is the same question as the multipart change in #3658.