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]

Reply via email to