From c85d728a5a6e8bec3283703aa2fda22aef4dd925 Mon Sep 17 00:00:00 2001 From: Andrew Gaul Date: Wed, 2 Jul 2014 15:02:26 -0700 Subject: [PATCH] Handle short reads in BasePayloadSlicer InputStream.read(byte[]) can return fewer bytes than requested. Specifically ByteSource.concat(ByteSource...).openStream() will only return as many bytes as the current ByteSource contains. Thus ByteSources.repeatingArrayByteSource(byte[]).openStream() will return short reads despite the byte[] input from its single logical InputStream. --- .../jclouds/io/internal/BasePayloadSlicer.java | 16 ++++++++++++---- .../io/internal/BasePayloadSlicerTest.java | 15 +++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/jclouds/io/internal/BasePayloadSlicer.java b/core/src/main/java/org/jclouds/io/internal/BasePayloadSlicer.java index 8c181c04a4..13b2624fb7 100644 --- a/core/src/main/java/org/jclouds/io/internal/BasePayloadSlicer.java +++ b/core/src/main/java/org/jclouds/io/internal/BasePayloadSlicer.java @@ -98,17 +98,25 @@ public class BasePayloadSlicer implements PayloadSlicer { private Payload getNextPayload() { byte[] content = new byte[readLen]; - int read = 0; + int offset = 0; try { - if ((read = input.read(content)) == -1) { - return null; + while (true) { + int read = input.read(content, offset, readLen - offset); + if (read <= 0) { + if (offset == 0) { + return null; + } else { + break; + } + } + offset += read; } } catch (IOException e) { throw Throwables.propagate(e); } - return createPayload((content.length == read) ? content : Arrays.copyOf(content, read)); + return createPayload((content.length == offset) ? content : Arrays.copyOf(content, offset)); } private Payload createPayload(byte[] content) { diff --git a/core/src/test/java/org/jclouds/io/internal/BasePayloadSlicerTest.java b/core/src/test/java/org/jclouds/io/internal/BasePayloadSlicerTest.java index b2d27b0e68..17e4076ac7 100644 --- a/core/src/test/java/org/jclouds/io/internal/BasePayloadSlicerTest.java +++ b/core/src/test/java/org/jclouds/io/internal/BasePayloadSlicerTest.java @@ -24,13 +24,17 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.Iterator; +import org.jclouds.io.ByteSources; import org.jclouds.io.Payload; import org.jclouds.io.PayloadSlicer; +import org.jclouds.io.payloads.ByteSourcePayload; import org.jclouds.io.payloads.InputStreamPayload; import org.jclouds.util.Strings2; import org.testng.annotations.Test; import com.google.common.base.Charsets; +import com.google.common.collect.Iterables; +import com.google.common.io.ByteSource; import com.google.common.io.ByteStreams; @Test @@ -67,4 +71,15 @@ public class BasePayloadSlicerTest { } + @Test + public void testIterableSliceWithRepeatingByteSource() throws IOException { + String content = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\n"; /* 53 chars */ + byte[] contentBytes = content.getBytes(Charsets.UTF_8); + ByteSource byteSource = ByteSources.repeatingArrayByteSource(contentBytes).slice(0, 1024); + PayloadSlicer slicer = new BasePayloadSlicer(); + Payload payload = new ByteSourcePayload(byteSource); + + assertEquals(Iterables.size(slicer.slice(payload, 100)), 11); + assertEquals(Iterables.size(slicer.slice(payload, 53)), 20); + } }