shashank created CAMEL-25867:
--------------------------------

             Summary: camel-mail - mimeMultipart unmarshal with 
headersInline=true cuts the start of a stream-cached body: a body that is not 
multipart loses its first lines, useOriginalMessage gets the body without its 
MIME headers
                 Key: CAMEL-25867
                 URL: https://issues.apache.org/jira/browse/CAMEL-25867
             Project: Camel
          Issue Type: Bug
          Components: camel-mail
            Reporter: shashank
            Assignee: shashank


With {{headersInline=true}}, 
{{MimeMultipartDataFormat.unmarshalWithInlineHeaders}} (main 20cdb309f7d0, line 
277) gives the body stream to {{new MimeBodyPart(stream)}}. Jakarta Mail uses a 
{{ByteArrayInputStream}} as it is (it wraps other streams in a 
{{BufferedInputStream}}), and its header parser 
({{org.eclipse.angus.mail.util.LineInputStream.readLine}}, Angus Mail 2.0.5) 
calls {{mark(2)}} on that stream after every CR of the MIME headers, to look at 
the next byte.

The in-memory stream cache that stream caching (on by default) makes of an 
{{InputStream}} body, for example the request body of camel-jetty or 
camel-servlet below the spool threshold, is an {{InputStreamCache}}, which 
extends {{ByteArrayInputStream}}; its {{reset()}} goes back to the last mark. 
So after the unmarshal a reset of the body went back to the last CR of the MIME 
headers instead of the start of the body:

* A body that is not multipart is left alone by the data format (the page says 
it leaves other messages alone, and that a stream body that is not MIME is 
replaced by an empty message only when stream caching is off). With CR LF line 
ends it came back without its first lines, silently: {{"first line\r\nsecond 
line\r\n\r\nthird line\r\n"}} became {{"\nthird line\r\n"}}.
* For a multipart body the result of the unmarshal is right, but the original 
body is not: a dead letter channel with {{useOriginalMessage()}} after a 
failure later in the route, or the stream cache kept in a property or variable 
before the unmarshal, got the body without its MIME headers (it starts at the 
CR LF before the first boundary).

This is the same mechanism as CAMEL-25574 (camel-zip-deflater: the gzip reader 
marked the stream-cached body); there the reader got a {{BufferedInputStream}} 
of its own.

*Fix*: {{new MimeBodyPart(new BufferedInputStream(stream))}}, so the parser 
marks its own buffer. The path with {{headersInline=false}} copies the body to 
a byte array first and is not affected.

*Tests*: new {{MimeMultipartInlineHeadersStreamCacheTest}} (3 tests, route with 
stream caching, the body an {{InputStream}} that is not a 
{{ByteArrayInputStream}}, as an HTTP request body is). All three fail on main: 
{{bodyThatIsNotMultipartIsKeptWhole}} {{expected: <first line ... third line> 
but was: <\nthird line>}}; {{originalMessageOfAFailedExchangeHasTheWholeBody}} 
(dead letter channel with {{useOriginalMessage}}) and 
{{streamCacheKeptInAPropertyCanBeReadAgain}} {{expected: <Content-Type: 
multipart/mixed; ...> but was: <\n--XYZ ...>}}. With the fix they pass; 
camel-mail unit tests: 248 run, 0 failures, 4 skipped.

*How it was found*: variant analysis of CAMEL-25574 (camel-zip-deflater): which 
other readers get the stream-cached body itself and mark it in the middle. 
Camel's own code does not, but a library can; the MIME header parser of Angus 
Mail does.

*Affected*: main, camel-4.23.x, camel-4.22.x, camel-4.18.x and camel-4.14.x 
have the same {{new MimeBodyPart(stream)}} and Angus Mail 2.0.5 (read, not run).

_Filed with Claude Code on behalf of allthingssecurity._




--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to