mirror of https://github.com/apache/jclouds.git
JCLOUDS-912: JCLOUDS-1547: GCS InputStream single-part upload
Previously this provider worked around a RestAnnotationProcessor quirk by using multi-part uploads for InputStream payloads. Instead work around the quirk another way which allows a single-part upload. This allows inclusion of the Content-MD5 header during object creation. Backfill tests with both ByteSource and InputStream inputs.
This commit is contained in:
parent
08a16c95fb
commit
6e6f8ebf77
|
@ -267,7 +267,7 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
|
|||
}
|
||||
}
|
||||
|
||||
private void putBlobWithMd5(byte[] payload, HashCode contentMD5) throws InterruptedException, IOException {
|
||||
private void putBlobWithMd5(Payload payload, long contentLength, HashCode contentMD5) throws InterruptedException, IOException {
|
||||
String container = getContainerName();
|
||||
BlobStore blobStore = view.getBlobStore();
|
||||
try {
|
||||
|
@ -275,6 +275,7 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
|
|||
Blob blob = blobStore
|
||||
.blobBuilder(blobName)
|
||||
.payload(payload)
|
||||
.contentLength(contentLength)
|
||||
.contentMD5(contentMD5)
|
||||
.build();
|
||||
blobStore.putBlob(container, blob);
|
||||
|
@ -288,18 +289,39 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
|
|||
}
|
||||
|
||||
@Test(groups = { "integration", "live" })
|
||||
public void testPutCorrectContentMD5() throws InterruptedException, IOException {
|
||||
byte[] payload = createTestInput(1024).read();
|
||||
HashCode contentMD5 = md5().hashBytes(payload);
|
||||
putBlobWithMd5(payload, contentMD5);
|
||||
public void testPutCorrectContentMD5ByteSource() throws InterruptedException, IOException {
|
||||
ByteSource payload = createTestInput(1024);
|
||||
HashCode contentMD5 = md5().hashBytes(payload.read());
|
||||
putBlobWithMd5(new ByteSourcePayload(payload), payload.size(), contentMD5);
|
||||
}
|
||||
|
||||
@Test(groups = { "integration", "live" })
|
||||
public void testPutIncorrectContentMD5() throws InterruptedException, IOException {
|
||||
byte[] payload = createTestInput(1024).read();
|
||||
public void testPutIncorrectContentMD5ByteSource() throws InterruptedException, IOException {
|
||||
ByteSource payload = createTestInput(1024);
|
||||
HashCode contentMD5 = md5().hashBytes(new byte[0]);
|
||||
try {
|
||||
putBlobWithMd5(payload, contentMD5);
|
||||
putBlobWithMd5(new ByteSourcePayload(payload), payload.size(), contentMD5);
|
||||
fail();
|
||||
} catch (HttpResponseException hre) {
|
||||
if (hre.getResponse().getStatusCode() != getIncorrectContentMD5StatusCode()) {
|
||||
throw hre;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test(groups = { "integration", "live" })
|
||||
public void testPutCorrectContentMD5InputStream() throws InterruptedException, IOException {
|
||||
ByteSource payload = createTestInput(1024);
|
||||
HashCode contentMD5 = md5().hashBytes(payload.read());
|
||||
putBlobWithMd5(new InputStreamPayload(payload.openStream()), payload.size(), contentMD5);
|
||||
}
|
||||
|
||||
@Test(groups = { "integration", "live" })
|
||||
public void testPutIncorrectContentMD5InputStream() throws InterruptedException, IOException {
|
||||
ByteSource payload = createTestInput(1024);
|
||||
HashCode contentMD5 = md5().hashBytes(new byte[0]);
|
||||
try {
|
||||
putBlobWithMd5(new InputStreamPayload(payload.openStream()), payload.size(), contentMD5);
|
||||
fail();
|
||||
} catch (HttpResponseException hre) {
|
||||
if (hre.getResponse().getStatusCode() != getIncorrectContentMD5StatusCode()) {
|
||||
|
|
|
@ -97,6 +97,14 @@ public class PayloadEnclosingImpl implements PayloadEnclosing {
|
|||
setPayload(newPayload(checkNotNull(data, "data")));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetPayload(boolean release) {
|
||||
if (release && payload != null) {
|
||||
payload.release();
|
||||
}
|
||||
payload = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
|
|
|
@ -48,4 +48,5 @@ public interface PayloadEnclosing {
|
|||
@Nullable
|
||||
Payload getPayload();
|
||||
|
||||
void resetPayload(boolean release);
|
||||
}
|
||||
|
|
|
@ -80,9 +80,19 @@ public final class B2BlobIntegrationLiveTest extends BaseBlobIntegrationTest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void testPutIncorrectContentMD5() throws InterruptedException, IOException {
|
||||
public void testPutIncorrectContentMD5ByteSource() throws InterruptedException, IOException {
|
||||
try {
|
||||
super.testPutIncorrectContentMD5();
|
||||
super.testPutIncorrectContentMD5ByteSource();
|
||||
failBecauseExceptionWasNotThrown(AssertionError.class);
|
||||
} catch (AssertionError ae) {
|
||||
throw new SkipException("B2 does not enforce Content-MD5", ae);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testPutIncorrectContentMD5InputStream() throws InterruptedException, IOException {
|
||||
try {
|
||||
super.testPutIncorrectContentMD5InputStream();
|
||||
failBecauseExceptionWasNotThrown(AssertionError.class);
|
||||
} catch (AssertionError ae) {
|
||||
throw new SkipException("B2 does not enforce Content-MD5", ae);
|
||||
|
|
|
@ -57,6 +57,7 @@ public final class MultipartUploadBinder implements MapBinder {
|
|||
Part jsonPart = Part.create("Metadata", jsonPayload, new Part.PartOptions().contentType(APPLICATION_JSON));
|
||||
Part mediaPart = Part.create(template.name(), payload, new Part.PartOptions().contentType(contentType));
|
||||
|
||||
request.resetPayload(/*release=*/ false);
|
||||
request.setPayload(new MultipartForm(BOUNDARY_HEADER, jsonPart, mediaPart));
|
||||
// HeaderPart
|
||||
request.toBuilder().replaceHeader(CONTENT_TYPE, "Multipart/related; boundary= " + BOUNDARY_HEADER).build();
|
||||
|
|
|
@ -211,7 +211,7 @@ public final class GoogleCloudStorageBlobStore extends BaseBlobStore {
|
|||
public String putBlob(String container, Blob blob, PutOptions options) {
|
||||
long length = checkNotNull(blob.getPayload().getContentMetadata().getContentLength());
|
||||
|
||||
if (length != 0 && (options.isMultipart() || !blob.getPayload().isRepeatable())) {
|
||||
if (length != 0 && options.isMultipart()) {
|
||||
// JCLOUDS-912 prevents using single-part uploads with InputStream payloads.
|
||||
// Work around this with multi-part upload which buffers parts in-memory.
|
||||
return putMultipartBlob(container, blob, options);
|
||||
|
|
Loading…
Reference in New Issue