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)