You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@camel.apache.org by "shashank (Jira)" <ji...@apache.org> on 2026/10/20 06:47:00 UTC
[jira] [Created] (CAMEL-25867) 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
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)