[
https://issues.apache.org/jira/browse/CAMEL-25905?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Work on CAMEL-25905 started by shashank.
----------------------------------------
> camel-file - with checksumFileAlgorithm and charset, the producer decodes the
> body with the JVM default charset (non-ASCII replaced) and writes a checksum
> that does not match the written file
> -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
> Key: CAMEL-25905
> URL: https://issues.apache.org/jira/browse/CAMEL-25905
> Project: Camel
> Issue Type: Bug
> Components: camel-file
> Reporter: shashank
> Assignee: shashank
> Priority: Major
>
> {{FileOperations.storeFile}} (main 74ee085f7d64, lines 349-375) implements
> {{checksumFileAlgorithm}} (CAMEL-22846, "calculate a checksum from the file
> that has been written") by wrapping the body in a {{DigestInputStream}}:
> {code:java}
> if (endpoint.getChecksumFileAlgorithm() != null) {
> MessageDigest digest =
> MessageDigest.getInstance(endpoint.getChecksumFileAlgorithm());
> InputStream is = exchange.getMessage().getBody(FileInputStream.class);
> if (is == null) {
> is = mandatoryBodyStream(exchange, exchange.getMessage(), file);
> }
> dis = new DigestInputStream(is, digest);
> }
> if (charset != null) {
> handleReaderAsFileSource(exchange, file, charset, dis);
> } ...
> {code}
> and {{handleReaderAsFileSource}} (lines 439-456) skips the {{Reader}}
> conversion when it gets that stream and reads it with {{new
> InputStreamReader(is)}}, the default charset of the JVM. So adding
> {{checksumFileAlgorithm}} to a producer with {{charset}} changes what is
> written, and the checksum is that of the body, not of the file:
> * the bytes of a file consumed with {{charset=ISO-8859-1}} (or any body whose
> bytes are in the exchange charset) are decoded as UTF-8: every non-ASCII
> character is written as U+FFFD. Without the checksum option the same route
> writes the file right
> ({{from("file:in?charset=ISO-8859-1").to("file:out?charset=UTF-8&checksumFileAlgorithm=sha256")}}
> turns {{Grüße aus Köln}} into {{Gr??e aus K?ln}});
> * the checksum (the {{CamelFileChecksum}} header and the {{.sha256}} file) is
> calculated over the bytes before re-encoding, so it does not match the
> written file as soon as the encoding changes a byte: a receiver that verifies
> the checksum file rejects every such file;
> * a String body whose exchange carries the endpoint charset (for example sent
> with a {{ProducerTemplate}} to
> {{file:out?charset=ISO-8859-1&checksumFileAlgorithm=sha256}}) is converted to
> ISO-8859-1 bytes, decoded as UTF-8 and fails with
> {{UnmappableCharacterException}};
> * with {{fileExist=Append}} and {{appendChars}}, the appended characters are
> written after the digest stream was read, so the checksum leaves them out.
> *Fix*: the digest is updated with the bytes written to the file: a
> {{DigestOutputStream}} under the writer of the charset path, and the buffer
> and the {{appendChars}} bytes of the stream path. The body is decoded as
> without the checksum option (the {{Reader}} conversion with the exchange
> charset). The writer of the charset path still reports unmappable characters,
> as {{Files.newBufferedWriter}} did. Upgrade note in the 4.24 guide (checksums
> of such files differ from the ones written before).
> *Tests*: new {{FileProducerChecksumOfWrittenFileTest}} in camel-core (4
> tests). On main: {{transcodedFileHasItsOwnChecksumAndContent}} fails with
> {{array lengths differ, expected: <17> but was: <20>}} (three U+FFFD of three
> bytes each), {{stringWrittenWithCharsetHasTheChecksumOfTheFile}} fails with
> {{CamelExecutionException}} caused by {{UnmappableCharacterException}},
> {{appendCharsArePartOfTheChecksum}} fails with {{expected: <d2a84f4b...> but
> was: <a591a6d4...>}} (the checksum of {{Hello World}} without the newline).
> {{bodyWithoutCharsetKeepsItsChecksum}} is a control and passes on main. The 9
> tests of {{FileProducerChecksumFileAlgorithmTest}} pass with the fix. The
> tests of the {{org.apache.camel.component.file}} package of camel-core: 478
> run, 0 failures, 12 skipped; camel-file: 28 run, 0 failures (one flake of
> {{FileProducerNoForcedWritesTest}}, passed on rerun; it does not use the
> checksum option).
> *How it was found*: comparing the code paths of the file producer for one
> option (here: the checksum path replaces the input of the charset path). The
> JUnit tests above are the evidence.
> *Affected*: main, camel-4.23.x, camel-4.22.x and camel-4.18.x ({{new
> DigestInputStream}} and {{new InputStreamReader(is)}} at the same lines;
> read, not run). 4.14.x has an older implementation
> ({{GenericFileProducer.writeChecksumFile}} re-reads the body after the
> write): no decoding problem there, but the same checksum of the body instead
> of the file.
> Not changed: with {{fileExist=Append}} to an existing file, the checksum
> covers the bytes this exchange wrote, not the whole file. The remote file
> producers (ftp, sftp, scp, smb, azure-files) expose {{checksumFileAlgorithm}}
> too (inherited from {{GenericFileEndpoint}}) but since the checksum moved
> into {{FileOperations}} (CAMEL-22846, 4.18) they never calculate one, so no
> header and no checksum file are written (4.14.x wrote one for them); possible
> follow-up.
> _Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v8.20.10#820010)