Dhairya-007 opened a new pull request, #29702: URL: https://github.com/apache/camel/pull/29702
## Problem The file resume support positions the body at a recorded offset with a single unchecked call, in three places: ```java // GenericFileConverter.genericFileToInputStream InputStream inputStream = IOHelper.toInputStream(f, charset); inputStream.skip(file.getLastOffsetValue()); // GenericFileConverter.genericFileToReader reader.skip(file.getLastOffsetValue()); // IOHelper.toString(BufferedReader, long offset) reader.skip(offset); ``` `InputStream.skip(long)` and `Reader.skip(long)` are both specified to skip **up to** the requested amount and to return how far they actually got — the javadoc of the former says it "may, for a variety of reasons, end up skipping over some smaller number of bytes, possibly 0". The returned count is the only thing that says where the stream now is, and all three calls discard it, so the body can silently start somewhere other than the offset that was asked for. ### How reachable is it? Honestly: for a fresh local file the skip normally completes, because `BufferedInputStream.skip` delegates to the position-based skip of the channel stream, and `Reader.skip` loops internally. I could not make a plain local file skip short mid-stream. The case that **is** reachable is an offset past the end of the file, which is exactly what a stale recorded offset looks like after the file was truncated or replaced. Today the stream runs to EOF and the exchange carries an empty or short body as if that were the file's content; nothing says the offset could not be honoured. For a resume feature, silently delivering the wrong bytes is worse than failing. Beyond that, the code is relying on an implementation detail of the stream it happens to get. `IOHelper.toInputStream` returns a `BufferedInputStream` for the no-charset path and a `ReaderInputStream` for the charset path, and `GenericFileConverter` does not control which stream a caller ends up with. ## Fix - `GenericFileConverter.genericFileToInputStream` uses `InputStream.skipNBytes(long)` (JDK 12+), which loops and throws `EOFException` if the stream ends first. - `IOHelper` gains `skipFully(Reader, long)`, the same loop for readers, since `Reader` has no `skipNBytes`. It is used by `GenericFileConverter.genericFileToReader` and by `IOHelper.toString(BufferedReader, long)`. ### Behaviour change An offset past the end of the file now fails with `EOFException` instead of yielding an empty body. That is the point of the change, but it is a visible difference for anyone whose resume offsets can go stale. If you would rather have an upgrade-guide entry for it, say so and I will add one. ## Tests `IOHelperTest` gets two cases driving a `FilterReader` that skips one character per call — which `Reader.skip` is free to do, and which a single unchecked call has to cope with: - `testSkipFullyWithAReaderThatSkipsInSmallSteps` — four one-character skips add up to the requested four, and the rest of the content is intact. A bare `reader.skip(4)` on that reader advances one character, so the old code would return `123456789`. - `testSkipFullyPastTheEnd` — `EOFException` rather than a silent short read. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
