[ 
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)

Reply via email to