Description
StreamUtils.copyRange copies the input stream with a buffer size of 4096 bytes. If the desired range is not divisible by 4096, copyRange will overread the input stream by reading whole buffers at a time. This will result in skipping the bytes in the input stream that were read into the buffer but not copied.
Consider the following kotlin code:
val a = ByteArrayInputStream(ByteArray(6000))
val b = ByteArrayOutputStream(6000)
val copied = StreamUtils.copyRange(a, b, 0, 5000) // copied == 5001
val rest = a.readAllBytes().size // rest == 0, should equal 999
val total = copied + rest // total == 5001, should equal 6000
Because the input stream spans over two buffers, copyRange will consume the whole stream even though the requested range was 1000 bytes smaller than the stream length.
Actual behavior
When the requested range is not divisible by 4096 and the input stream is longer than the range copyRange will consume extra bytes after the end of the range. This advances the stream unnecessarily and results in those bytes being skipped.
Expected behavior
StreamUtils.copyRange should only read the requested number of bytes from the input stream.
Suggested fix
The number of remaining bytes to be read should be taken into account instead of reading the whole buffer:
int bytesRead = in.read(buffer, 0, Math.min(buffer.size, numRemainingBytes));
Comment From: icguy
Wow, that was some response time! Thanks a lot for the fix!