This is an automated email from the ASF dual-hosted git repository.

peterlee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-compress.git


The following commit(s) were added to refs/heads/master by this push:
     new 2fe5825  [COMPRESS-584] [COMPRESS-585] Fix IOUtils.readRange() can 
read more from a channel than asked for
2fe5825 is described below

commit 2fe5825828f7a96b0676d11972f9a13892075b4d
Author: Matthijs Laan <matthij...@gmail.com>
AuthorDate: Wed Aug 4 12:04:29 2021 +0200

    [COMPRESS-584] [COMPRESS-585] Fix IOUtils.readRange() can read more from a 
channel than asked for
---
 .../org/apache/commons/compress/utils/IOUtils.java |  2 ++
 .../apache/commons/compress/utils/IOUtilsTest.java | 38 ++++++++++++++++++++++
 2 files changed, 40 insertions(+)

diff --git a/src/main/java/org/apache/commons/compress/utils/IOUtils.java 
b/src/main/java/org/apache/commons/compress/utils/IOUtils.java
index 3a1f582..d07f3d8 100644
--- a/src/main/java/org/apache/commons/compress/utils/IOUtils.java
+++ b/src/main/java/org/apache/commons/compress/utils/IOUtils.java
@@ -367,6 +367,8 @@ public final class IOUtils {
         final ByteBuffer b = ByteBuffer.allocate(Math.min(len, COPY_BUF_SIZE));
         int read = 0;
         while (read < len) {
+            // Make sure we never read more than len bytes
+            b.limit(Math.min(len - read, b.capacity()));
             final int readNow = input.read(b);
             if (readNow <= 0) {
                 break;
diff --git a/src/test/java/org/apache/commons/compress/utils/IOUtilsTest.java 
b/src/test/java/org/apache/commons/compress/utils/IOUtilsTest.java
index a692ef0..f5d00dc 100644
--- a/src/test/java/org/apache/commons/compress/utils/IOUtilsTest.java
+++ b/src/test/java/org/apache/commons/compress/utils/IOUtilsTest.java
@@ -23,6 +23,7 @@ import java.io.EOFException;
 import java.io.FilterInputStream;
 import java.io.InputStream;
 import java.io.IOException;
+import java.lang.reflect.Field;
 import java.nio.ByteBuffer;
 import java.nio.channels.ReadableByteChannel;
 
@@ -149,6 +150,43 @@ public class IOUtilsTest {
     }
 
     @Test
+    public void 
readRangeFromChannelDoesntReadMoreThanAskedForWhenItGotLessInFirstReadCall() 
throws IOException {
+        try (ReadableByteChannel in = new SeekableInMemoryByteChannel(new 
byte[] { 1, 2, 3, 4, 5, 6, 7 }) {
+            @Override
+            public int read(ByteBuffer buf) throws IOException {
+                // Trickle max 2 bytes at a time to trigger COMPRESS-584
+                final ByteBuffer temp = ByteBuffer.allocate(Math.min(2, 
buf.remaining()));
+                final int read = super.read(temp);
+                if (read > 0) {
+                    buf.put(temp.array(), 0, read);
+                }
+                return read;
+            }
+        }) {
+            final byte[] read = IOUtils.readRange(in, 5);
+            Assert.assertArrayEquals(new byte[] { 1, 2, 3, 4, 5 }, read);
+        }
+    }
+
+    @Test
+    public void readRangeMoreThanCopyBufferSize() throws Exception {
+        final Field COPY_BUF_SIZE = 
IOUtils.class.getDeclaredField("COPY_BUF_SIZE");
+        COPY_BUF_SIZE.setAccessible(true);
+        final int copyBufSize = (int)COPY_BUF_SIZE.get(null);
+
+        // Make an input that requires two read loops to trigger COMPRESS-585
+        final byte[] input = new byte[copyBufSize + 10];
+
+        try (SeekableInMemoryByteChannel in = new 
SeekableInMemoryByteChannel(input)) {
+            // Ask for less than the input length, but more than the buffer 
size
+            final int toRead = copyBufSize + 1;
+            final byte[] read = IOUtils.readRange(in, toRead);
+            Assert.assertEquals(toRead, read.length);
+            Assert.assertEquals(toRead, in.position());
+        }
+    }
+
+    @Test
     public void readRangeFromChannelStopsIfThereIsNothingToReadAnymore() 
throws IOException {
         try (ReadableByteChannel in = new SeekableInMemoryByteChannel(new 
byte[] { 1, 2, 3, 4, 5 })) {
             byte[] read = IOUtils.readRange(in, 10);

Reply via email to