diff --git a/blobstore/src/main/java/org/jclouds/blobstore/config/LocalBlobStore.java b/blobstore/src/main/java/org/jclouds/blobstore/config/LocalBlobStore.java index 95364e832e..be96b73bc4 100644 --- a/blobstore/src/main/java/org/jclouds/blobstore/config/LocalBlobStore.java +++ b/blobstore/src/main/java/org/jclouds/blobstore/config/LocalBlobStore.java @@ -633,6 +633,9 @@ public final class LocalBlobStore implements BlobStore { int last = data.length - 1; if (s.startsWith("-")) { offset = last - Integer.parseInt(s.substring(1)) + 1; + if (offset < 0) { + offset = 0; + } } else if (s.endsWith("-")) { offset = Integer.parseInt(s.substring(0, s.length() - 1)); } else if (s.contains("-")) { @@ -643,7 +646,7 @@ public final class LocalBlobStore implements BlobStore { throw new IllegalArgumentException("illegal range: " + s); } - if (offset > last) { + if (offset >= data.length) { throw new IllegalArgumentException("illegal range: " + s); } if (last + 1 > data.length) { diff --git a/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobIntegrationTest.java b/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobIntegrationTest.java index deaee579af..730d93537b 100644 --- a/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobIntegrationTest.java +++ b/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobIntegrationTest.java @@ -61,6 +61,7 @@ import org.jclouds.blobstore.domain.PageSet; import org.jclouds.blobstore.domain.StorageMetadata; import org.jclouds.blobstore.domain.StorageType; import org.jclouds.blobstore.options.CopyOptions; +import org.jclouds.blobstore.options.GetOptions; import org.jclouds.blobstore.options.PutOptions; import org.jclouds.crypto.Crypto; import org.jclouds.encryption.internal.JCECrypto; @@ -364,6 +365,25 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest { } } + @Test(groups = { "integration", "live" }) + public void testGetRangeOutOfRange() throws InterruptedException, IOException { + String container = getContainerName(); + try { + String name = "apples"; + + addObjectAndValidateContent(container, name); + view.getBlobStore().getBlob(container, name, range(TEST_STRING.length(), TEST_STRING.length() + 1)); + throw new AssertionError("Invalid range not caught"); + } catch (HttpResponseException e) { + assertThat(e.getResponse().getStatusCode()).isEqualTo(416); + } catch (IllegalArgumentException e) { + assertThat(e.getMessage()).startsWith("illegal range: "); + } finally { + returnContainer(container); + } + + } + @Test(groups = { "integration", "live" }) public void testGetRange() throws InterruptedException, IOException { String container = getContainerName(); @@ -379,6 +399,13 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest { Blob blob2 = view.getBlobStore().getBlob(container, name, range(6, TEST_STRING.length())); validateMetadata(blob2.getMetadata(), container, name); assertEquals(getContentAsStringOrNullAndClose(blob2), TEST_STRING.substring(6, TEST_STRING.length())); + + /* RFC 2616 14.35.1 + "If the entity is shorter than the specified suffix-length, the + entire entity-body is used." */ + Blob blob3 = view.getBlobStore().getBlob(container, name, new GetOptions().tail(TEST_STRING.length() + 10)); + validateMetadata(blob3.getMetadata(), container, name); + assertEquals(getContentAsStringOrNullAndClose(blob3), TEST_STRING); } finally { returnContainer(container); }