[
https://issues.apache.org/jira/browse/CAMEL-24406?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
mayur mohan updated CAMEL-24406:
--------------------------------
Description:
h2. Problem
When a ByteArrayInputStreamCache (or byte[]) carrying a non-XML response body
(empty body, JSON error page, plain-text HTTP response, BOM-only) is passed to
XmlConverter.toDOMDocument, the JDK XML parser throws:
{noformat}
org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not
allowed in prolog.
{noformat}
Surfaced as:
{noformat}
Cannot read from xml stream. Reason: Error during type conversion from type:
org.apache.camel.converter.stream.ByteArrayInputStreamCache to the required
type: org.w3c.dom.Document ... due to org.xml.sax.SAXParseException: Content is
not allowed in prolog.
{noformat}
h2. Why Fix required
* Currently Invalid / non-XML content does *not* just produce a clean
exception – it forces memory intensive DOM construction first.
* in distributed communication systems, messages are Retried multiple times,
this increases the cost of compute and memory in cloud runtime. because the
same erroneous stream objects are rebuilt multiple time. where simple precheck
for consistency and validity is introduced before expensive operations
triggered.
* Under load or with large bad payloads this becomes a significant heap-memory
and GC problem, even though the final outcome is always a parse failure.
* In our just one production landscape 5 million such errors seen with
different tenants.
h2. Stack Trace
{noformat}
org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not
allowed in prolog.
at
java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:204)
at
java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:178)
at
java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:400)
at
java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:978)
at
java.xml/javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:122)
at
org.apache.camel.converter.jaxp.XmlConverter.toDOMDocument(XmlConverter.java:661)
at
org.apache.camel.converter.jaxp.CamelXmlJaxpBulkConverterLoader.doConvertTo(CamelXmlJaxpBulkConverterLoader.java:317)
at
org.apache.camel.converter.jaxp.CamelXmlJaxpBulkConverterLoader.convertTo(CamelXmlJaxpBulkConverterLoader.java:51)
at
org.apache.camel.spi.BulkTypeConverters.convertTo(BulkTypeConverters.java:122)
at
org.apache.camel.component.cxf.converter.CxfPayloadConverter.convertTo(CxfPayloadConverter.java:165)
at
org.apache.camel.component.cxf.converter.CxfPayloadConverterLoader.lambda(CxfPayloadConverterLoader.java:68)
at
org.apache.camel.support.SimpleTypeConverter.convertTo(SimpleTypeConverter.java:101)
at
org.apache.camel.impl.converter.CoreTypeConverterRegistry.doConvertTo(CoreTypeConverterRegistry.java:516)
at
org.apache.camel.impl.converter.CoreTypeConverterRegistry.convertTo(CoreTypeConverterRegistry.java:203)
at
org.apache.camel.core.osgi.OsgiTypeConverter.convertTo(OsgiTypeConverter.java:138)
at org.apache.camel.support.MessageSupport.getBody(MessageSupport.java:96)
at
org.apache.camel.component.cxf.DefaultCxfBinding.getBodyFromCamel(DefaultCxfBinding.java:1019)
at
org.apache.camel.component.cxf.DefaultCxfBinding.populateCxfResponseFromExchange(DefaultCxfBinding.java:461)
at
org.apache.camel.component.cxf.CxfConsumer.CxfConsumerInvoker.setResponseBack(CxfConsumer.java:324)
at
org.apache.camel.component.cxf.CxfConsumer.CxfConsumerInvoker.syncInvoke(CxfConsumer.java:248)
{noformat}
h2. Root Cause
XmlConverter.toDOMDocument(byte[], Exchange) and toDOMDocument(StreamCache,
Exchange) pass the content directly to DocumentBuilder.parse() without first
checking whether it could plausibly be XML. Any content whose first
non-whitespace byte is not < causes an immediate SAXParseException deep inside
the JDK parser.
h2. Fix
Add a cheap static looksLikeXml(byte[]) helper that inspects only the first few
bytes (handles UTF-8 BOM, UTF-16 BE/LE BOM, leading whitespace). Guard the two
toDOMDocument overloads that take byte[] and StreamCache to return null when
content is definitely not XML. Use @Converter(allowNull = true) so the Camel
type-converter framework falls through gracefully.
h2. Files Changed
core/camel-xml-jaxp/src/main/java/org/apache/camel/converter/jaxp/XmlConverter.java
core/camel-xml-jaxp/src/test/java/org/apache/camel/converter/jaxp/XmlConverterPrologTest.java
(new, 13 tests)
h2. Test Results
{noformat}
Tests run: 13, Failures: 0, Errors: 0, Skipped: 0 [JDK 21 / Maven 3.9]
BUILD SUCCESS
{noformat}
was:
h2. Problem
When a ByteArrayInputStreamCache (or byte[]) carrying a non-XML response body
(empty body, JSON error page, plain-text HTTP response, BOM-only) is passed to
XmlConverter.toDOMDocument, the JDK XML parser throws:
{noformat}
org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not
allowed in prolog.
{noformat}
Surfaced as:
{noformat}
Cannot read from xml stream. Reason: Error during type conversion from type:
org.apache.camel.converter.stream.ByteArrayInputStreamCache to the required
type: org.w3c.dom.Document ... due to org.xml.sax.SAXParseException: Content is
not allowed in prolog.
{noformat}
h2. Why Fix required
* Currently Invalid / non-XML content does *not* just produce a clean
exception – it forces memory intensive DOM construction first.
* in distributed communication systems, messages are Retried multiple times,
this increases the cost of compute and memory in cloud runtime. because the
same erroneous stream objects are rebuilt multiple time. where simple precheck
for consistency and validity is introduced before expensive operations
triggered.
* Under load or with large bad payloads this becomes a significant heap-memory
and GC problem, even though the final outcome is always a parse failure.
h2. Stack Trace
{noformat}
org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not
allowed in prolog.
at
java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:204)
at
java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:178)
at
java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:400)
at
java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:978)
at
java.xml/javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:122)
at
org.apache.camel.converter.jaxp.XmlConverter.toDOMDocument(XmlConverter.java:661)
at
org.apache.camel.converter.jaxp.CamelXmlJaxpBulkConverterLoader.doConvertTo(CamelXmlJaxpBulkConverterLoader.java:317)
at
org.apache.camel.converter.jaxp.CamelXmlJaxpBulkConverterLoader.convertTo(CamelXmlJaxpBulkConverterLoader.java:51)
at
org.apache.camel.spi.BulkTypeConverters.convertTo(BulkTypeConverters.java:122)
at
org.apache.camel.component.cxf.converter.CxfPayloadConverter.convertTo(CxfPayloadConverter.java:165)
at
org.apache.camel.component.cxf.converter.CxfPayloadConverterLoader.lambda(CxfPayloadConverterLoader.java:68)
at
org.apache.camel.support.SimpleTypeConverter.convertTo(SimpleTypeConverter.java:101)
at
org.apache.camel.impl.converter.CoreTypeConverterRegistry.doConvertTo(CoreTypeConverterRegistry.java:516)
at
org.apache.camel.impl.converter.CoreTypeConverterRegistry.convertTo(CoreTypeConverterRegistry.java:203)
at
org.apache.camel.core.osgi.OsgiTypeConverter.convertTo(OsgiTypeConverter.java:138)
at org.apache.camel.support.MessageSupport.getBody(MessageSupport.java:96)
at
org.apache.camel.component.cxf.DefaultCxfBinding.getBodyFromCamel(DefaultCxfBinding.java:1019)
at
org.apache.camel.component.cxf.DefaultCxfBinding.populateCxfResponseFromExchange(DefaultCxfBinding.java:461)
at
org.apache.camel.component.cxf.CxfConsumer.CxfConsumerInvoker.setResponseBack(CxfConsumer.java:324)
at
org.apache.camel.component.cxf.CxfConsumer.CxfConsumerInvoker.syncInvoke(CxfConsumer.java:248)
{noformat}
h2. Root Cause
XmlConverter.toDOMDocument(byte[], Exchange) and toDOMDocument(StreamCache,
Exchange) pass the content directly to DocumentBuilder.parse() without first
checking whether it could plausibly be XML. Any content whose first
non-whitespace byte is not < causes an immediate SAXParseException deep inside
the JDK parser.
h2. Fix
Add a cheap static looksLikeXml(byte[]) helper that inspects only the first few
bytes (handles UTF-8 BOM, UTF-16 BE/LE BOM, leading whitespace). Guard the two
toDOMDocument overloads that take byte[] and StreamCache to return null when
content is definitely not XML. Use @Converter(allowNull = true) so the Camel
type-converter framework falls through gracefully.
h2. Files Changed
core/camel-xml-jaxp/src/main/java/org/apache/camel/converter/jaxp/XmlConverter.java
core/camel-xml-jaxp/src/test/java/org/apache/camel/converter/jaxp/XmlConverterPrologTest.java
(new, 13 tests)
h2. Test Results
{noformat}
Tests run: 13, Failures: 0, Errors: 0, Skipped: 0 [JDK 21 / Maven 3.9]
BUILD SUCCESS
{noformat}
> camel-xml-jaxp: XmlConverter.toDOMDocument throws SAXParseException for
> non-XML content (Content is not allowed in prolog)
> --------------------------------------------------------------------------------------------------------------------------
>
> Key: CAMEL-24406
> URL: https://issues.apache.org/jira/browse/CAMEL-24406
> Project: Camel
> Issue Type: Improvement
> Components: camel-core-xml
> Reporter: mayur mohan
> Priority: Major
>
> h2. Problem
> When a ByteArrayInputStreamCache (or byte[]) carrying a non-XML response body
> (empty body, JSON error page, plain-text HTTP response, BOM-only) is passed
> to XmlConverter.toDOMDocument, the JDK XML parser throws:
> {noformat}
> org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not
> allowed in prolog.
> {noformat}
> Surfaced as:
> {noformat}
> Cannot read from xml stream. Reason: Error during type conversion from type:
> org.apache.camel.converter.stream.ByteArrayInputStreamCache to the required
> type: org.w3c.dom.Document ... due to org.xml.sax.SAXParseException: Content
> is not allowed in prolog.
> {noformat}
> h2. Why Fix required
> * Currently Invalid / non-XML content does *not* just produce a clean
> exception – it forces memory intensive DOM construction first.
> * in distributed communication systems, messages are Retried multiple times,
> this increases the cost of compute and memory in cloud runtime. because the
> same erroneous stream objects are rebuilt multiple time. where simple
> precheck for consistency and validity is introduced before expensive
> operations triggered.
> * Under load or with large bad payloads this becomes a significant
> heap-memory and GC problem, even though the final outcome is always a parse
> failure.
> * In our just one production landscape 5 million such errors seen with
> different tenants.
> h2. Stack Trace
> {noformat}
> org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not
> allowed in prolog.
> at
> java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:204)
> at
> java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:178)
> at
> java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:400)
> at
> java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:978)
> at
> java.xml/javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:122)
> at
> org.apache.camel.converter.jaxp.XmlConverter.toDOMDocument(XmlConverter.java:661)
> at
> org.apache.camel.converter.jaxp.CamelXmlJaxpBulkConverterLoader.doConvertTo(CamelXmlJaxpBulkConverterLoader.java:317)
> at
> org.apache.camel.converter.jaxp.CamelXmlJaxpBulkConverterLoader.convertTo(CamelXmlJaxpBulkConverterLoader.java:51)
> at
> org.apache.camel.spi.BulkTypeConverters.convertTo(BulkTypeConverters.java:122)
> at
> org.apache.camel.component.cxf.converter.CxfPayloadConverter.convertTo(CxfPayloadConverter.java:165)
> at
> org.apache.camel.component.cxf.converter.CxfPayloadConverterLoader.lambda(CxfPayloadConverterLoader.java:68)
> at
> org.apache.camel.support.SimpleTypeConverter.convertTo(SimpleTypeConverter.java:101)
> at
> org.apache.camel.impl.converter.CoreTypeConverterRegistry.doConvertTo(CoreTypeConverterRegistry.java:516)
> at
> org.apache.camel.impl.converter.CoreTypeConverterRegistry.convertTo(CoreTypeConverterRegistry.java:203)
> at
> org.apache.camel.core.osgi.OsgiTypeConverter.convertTo(OsgiTypeConverter.java:138)
> at org.apache.camel.support.MessageSupport.getBody(MessageSupport.java:96)
> at
> org.apache.camel.component.cxf.DefaultCxfBinding.getBodyFromCamel(DefaultCxfBinding.java:1019)
> at
> org.apache.camel.component.cxf.DefaultCxfBinding.populateCxfResponseFromExchange(DefaultCxfBinding.java:461)
> at
> org.apache.camel.component.cxf.CxfConsumer.CxfConsumerInvoker.setResponseBack(CxfConsumer.java:324)
> at
> org.apache.camel.component.cxf.CxfConsumer.CxfConsumerInvoker.syncInvoke(CxfConsumer.java:248)
> {noformat}
> h2. Root Cause
> XmlConverter.toDOMDocument(byte[], Exchange) and toDOMDocument(StreamCache,
> Exchange) pass the content directly to DocumentBuilder.parse() without first
> checking whether it could plausibly be XML. Any content whose first
> non-whitespace byte is not < causes an immediate SAXParseException deep
> inside the JDK parser.
> h2. Fix
> Add a cheap static looksLikeXml(byte[]) helper that inspects only the first
> few bytes (handles UTF-8 BOM, UTF-16 BE/LE BOM, leading whitespace). Guard
> the two toDOMDocument overloads that take byte[] and StreamCache to return
> null when content is definitely not XML. Use @Converter(allowNull = true) so
> the Camel type-converter framework falls through gracefully.
> h2. Files Changed
> core/camel-xml-jaxp/src/main/java/org/apache/camel/converter/jaxp/XmlConverter.java
> core/camel-xml-jaxp/src/test/java/org/apache/camel/converter/jaxp/XmlConverterPrologTest.java
> (new, 13 tests)
> h2. Test Results
> {noformat}
> Tests run: 13, Failures: 0, Errors: 0, Skipped: 0 [JDK 21 / Maven 3.9]
> BUILD SUCCESS
> {noformat}
--
This message was sent by Atlassian Jira
(v8.20.10#820010)