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.
This commit is contained in:
Andrew Gaul 2014-07-02 15:02:26 -07:00
parent b41c4c2ab0
commit c85d728a5a
2 changed files with 27 additions and 4 deletions

View File

@ -98,17 +98,25 @@ public class BasePayloadSlicer implements PayloadSlicer {
private Payload getNextPayload() { private Payload getNextPayload() {
byte[] content = new byte[readLen]; byte[] content = new byte[readLen];
int read = 0; int offset = 0;
try { try {
if ((read = input.read(content)) == -1) { while (true) {
int read = input.read(content, offset, readLen - offset);
if (read <= 0) {
if (offset == 0) {
return null; return null;
} else {
break;
}
}
offset += read;
} }
} catch (IOException e) { } catch (IOException e) {
throw Throwables.propagate(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) { private Payload createPayload(byte[] content) {

View File

@ -24,13 +24,17 @@ import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Iterator; import java.util.Iterator;
import org.jclouds.io.ByteSources;
import org.jclouds.io.Payload; import org.jclouds.io.Payload;
import org.jclouds.io.PayloadSlicer; import org.jclouds.io.PayloadSlicer;
import org.jclouds.io.payloads.ByteSourcePayload;
import org.jclouds.io.payloads.InputStreamPayload; import org.jclouds.io.payloads.InputStreamPayload;
import org.jclouds.util.Strings2; import org.jclouds.util.Strings2;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.collect.Iterables;
import com.google.common.io.ByteSource;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
@Test @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);
}
} }