From fc7ae19f4bce18b9c4663d26af19ad9b3d5cf4f0 Mon Sep 17 00:00:00 2001 From: abhinav Date: Mon, 1 Apr 2019 19:48:27 +0530 Subject: [PATCH 01/14] commit for manage resumeable signedURL uploads #2462 --- .../contrib/nio/testing/FakeStorageRpc.java | 5 + .../cloud/storage/BlobWriteChannel.java | 26 ++++ .../com/google/cloud/storage/Storage.java | 23 ++-- .../com/google/cloud/storage/StorageImpl.java | 6 + .../cloud/storage/spi/v1/HttpStorageRpc.java | 33 +++++ .../cloud/storage/spi/v1/StorageRpc.java | 7 ++ .../cloud/storage/BlobWriteChannelTest.java | 119 ++++++++++++++++++ .../google/cloud/storage/StorageImplTest.java | 14 +++ 8 files changed, 219 insertions(+), 14 deletions(-) diff --git a/google-cloud-clients/google-cloud-contrib/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/testing/FakeStorageRpc.java b/google-cloud-clients/google-cloud-contrib/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/testing/FakeStorageRpc.java index 515235cc5176..b1a451e6fcc6 100644 --- a/google-cloud-clients/google-cloud-contrib/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/testing/FakeStorageRpc.java +++ b/google-cloud-clients/google-cloud-contrib/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/testing/FakeStorageRpc.java @@ -312,6 +312,11 @@ public String open(StorageObject object, Map options) throws StorageE return fullname(object); } + @Override + public String getUploadId(String signURL) { + return null; + } + @Override public void write( String uploadId, byte[] toWrite, int toWriteOffset, long destOffset, int length, boolean last) diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java index eade1d245d83..306214b65d6b 100644 --- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java +++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java @@ -24,6 +24,7 @@ import com.google.cloud.RetryHelper; import com.google.cloud.WriteChannel; import com.google.cloud.storage.spi.v1.StorageRpc; +import java.net.URL; import java.util.Map; import java.util.concurrent.Callable; @@ -34,10 +35,18 @@ class BlobWriteChannel extends BaseWriteChannel { this(options, blob, open(options, blob, optionsMap)); } + BlobWriteChannel(StorageOptions options, URL signURL) { + this(options, getUploadId(signURL.toString(), options)); + } + BlobWriteChannel(StorageOptions options, BlobInfo blobInfo, String uploadId) { super(options, blobInfo, uploadId); } + BlobWriteChannel(StorageOptions options, String uploadId) { + super(options, null, uploadId); + } + @Override protected void flushBuffer(final int length, final boolean last) { try { @@ -83,6 +92,23 @@ public String call() { } } + private static String getUploadId(final String signURL, final StorageOptions options) { + try { + return runWithRetries( + new Callable() { + @Override + public String call() { + return options.getStorageRpcV1().getUploadId(signURL); + } + }, + options.getRetrySettings(), + StorageImpl.EXCEPTION_HANDLER, + options.getClock()); + } catch (RetryHelper.RetryHelperException e) { + throw StorageException.translateAndThrow(e); + } + } + static class StateImpl extends BaseWriteChannel.BaseState { private static final long serialVersionUID = -9028324143780151286L; diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java index 9d2d0d5c33f2..c82f37546d2a 100644 --- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java +++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java @@ -22,13 +22,8 @@ import com.google.api.gax.paging.Page; import com.google.auth.ServiceAccountSigner; import com.google.auth.ServiceAccountSigner.SigningException; -import com.google.cloud.FieldSelector; +import com.google.cloud.*; import com.google.cloud.FieldSelector.Helper; -import com.google.cloud.Policy; -import com.google.cloud.ReadChannel; -import com.google.cloud.Service; -import com.google.cloud.Tuple; -import com.google.cloud.WriteChannel; import com.google.cloud.storage.Acl.Entity; import com.google.cloud.storage.spi.v1.StorageRpc; import com.google.common.collect.ImmutableList; @@ -39,14 +34,7 @@ import java.io.Serializable; import java.net.URL; import java.security.Key; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; +import java.util.*; import java.util.concurrent.TimeUnit; /** @@ -2068,6 +2056,13 @@ Blob create( */ WriteChannel writer(BlobInfo blobInfo, BlobWriteOption... options); + /** + * accept signURL and return a channel for writing content. + * + * @throws StorageException upon failure + */ + WriteChannel writer(URL signURL); + /** * Generates a signed URL for a blob. If you have a blob that you want to allow access to for a * fixed amount of time, you can use this method to generate a URL that is only valid within a diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageImpl.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageImpl.java index ac4da4c32eea..707b3b80e61c 100644 --- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageImpl.java +++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageImpl.java @@ -598,6 +598,12 @@ public BlobWriteChannel writer(BlobInfo blobInfo, BlobWriteOption... options) { return writer(targetOptions.x(), targetOptions.y()); } + @Override + public BlobWriteChannel writer(URL signURL) { + final StorageOptions options = StorageOptions.newBuilder().build(); + return new BlobWriteChannel(options, signURL); + } + private BlobWriteChannel writer(BlobInfo blobInfo, BlobTargetOption... options) { final Map optionsMap = optionMap(blobInfo, options); return new BlobWriteChannel(getOptions(), blobInfo, optionsMap); diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java index b736600fcf69..f22ec53fd6e5 100644 --- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java +++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java @@ -822,6 +822,39 @@ public String open(StorageObject object, Map options) { } } + @Override + public String getUploadId(String signURL) { + Span span = startSpan(HttpStorageRpcSpans.SPAN_NAME_OPEN); + Scope scope = tracer.withSpan(span); + try { + GenericUrl url = new GenericUrl(signURL); + url.set("uploadType", "resumable"); + String bytesArrayParameters = ""; + byte[] bytesArray = new byte[bytesArrayParameters.length()]; + HttpRequestFactory requestFactory = storage.getRequestFactory(); + HttpRequest httpRequest = + requestFactory.buildPostRequest( + url, new ByteArrayContent("", bytesArray, 0, bytesArray.length)); + HttpHeaders requestHeaders = httpRequest.getHeaders(); + requestHeaders.set("X-Upload-Content-Type", firstNonNull("", "application/octet-stream")); + requestHeaders.set("x-goog-resumable", "start"); + HttpResponse response = httpRequest.execute(); + if (response.getStatusCode() != 201) { + GoogleJsonError error = new GoogleJsonError(); + error.setCode(response.getStatusCode()); + error.setMessage(response.getStatusMessage()); + throw translate(error); + } + return response.getHeaders().getLocation(); + } catch (IOException ex) { + span.setStatus(Status.UNKNOWN.withDescription(ex.getMessage())); + throw translate(ex); + } finally { + scope.close(); + span.end(); + } + } + @Override public RewriteResponse openRewrite(RewriteRequest rewriteRequest) { Span span = startSpan(HttpStorageRpcSpans.SPAN_NAME_OPEN_REWRITE); diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java index eecf311a7033..faaec7824939 100644 --- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java +++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java @@ -289,6 +289,13 @@ StorageObject compose( */ String open(StorageObject object, Map options); + /** + * Opens a resumable upload channel for a given storage object. + * + * @throws StorageException upon failure + */ + String getUploadId(String signURL); + /** * Writes the provided bytes to a storage object at the provided location. * diff --git a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java index 8e2d7d14bdb5..7de0b0174654 100644 --- a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java +++ b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java @@ -37,6 +37,7 @@ import com.google.common.collect.ImmutableMap; import java.io.IOException; import java.net.SocketException; +import java.net.URL; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Map; @@ -60,6 +61,8 @@ public class BlobWriteChannelTest { private static final int DEFAULT_CHUNK_SIZE = 8 * MIN_CHUNK_SIZE; private static final int CUSTOM_CHUNK_SIZE = 4 * MIN_CHUNK_SIZE; private static final Random RANDOM = new Random(); + private static final String SIGN_URL = + "http://www.test.com/test-bucket/test1.txt?GoogleAccessId=testClient-test@test.com&Expires=1553839761&Signature=MJUBXAZ7"; @Rule public ExpectedException thrown = ExpectedException.none(); @@ -265,6 +268,122 @@ public void testStateEquals() { assertEquals(state.toString(), state2.toString()); } + @Test + public void testWriteWithSignURLAndWithoutFlush() throws IOException { + expect(storageRpcMock.getUploadId(SIGN_URL)).andReturn(UPLOAD_ID); + replay(storageRpcMock); + writer = new BlobWriteChannel(options, new URL(SIGN_URL)); + assertEquals(MIN_CHUNK_SIZE, writer.write(ByteBuffer.allocate(MIN_CHUNK_SIZE))); + } + + @Test + public void testWriteWithSignURLAndWithFlush() throws IOException { + expect(storageRpcMock.getUploadId(SIGN_URL)).andReturn(UPLOAD_ID); + Capture capturedBuffer = Capture.newInstance(); + storageRpcMock.write( + eq(UPLOAD_ID), capture(capturedBuffer), eq(0), eq(0L), eq(CUSTOM_CHUNK_SIZE), eq(false)); + replay(storageRpcMock); + writer = new BlobWriteChannel(options, new URL(SIGN_URL)); + writer.setChunkSize(CUSTOM_CHUNK_SIZE); + ByteBuffer buffer = randomBuffer(CUSTOM_CHUNK_SIZE); + assertEquals(CUSTOM_CHUNK_SIZE, writer.write(buffer)); + assertArrayEquals(buffer.array(), capturedBuffer.getValue()); + } + + @Test + public void testWriteWithSignURLAndFlush() throws IOException { + expect(storageRpcMock.getUploadId(SIGN_URL)).andReturn(UPLOAD_ID); + Capture capturedBuffer = Capture.newInstance(); + storageRpcMock.write( + eq(UPLOAD_ID), capture(capturedBuffer), eq(0), eq(0L), eq(DEFAULT_CHUNK_SIZE), eq(false)); + replay(storageRpcMock); + writer = new BlobWriteChannel(options, new URL(SIGN_URL)); + ByteBuffer[] buffers = new ByteBuffer[DEFAULT_CHUNK_SIZE / MIN_CHUNK_SIZE]; + for (int i = 0; i < buffers.length; i++) { + buffers[i] = randomBuffer(MIN_CHUNK_SIZE); + assertEquals(MIN_CHUNK_SIZE, writer.write(buffers[i])); + } + for (int i = 0; i < buffers.length; i++) { + assertArrayEquals( + buffers[i].array(), + Arrays.copyOfRange( + capturedBuffer.getValue(), MIN_CHUNK_SIZE * i, MIN_CHUNK_SIZE * (i + 1))); + } + } + + @Test + public void testCloseWithSignURLWithoutFlush() throws IOException { + expect(storageRpcMock.getUploadId(SIGN_URL)).andReturn(UPLOAD_ID); + Capture capturedBuffer = Capture.newInstance(); + storageRpcMock.write(eq(UPLOAD_ID), capture(capturedBuffer), eq(0), eq(0L), eq(0), eq(true)); + replay(storageRpcMock); + writer = new BlobWriteChannel(options, new URL(SIGN_URL)); + assertTrue(writer.isOpen()); + writer.close(); + assertArrayEquals(new byte[0], capturedBuffer.getValue()); + assertTrue(!writer.isOpen()); + } + + @Test + public void testCloseWithSignURLWithFlush() throws IOException { + expect(storageRpcMock.getUploadId(SIGN_URL)).andReturn(UPLOAD_ID); + Capture capturedBuffer = Capture.newInstance(); + ByteBuffer buffer = randomBuffer(MIN_CHUNK_SIZE); + storageRpcMock.write( + eq(UPLOAD_ID), capture(capturedBuffer), eq(0), eq(0L), eq(MIN_CHUNK_SIZE), eq(true)); + replay(storageRpcMock); + writer = new BlobWriteChannel(options, new URL(SIGN_URL)); + assertTrue(writer.isOpen()); + writer.write(buffer); + writer.close(); + assertEquals(DEFAULT_CHUNK_SIZE, capturedBuffer.getValue().length); + assertArrayEquals(buffer.array(), Arrays.copyOf(capturedBuffer.getValue(), MIN_CHUNK_SIZE)); + assertTrue(!writer.isOpen()); + } + + @Test + public void testWriteWithSignURLClosed() throws IOException { + expect(storageRpcMock.getUploadId(SIGN_URL)).andReturn(UPLOAD_ID); + Capture capturedBuffer = Capture.newInstance(); + storageRpcMock.write(eq(UPLOAD_ID), capture(capturedBuffer), eq(0), eq(0L), eq(0), eq(true)); + replay(storageRpcMock); + writer = new BlobWriteChannel(options, new URL(SIGN_URL)); + writer.close(); + try { + writer.write(ByteBuffer.allocate(MIN_CHUNK_SIZE)); + fail("Expected BlobWriteChannel write to throw IOException"); + } catch (IOException ex) { + // expected + } + } + + @Test + public void testSaveAndRestoreWithSignURL() throws IOException { + expect(storageRpcMock.getUploadId(SIGN_URL)).andReturn(UPLOAD_ID); + Capture capturedBuffer = Capture.newInstance(CaptureType.ALL); + Capture capturedPosition = Capture.newInstance(CaptureType.ALL); + storageRpcMock.write( + eq(UPLOAD_ID), + capture(capturedBuffer), + eq(0), + captureLong(capturedPosition), + eq(DEFAULT_CHUNK_SIZE), + eq(false)); + expectLastCall().times(2); + replay(storageRpcMock); + ByteBuffer buffer1 = randomBuffer(DEFAULT_CHUNK_SIZE); + ByteBuffer buffer2 = randomBuffer(DEFAULT_CHUNK_SIZE); + writer = new BlobWriteChannel(options, new URL(SIGN_URL)); + assertEquals(DEFAULT_CHUNK_SIZE, writer.write(buffer1)); + assertArrayEquals(buffer1.array(), capturedBuffer.getValues().get(0)); + assertEquals(new Long(0L), capturedPosition.getValues().get(0)); + RestorableState writerState = writer.capture(); + WriteChannel restoredWriter = writerState.restore(); + assertEquals(DEFAULT_CHUNK_SIZE, restoredWriter.write(buffer2)); + assertArrayEquals(buffer2.array(), capturedBuffer.getValues().get(1)); + assertEquals(new Long(DEFAULT_CHUNK_SIZE), capturedPosition.getValues().get(1)); + } + private static ByteBuffer randomBuffer(int size) { byte[] byteArray = new byte[size]; RANDOM.nextBytes(byteArray); diff --git a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java index 0d77547e7605..5e9b9032d264 100644 --- a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java +++ b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java @@ -59,6 +59,7 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; import java.net.URL; import java.net.URLDecoder; import java.nio.ByteBuffer; @@ -319,6 +320,9 @@ public class StorageImplTest { + "EkPPhszldvQTY486uPxyD/D7HdfnGW/Nbw5JUhfvecAdudDEhNAQ3PNabyDMI+TpiHy4NTWOrgdcWrzj6VXcdc" + "+uuABnPwRCdcyJ1xl2kOrPksRnp1auNGMLOe4IpEBjGY7baX9UG8+A45MbG0aHmkR59Op/aR9XowIDAQAB"; + private static final String SIGN_URL = + "http://www.test.com/test-bucket/test1.txt?GoogleAccessId=testClient-test@test.com&Expires=1553839761&Signature=MJUBXAZ7"; + private static final ApiClock TIME_SOURCE = new ApiClock() { @Override @@ -2835,4 +2839,14 @@ public void testRuntimeException() { thrown.expectMessage(exceptionMessage); storage.get(blob); } + + @Test + public void testWriterWithSignURL() throws MalformedURLException { + EasyMock.expect(storageRpcMock.getUploadId(SIGN_URL)).andReturn("upload-id"); + EasyMock.replay(storageRpcMock); + initializeService(); + WriteChannel writer = new BlobWriteChannel(options, new URL(SIGN_URL)); + assertNotNull(writer); + assertTrue(writer.isOpen()); + } } From e8e975dfbdcb3496ec535f591f32a7fe24de3549 Mon Sep 17 00:00:00 2001 From: abhinav Date: Tue, 2 Apr 2019 12:04:22 +0530 Subject: [PATCH 02/14] for manage resumeable signedURL uploads #2462 --- .../contrib/nio/testing/FakeStorageRpc.java | 2 +- .../google/cloud/storage/BlobWriteChannel.java | 6 +++--- .../java/com/google/cloud/storage/Storage.java | 16 ++++++++++++++-- .../cloud/storage/spi/v1/HttpStorageRpc.java | 2 +- .../google/cloud/storage/spi/v1/StorageRpc.java | 2 +- .../cloud/storage/BlobWriteChannelTest.java | 14 +++++++------- .../google/cloud/storage/StorageImplTest.java | 2 +- 7 files changed, 28 insertions(+), 16 deletions(-) diff --git a/google-cloud-clients/google-cloud-contrib/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/testing/FakeStorageRpc.java b/google-cloud-clients/google-cloud-contrib/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/testing/FakeStorageRpc.java index b1a451e6fcc6..838a092f08d9 100644 --- a/google-cloud-clients/google-cloud-contrib/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/testing/FakeStorageRpc.java +++ b/google-cloud-clients/google-cloud-contrib/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/testing/FakeStorageRpc.java @@ -313,7 +313,7 @@ public String open(StorageObject object, Map options) throws StorageE } @Override - public String getUploadId(String signURL) { + public String open(String signURL) { return null; } diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java index 306214b65d6b..56acd6ac4546 100644 --- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java +++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java @@ -36,7 +36,7 @@ class BlobWriteChannel extends BaseWriteChannel { } BlobWriteChannel(StorageOptions options, URL signURL) { - this(options, getUploadId(signURL.toString(), options)); + this(options, open(signURL.toString(), options)); } BlobWriteChannel(StorageOptions options, BlobInfo blobInfo, String uploadId) { @@ -92,13 +92,13 @@ public String call() { } } - private static String getUploadId(final String signURL, final StorageOptions options) { + private static String open(final String signURL, final StorageOptions options) { try { return runWithRetries( new Callable() { @Override public String call() { - return options.getStorageRpcV1().getUploadId(signURL); + return options.getStorageRpcV1().open(signURL); } }, options.getRetrySettings(), diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java index c82f37546d2a..d47d7f59258a 100644 --- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java +++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java @@ -22,8 +22,13 @@ import com.google.api.gax.paging.Page; import com.google.auth.ServiceAccountSigner; import com.google.auth.ServiceAccountSigner.SigningException; -import com.google.cloud.*; +import com.google.cloud.FieldSelector; import com.google.cloud.FieldSelector.Helper; +import com.google.cloud.Policy; +import com.google.cloud.ReadChannel; +import com.google.cloud.Service; +import com.google.cloud.Tuple; +import com.google.cloud.WriteChannel; import com.google.cloud.storage.Acl.Entity; import com.google.cloud.storage.spi.v1.StorageRpc; import com.google.common.collect.ImmutableList; @@ -34,7 +39,14 @@ import java.io.Serializable; import java.net.URL; import java.security.Key; -import java.util.*; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; import java.util.concurrent.TimeUnit; /** diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java index f22ec53fd6e5..c05a5301d25e 100644 --- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java +++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java @@ -823,7 +823,7 @@ public String open(StorageObject object, Map options) { } @Override - public String getUploadId(String signURL) { + public String open(String signURL) { Span span = startSpan(HttpStorageRpcSpans.SPAN_NAME_OPEN); Scope scope = tracer.withSpan(span); try { diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java index faaec7824939..6ffd1f5a2ba8 100644 --- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java +++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java @@ -294,7 +294,7 @@ StorageObject compose( * * @throws StorageException upon failure */ - String getUploadId(String signURL); + String open(String signURL); /** * Writes the provided bytes to a storage object at the provided location. diff --git a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java index 7de0b0174654..f44a59b0018c 100644 --- a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java +++ b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java @@ -270,7 +270,7 @@ public void testStateEquals() { @Test public void testWriteWithSignURLAndWithoutFlush() throws IOException { - expect(storageRpcMock.getUploadId(SIGN_URL)).andReturn(UPLOAD_ID); + expect(storageRpcMock.open(SIGN_URL)).andReturn(UPLOAD_ID); replay(storageRpcMock); writer = new BlobWriteChannel(options, new URL(SIGN_URL)); assertEquals(MIN_CHUNK_SIZE, writer.write(ByteBuffer.allocate(MIN_CHUNK_SIZE))); @@ -278,7 +278,7 @@ public void testWriteWithSignURLAndWithoutFlush() throws IOException { @Test public void testWriteWithSignURLAndWithFlush() throws IOException { - expect(storageRpcMock.getUploadId(SIGN_URL)).andReturn(UPLOAD_ID); + expect(storageRpcMock.open(SIGN_URL)).andReturn(UPLOAD_ID); Capture capturedBuffer = Capture.newInstance(); storageRpcMock.write( eq(UPLOAD_ID), capture(capturedBuffer), eq(0), eq(0L), eq(CUSTOM_CHUNK_SIZE), eq(false)); @@ -292,7 +292,7 @@ public void testWriteWithSignURLAndWithFlush() throws IOException { @Test public void testWriteWithSignURLAndFlush() throws IOException { - expect(storageRpcMock.getUploadId(SIGN_URL)).andReturn(UPLOAD_ID); + expect(storageRpcMock.open(SIGN_URL)).andReturn(UPLOAD_ID); Capture capturedBuffer = Capture.newInstance(); storageRpcMock.write( eq(UPLOAD_ID), capture(capturedBuffer), eq(0), eq(0L), eq(DEFAULT_CHUNK_SIZE), eq(false)); @@ -313,7 +313,7 @@ public void testWriteWithSignURLAndFlush() throws IOException { @Test public void testCloseWithSignURLWithoutFlush() throws IOException { - expect(storageRpcMock.getUploadId(SIGN_URL)).andReturn(UPLOAD_ID); + expect(storageRpcMock.open(SIGN_URL)).andReturn(UPLOAD_ID); Capture capturedBuffer = Capture.newInstance(); storageRpcMock.write(eq(UPLOAD_ID), capture(capturedBuffer), eq(0), eq(0L), eq(0), eq(true)); replay(storageRpcMock); @@ -326,7 +326,7 @@ public void testCloseWithSignURLWithoutFlush() throws IOException { @Test public void testCloseWithSignURLWithFlush() throws IOException { - expect(storageRpcMock.getUploadId(SIGN_URL)).andReturn(UPLOAD_ID); + expect(storageRpcMock.open(SIGN_URL)).andReturn(UPLOAD_ID); Capture capturedBuffer = Capture.newInstance(); ByteBuffer buffer = randomBuffer(MIN_CHUNK_SIZE); storageRpcMock.write( @@ -343,7 +343,7 @@ public void testCloseWithSignURLWithFlush() throws IOException { @Test public void testWriteWithSignURLClosed() throws IOException { - expect(storageRpcMock.getUploadId(SIGN_URL)).andReturn(UPLOAD_ID); + expect(storageRpcMock.open(SIGN_URL)).andReturn(UPLOAD_ID); Capture capturedBuffer = Capture.newInstance(); storageRpcMock.write(eq(UPLOAD_ID), capture(capturedBuffer), eq(0), eq(0L), eq(0), eq(true)); replay(storageRpcMock); @@ -359,7 +359,7 @@ public void testWriteWithSignURLClosed() throws IOException { @Test public void testSaveAndRestoreWithSignURL() throws IOException { - expect(storageRpcMock.getUploadId(SIGN_URL)).andReturn(UPLOAD_ID); + expect(storageRpcMock.open(SIGN_URL)).andReturn(UPLOAD_ID); Capture capturedBuffer = Capture.newInstance(CaptureType.ALL); Capture capturedPosition = Capture.newInstance(CaptureType.ALL); storageRpcMock.write( diff --git a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java index 5e9b9032d264..8c2c301b9bfa 100644 --- a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java +++ b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java @@ -2842,7 +2842,7 @@ public void testRuntimeException() { @Test public void testWriterWithSignURL() throws MalformedURLException { - EasyMock.expect(storageRpcMock.getUploadId(SIGN_URL)).andReturn("upload-id"); + EasyMock.expect(storageRpcMock.open(SIGN_URL)).andReturn("upload-id"); EasyMock.replay(storageRpcMock); initializeService(); WriteChannel writer = new BlobWriteChannel(options, new URL(SIGN_URL)); From 08e096730fcd8e0d8bda637d64164817feba7cfc Mon Sep 17 00:00:00 2001 From: abhinav Date: Tue, 2 Apr 2019 12:18:45 +0530 Subject: [PATCH 03/14] fix comment --- .../main/java/com/google/cloud/storage/spi/v1/StorageRpc.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java index 6ffd1f5a2ba8..cf1ae3e2a274 100644 --- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java +++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java @@ -290,7 +290,7 @@ StorageObject compose( String open(StorageObject object, Map options); /** - * Opens a resumable upload channel for a given storage object. + * Opens a resumable upload channel for a given signUrl. * * @throws StorageException upon failure */ From b51217618109b2bab98019e0bbf38ff1ed493dd1 Mon Sep 17 00:00:00 2001 From: abhinav Date: Tue, 2 Apr 2019 17:10:19 +0530 Subject: [PATCH 04/14] fix ITStorageTest case written for upload using signURL --- .../cloud/storage/it/ITStorageTest.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java index 0e9e33f177bf..182f828041c5 100644 --- a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java +++ b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java @@ -2542,4 +2542,29 @@ public void testEnableAndDisableBucketPolicyOnlyOnExistingBucket() throws Except RemoteStorageHelper.forceDelete(storage, bpoBucket, 1, TimeUnit.MINUTES); } } + + @Test + public void testUploadUsingSignURL() throws Exception { + String blobName = "test-signed-url-upload"; + BlobInfo blob = BlobInfo.newBuilder(BUCKET, blobName).build(); + assertNotNull(storage.create(blob)); + URL signUrl = + storage.signUrl(blob, 1, TimeUnit.HOURS, Storage.SignUrlOption.httpMethod(HttpMethod.POST)); + byte[] bytesArrayToUpload = BLOB_STRING_CONTENT.getBytes(); + try (WriteChannel writer = storage.writer(signUrl)) { + writer.write(ByteBuffer.wrap(bytesArrayToUpload, 0, bytesArrayToUpload.length)); + } + + int lengthOfDownLoadBytes = -1; + BlobId blobId = BlobId.of(BUCKET, blobName); + Blob blobToRead = storage.get(blobId); + try (ReadChannel reader = blobToRead.reader()) { + ByteBuffer bytes = ByteBuffer.allocate(64 * 1024); + lengthOfDownLoadBytes = reader.read(bytes); + } + + assertEquals(bytesArrayToUpload.length, lengthOfDownLoadBytes); + assertTrue(storage.delete(BUCKET, blobName)); + + } } From 5f78509d3c10d51f30f74829d4deec7f65e2a0fb Mon Sep 17 00:00:00 2001 From: abhinav Date: Tue, 2 Apr 2019 17:54:52 +0530 Subject: [PATCH 05/14] fix format --- .../test/java/com/google/cloud/storage/it/ITStorageTest.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java index 182f828041c5..919fc5030e71 100644 --- a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java +++ b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java @@ -2549,10 +2549,10 @@ public void testUploadUsingSignURL() throws Exception { BlobInfo blob = BlobInfo.newBuilder(BUCKET, blobName).build(); assertNotNull(storage.create(blob)); URL signUrl = - storage.signUrl(blob, 1, TimeUnit.HOURS, Storage.SignUrlOption.httpMethod(HttpMethod.POST)); + storage.signUrl(blob, 1, TimeUnit.HOURS, Storage.SignUrlOption.httpMethod(HttpMethod.POST)); byte[] bytesArrayToUpload = BLOB_STRING_CONTENT.getBytes(); try (WriteChannel writer = storage.writer(signUrl)) { - writer.write(ByteBuffer.wrap(bytesArrayToUpload, 0, bytesArrayToUpload.length)); + writer.write(ByteBuffer.wrap(bytesArrayToUpload, 0, bytesArrayToUpload.length)); } int lengthOfDownLoadBytes = -1; @@ -2565,6 +2565,5 @@ public void testUploadUsingSignURL() throws Exception { assertEquals(bytesArrayToUpload.length, lengthOfDownLoadBytes); assertTrue(storage.delete(BUCKET, blobName)); - } } From 422aa1da265dd0344d242996c7b5526ce26e3d00 Mon Sep 17 00:00:00 2001 From: abhinav Date: Tue, 2 Apr 2019 18:34:17 +0530 Subject: [PATCH 06/14] fix BlobWriteChannel constructor changes. --- .../src/main/java/com/google/cloud/storage/StorageImpl.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageImpl.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageImpl.java index 707b3b80e61c..04d51ad81d4a 100644 --- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageImpl.java +++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageImpl.java @@ -600,8 +600,7 @@ public BlobWriteChannel writer(BlobInfo blobInfo, BlobWriteOption... options) { @Override public BlobWriteChannel writer(URL signURL) { - final StorageOptions options = StorageOptions.newBuilder().build(); - return new BlobWriteChannel(options, signURL); + return new BlobWriteChannel(getOptions(), signURL); } private BlobWriteChannel writer(BlobInfo blobInfo, BlobTargetOption... options) { From b34a6c64eb9bf3d9a00ca277145e4cc319a62955 Mon Sep 17 00:00:00 2001 From: abhinav Date: Wed, 3 Apr 2019 19:15:51 +0530 Subject: [PATCH 07/14] fix signURL validation. --- .../cloud/storage/BlobWriteChannel.java | 16 ++++-- .../cloud/storage/BlobWriteChannelTest.java | 56 ++++++++++++------- 2 files changed, 46 insertions(+), 26 deletions(-) diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java index 56acd6ac4546..aca68d0678d7 100644 --- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java +++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java @@ -16,18 +16,19 @@ package com.google.cloud.storage; -import static com.google.cloud.RetryHelper.runWithRetries; -import static java.util.concurrent.Executors.callable; - import com.google.cloud.BaseWriteChannel; import com.google.cloud.RestorableState; import com.google.cloud.RetryHelper; import com.google.cloud.WriteChannel; import com.google.cloud.storage.spi.v1.StorageRpc; + import java.net.URL; import java.util.Map; import java.util.concurrent.Callable; +import static com.google.cloud.RetryHelper.runWithRetries; +import static java.util.concurrent.Executors.callable; + /** Write channel implementation to upload Google Cloud Storage blobs. */ class BlobWriteChannel extends BaseWriteChannel { @@ -36,7 +37,7 @@ class BlobWriteChannel extends BaseWriteChannel { } BlobWriteChannel(StorageOptions options, URL signURL) { - this(options, open(signURL.toString(), options)); + this(options, open(signURL, options)); } BlobWriteChannel(StorageOptions options, BlobInfo blobInfo, String uploadId) { @@ -92,13 +93,16 @@ public String call() { } } - private static String open(final String signURL, final StorageOptions options) { + private static String open(final URL signURL, final StorageOptions options) { try { return runWithRetries( new Callable() { @Override public String call() { - return options.getStorageRpcV1().open(signURL); + if (!signURL.getQuery().contains("&Signature=")) { + throw new StorageException(2, "invalid signURL"); + } + return options.getStorageRpcV1().open(signURL.toString()); } }, options.getRetrySettings(), diff --git a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java index f44a59b0018c..a68f51a13761 100644 --- a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java +++ b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java @@ -16,6 +16,28 @@ package com.google.cloud.storage; +import com.google.cloud.RestorableState; +import com.google.cloud.WriteChannel; +import com.google.cloud.storage.spi.StorageRpcFactory; +import com.google.cloud.storage.spi.v1.StorageRpc; +import com.google.common.collect.ImmutableMap; +import org.easymock.Capture; +import org.easymock.CaptureType; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.SocketException; +import java.net.URL; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Map; +import java.util.Random; + import static org.easymock.EasyMock.anyObject; import static org.easymock.EasyMock.capture; import static org.easymock.EasyMock.captureLong; @@ -30,26 +52,6 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import com.google.cloud.RestorableState; -import com.google.cloud.WriteChannel; -import com.google.cloud.storage.spi.StorageRpcFactory; -import com.google.cloud.storage.spi.v1.StorageRpc; -import com.google.common.collect.ImmutableMap; -import java.io.IOException; -import java.net.SocketException; -import java.net.URL; -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.Map; -import java.util.Random; -import org.easymock.Capture; -import org.easymock.CaptureType; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - public class BlobWriteChannelTest { private static final String BUCKET_NAME = "b"; @@ -64,6 +66,10 @@ public class BlobWriteChannelTest { private static final String SIGN_URL = "http://www.test.com/test-bucket/test1.txt?GoogleAccessId=testClient-test@test.com&Expires=1553839761&Signature=MJUBXAZ7"; + private static final String SIGN_URL_WITH_OUT_SIGNATURE = + "http://www.test.com/test-bucket/test1.txt?GoogleAccessId=testClient-test@test.com&Expires=1553839761"; + + @Rule public ExpectedException thrown = ExpectedException.none(); private StorageOptions options; @@ -384,6 +390,16 @@ public void testSaveAndRestoreWithSignURL() throws IOException { assertEquals(new Long(DEFAULT_CHUNK_SIZE), capturedPosition.getValues().get(1)); } + @Test + public void testRuntimeExceptionWithSignURL() throws MalformedURLException { + String exceptionMessage = "invalid signURL"; + expect(new BlobWriteChannel(options, new URL(SIGN_URL))).andThrow(new RuntimeException(exceptionMessage)); + replay(storageRpcMock); + thrown.expect(StorageException.class); + thrown.expectMessage(exceptionMessage); + writer = new BlobWriteChannel(options, new URL(SIGN_URL)); + } + private static ByteBuffer randomBuffer(int size) { byte[] byteArray = new byte[size]; RANDOM.nextBytes(byteArray); From 398d37095e6d3d442579c643c11d6471da1c4373 Mon Sep 17 00:00:00 2001 From: abhinav Date: Wed, 3 Apr 2019 19:54:08 +0530 Subject: [PATCH 08/14] fix format --- .../cloud/storage/BlobWriteChannel.java | 7 ++- .../cloud/storage/BlobWriteChannelTest.java | 49 +++++++++---------- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java index aca68d0678d7..d5a2cefe656e 100644 --- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java +++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java @@ -16,19 +16,18 @@ package com.google.cloud.storage; +import static com.google.cloud.RetryHelper.runWithRetries; +import static java.util.concurrent.Executors.callable; + import com.google.cloud.BaseWriteChannel; import com.google.cloud.RestorableState; import com.google.cloud.RetryHelper; import com.google.cloud.WriteChannel; import com.google.cloud.storage.spi.v1.StorageRpc; - import java.net.URL; import java.util.Map; import java.util.concurrent.Callable; -import static com.google.cloud.RetryHelper.runWithRetries; -import static java.util.concurrent.Executors.callable; - /** Write channel implementation to upload Google Cloud Storage blobs. */ class BlobWriteChannel extends BaseWriteChannel { diff --git a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java index a68f51a13761..d26a727f2603 100644 --- a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java +++ b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java @@ -16,28 +16,6 @@ package com.google.cloud.storage; -import com.google.cloud.RestorableState; -import com.google.cloud.WriteChannel; -import com.google.cloud.storage.spi.StorageRpcFactory; -import com.google.cloud.storage.spi.v1.StorageRpc; -import com.google.common.collect.ImmutableMap; -import org.easymock.Capture; -import org.easymock.CaptureType; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.SocketException; -import java.net.URL; -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.Map; -import java.util.Random; - import static org.easymock.EasyMock.anyObject; import static org.easymock.EasyMock.capture; import static org.easymock.EasyMock.captureLong; @@ -52,6 +30,27 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import com.google.cloud.RestorableState; +import com.google.cloud.WriteChannel; +import com.google.cloud.storage.spi.StorageRpcFactory; +import com.google.cloud.storage.spi.v1.StorageRpc; +import com.google.common.collect.ImmutableMap; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.SocketException; +import java.net.URL; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Map; +import java.util.Random; +import org.easymock.Capture; +import org.easymock.CaptureType; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + public class BlobWriteChannelTest { private static final String BUCKET_NAME = "b"; @@ -67,8 +66,7 @@ public class BlobWriteChannelTest { "http://www.test.com/test-bucket/test1.txt?GoogleAccessId=testClient-test@test.com&Expires=1553839761&Signature=MJUBXAZ7"; private static final String SIGN_URL_WITH_OUT_SIGNATURE = - "http://www.test.com/test-bucket/test1.txt?GoogleAccessId=testClient-test@test.com&Expires=1553839761"; - + "http://www.test.com/test-bucket/test1.txt?GoogleAccessId=testClient-test@test.com&Expires=1553839761"; @Rule public ExpectedException thrown = ExpectedException.none(); @@ -393,7 +391,8 @@ public void testSaveAndRestoreWithSignURL() throws IOException { @Test public void testRuntimeExceptionWithSignURL() throws MalformedURLException { String exceptionMessage = "invalid signURL"; - expect(new BlobWriteChannel(options, new URL(SIGN_URL))).andThrow(new RuntimeException(exceptionMessage)); + expect(new BlobWriteChannel(options, new URL(SIGN_URL))) + .andThrow(new RuntimeException(exceptionMessage)); replay(storageRpcMock); thrown.expect(StorageException.class); thrown.expectMessage(exceptionMessage); From fd13f06957ded762f8a88b107194b78e9778d489 Mon Sep 17 00:00:00 2001 From: abhinav Date: Mon, 8 Apr 2019 13:51:51 +0530 Subject: [PATCH 09/14] signurl rename to signedURL , firstnonnull check removed,signedURL validation with googleacessid and expires field also. --- .../contrib/nio/testing/FakeStorageRpc.java | 2 +- .../google-cloud-storage/.attach_pid8524 | 0 .../cloud/storage/BlobWriteChannel.java | 16 ++++-- .../com/google/cloud/storage/Storage.java | 2 +- .../com/google/cloud/storage/StorageImpl.java | 4 +- .../cloud/storage/spi/v1/HttpStorageRpc.java | 6 +- .../cloud/storage/BlobWriteChannelTest.java | 55 +++++++++---------- .../google/cloud/storage/StorageImplTest.java | 8 +-- .../cloud/storage/it/ITStorageTest.java | 2 +- 9 files changed, 48 insertions(+), 47 deletions(-) create mode 100644 google-cloud-clients/google-cloud-storage/.attach_pid8524 diff --git a/google-cloud-clients/google-cloud-contrib/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/testing/FakeStorageRpc.java b/google-cloud-clients/google-cloud-contrib/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/testing/FakeStorageRpc.java index 838a092f08d9..bee18dda5290 100644 --- a/google-cloud-clients/google-cloud-contrib/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/testing/FakeStorageRpc.java +++ b/google-cloud-clients/google-cloud-contrib/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/testing/FakeStorageRpc.java @@ -313,7 +313,7 @@ public String open(StorageObject object, Map options) throws StorageE } @Override - public String open(String signURL) { + public String open(String signedURL) { return null; } diff --git a/google-cloud-clients/google-cloud-storage/.attach_pid8524 b/google-cloud-clients/google-cloud-storage/.attach_pid8524 new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java index d5a2cefe656e..5b5507070cd2 100644 --- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java +++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java @@ -35,8 +35,8 @@ class BlobWriteChannel extends BaseWriteChannel { this(options, blob, open(options, blob, optionsMap)); } - BlobWriteChannel(StorageOptions options, URL signURL) { - this(options, open(signURL, options)); + BlobWriteChannel(StorageOptions options, URL signedURL) { + this(options, open(signedURL, options)); } BlobWriteChannel(StorageOptions options, BlobInfo blobInfo, String uploadId) { @@ -92,16 +92,20 @@ public String call() { } } - private static String open(final URL signURL, final StorageOptions options) { + private static String open(final URL signedURL, final StorageOptions options) { try { return runWithRetries( new Callable() { @Override public String call() { - if (!signURL.getQuery().contains("&Signature=")) { - throw new StorageException(2, "invalid signURL"); + String signedURLQuery = signedURL.getQuery(); + if (null != signedURLQuery + && signedURLQuery.startsWith("GoogleAccessId=") + && signedURLQuery.contains("&Expires=") + && !signedURL.getQuery().contains("&Signature=")) { + throw new StorageException(2, "invalid signedURL"); } - return options.getStorageRpcV1().open(signURL.toString()); + return options.getStorageRpcV1().open(signedURL.toString()); } }, options.getRetrySettings(), diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java index d47d7f59258a..751e3e900bfe 100644 --- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java +++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java @@ -2073,7 +2073,7 @@ Blob create( * * @throws StorageException upon failure */ - WriteChannel writer(URL signURL); + WriteChannel writer(URL signedURL); /** * Generates a signed URL for a blob. If you have a blob that you want to allow access to for a diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageImpl.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageImpl.java index 04d51ad81d4a..14a2c7281e68 100644 --- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageImpl.java +++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageImpl.java @@ -599,8 +599,8 @@ public BlobWriteChannel writer(BlobInfo blobInfo, BlobWriteOption... options) { } @Override - public BlobWriteChannel writer(URL signURL) { - return new BlobWriteChannel(getOptions(), signURL); + public BlobWriteChannel writer(URL signedURL) { + return new BlobWriteChannel(getOptions(), signedURL); } private BlobWriteChannel writer(BlobInfo blobInfo, BlobTargetOption... options) { diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java index c05a5301d25e..d162b33c5c7f 100644 --- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java +++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java @@ -823,11 +823,11 @@ public String open(StorageObject object, Map options) { } @Override - public String open(String signURL) { + public String open(String signedURL) { Span span = startSpan(HttpStorageRpcSpans.SPAN_NAME_OPEN); Scope scope = tracer.withSpan(span); try { - GenericUrl url = new GenericUrl(signURL); + GenericUrl url = new GenericUrl(signedURL); url.set("uploadType", "resumable"); String bytesArrayParameters = ""; byte[] bytesArray = new byte[bytesArrayParameters.length()]; @@ -836,7 +836,7 @@ public String open(String signURL) { requestFactory.buildPostRequest( url, new ByteArrayContent("", bytesArray, 0, bytesArray.length)); HttpHeaders requestHeaders = httpRequest.getHeaders(); - requestHeaders.set("X-Upload-Content-Type", firstNonNull("", "application/octet-stream")); + requestHeaders.set("X-Upload-Content-Type", ""); requestHeaders.set("x-goog-resumable", "start"); HttpResponse response = httpRequest.execute(); if (response.getStatusCode() != 201) { diff --git a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java index d26a727f2603..d3cd439d203e 100644 --- a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java +++ b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java @@ -62,12 +62,9 @@ public class BlobWriteChannelTest { private static final int DEFAULT_CHUNK_SIZE = 8 * MIN_CHUNK_SIZE; private static final int CUSTOM_CHUNK_SIZE = 4 * MIN_CHUNK_SIZE; private static final Random RANDOM = new Random(); - private static final String SIGN_URL = + private static final String SIGNED_URL = "http://www.test.com/test-bucket/test1.txt?GoogleAccessId=testClient-test@test.com&Expires=1553839761&Signature=MJUBXAZ7"; - private static final String SIGN_URL_WITH_OUT_SIGNATURE = - "http://www.test.com/test-bucket/test1.txt?GoogleAccessId=testClient-test@test.com&Expires=1553839761"; - @Rule public ExpectedException thrown = ExpectedException.none(); private StorageOptions options; @@ -273,21 +270,21 @@ public void testStateEquals() { } @Test - public void testWriteWithSignURLAndWithoutFlush() throws IOException { - expect(storageRpcMock.open(SIGN_URL)).andReturn(UPLOAD_ID); + public void testWriteWithSignedURLAndWithoutFlush() throws IOException { + expect(storageRpcMock.open(SIGNED_URL)).andReturn(UPLOAD_ID); replay(storageRpcMock); - writer = new BlobWriteChannel(options, new URL(SIGN_URL)); + writer = new BlobWriteChannel(options, new URL(SIGNED_URL)); assertEquals(MIN_CHUNK_SIZE, writer.write(ByteBuffer.allocate(MIN_CHUNK_SIZE))); } @Test - public void testWriteWithSignURLAndWithFlush() throws IOException { - expect(storageRpcMock.open(SIGN_URL)).andReturn(UPLOAD_ID); + public void testWriteWithSignedURLAndWithFlush() throws IOException { + expect(storageRpcMock.open(SIGNED_URL)).andReturn(UPLOAD_ID); Capture capturedBuffer = Capture.newInstance(); storageRpcMock.write( eq(UPLOAD_ID), capture(capturedBuffer), eq(0), eq(0L), eq(CUSTOM_CHUNK_SIZE), eq(false)); replay(storageRpcMock); - writer = new BlobWriteChannel(options, new URL(SIGN_URL)); + writer = new BlobWriteChannel(options, new URL(SIGNED_URL)); writer.setChunkSize(CUSTOM_CHUNK_SIZE); ByteBuffer buffer = randomBuffer(CUSTOM_CHUNK_SIZE); assertEquals(CUSTOM_CHUNK_SIZE, writer.write(buffer)); @@ -295,13 +292,13 @@ public void testWriteWithSignURLAndWithFlush() throws IOException { } @Test - public void testWriteWithSignURLAndFlush() throws IOException { - expect(storageRpcMock.open(SIGN_URL)).andReturn(UPLOAD_ID); + public void testWriteWithSignedURLAndFlush() throws IOException { + expect(storageRpcMock.open(SIGNED_URL)).andReturn(UPLOAD_ID); Capture capturedBuffer = Capture.newInstance(); storageRpcMock.write( eq(UPLOAD_ID), capture(capturedBuffer), eq(0), eq(0L), eq(DEFAULT_CHUNK_SIZE), eq(false)); replay(storageRpcMock); - writer = new BlobWriteChannel(options, new URL(SIGN_URL)); + writer = new BlobWriteChannel(options, new URL(SIGNED_URL)); ByteBuffer[] buffers = new ByteBuffer[DEFAULT_CHUNK_SIZE / MIN_CHUNK_SIZE]; for (int i = 0; i < buffers.length; i++) { buffers[i] = randomBuffer(MIN_CHUNK_SIZE); @@ -316,12 +313,12 @@ public void testWriteWithSignURLAndFlush() throws IOException { } @Test - public void testCloseWithSignURLWithoutFlush() throws IOException { - expect(storageRpcMock.open(SIGN_URL)).andReturn(UPLOAD_ID); + public void testCloseWithSignedURLWithoutFlush() throws IOException { + expect(storageRpcMock.open(SIGNED_URL)).andReturn(UPLOAD_ID); Capture capturedBuffer = Capture.newInstance(); storageRpcMock.write(eq(UPLOAD_ID), capture(capturedBuffer), eq(0), eq(0L), eq(0), eq(true)); replay(storageRpcMock); - writer = new BlobWriteChannel(options, new URL(SIGN_URL)); + writer = new BlobWriteChannel(options, new URL(SIGNED_URL)); assertTrue(writer.isOpen()); writer.close(); assertArrayEquals(new byte[0], capturedBuffer.getValue()); @@ -329,14 +326,14 @@ public void testCloseWithSignURLWithoutFlush() throws IOException { } @Test - public void testCloseWithSignURLWithFlush() throws IOException { - expect(storageRpcMock.open(SIGN_URL)).andReturn(UPLOAD_ID); + public void testCloseWithSignedURLWithFlush() throws IOException { + expect(storageRpcMock.open(SIGNED_URL)).andReturn(UPLOAD_ID); Capture capturedBuffer = Capture.newInstance(); ByteBuffer buffer = randomBuffer(MIN_CHUNK_SIZE); storageRpcMock.write( eq(UPLOAD_ID), capture(capturedBuffer), eq(0), eq(0L), eq(MIN_CHUNK_SIZE), eq(true)); replay(storageRpcMock); - writer = new BlobWriteChannel(options, new URL(SIGN_URL)); + writer = new BlobWriteChannel(options, new URL(SIGNED_URL)); assertTrue(writer.isOpen()); writer.write(buffer); writer.close(); @@ -346,12 +343,12 @@ public void testCloseWithSignURLWithFlush() throws IOException { } @Test - public void testWriteWithSignURLClosed() throws IOException { - expect(storageRpcMock.open(SIGN_URL)).andReturn(UPLOAD_ID); + public void testWriteWithSignedURLClosed() throws IOException { + expect(storageRpcMock.open(SIGNED_URL)).andReturn(UPLOAD_ID); Capture capturedBuffer = Capture.newInstance(); storageRpcMock.write(eq(UPLOAD_ID), capture(capturedBuffer), eq(0), eq(0L), eq(0), eq(true)); replay(storageRpcMock); - writer = new BlobWriteChannel(options, new URL(SIGN_URL)); + writer = new BlobWriteChannel(options, new URL(SIGNED_URL)); writer.close(); try { writer.write(ByteBuffer.allocate(MIN_CHUNK_SIZE)); @@ -362,8 +359,8 @@ public void testWriteWithSignURLClosed() throws IOException { } @Test - public void testSaveAndRestoreWithSignURL() throws IOException { - expect(storageRpcMock.open(SIGN_URL)).andReturn(UPLOAD_ID); + public void testSaveAndRestoreWithSignedURL() throws IOException { + expect(storageRpcMock.open(SIGNED_URL)).andReturn(UPLOAD_ID); Capture capturedBuffer = Capture.newInstance(CaptureType.ALL); Capture capturedPosition = Capture.newInstance(CaptureType.ALL); storageRpcMock.write( @@ -377,7 +374,7 @@ public void testSaveAndRestoreWithSignURL() throws IOException { replay(storageRpcMock); ByteBuffer buffer1 = randomBuffer(DEFAULT_CHUNK_SIZE); ByteBuffer buffer2 = randomBuffer(DEFAULT_CHUNK_SIZE); - writer = new BlobWriteChannel(options, new URL(SIGN_URL)); + writer = new BlobWriteChannel(options, new URL(SIGNED_URL)); assertEquals(DEFAULT_CHUNK_SIZE, writer.write(buffer1)); assertArrayEquals(buffer1.array(), capturedBuffer.getValues().get(0)); assertEquals(new Long(0L), capturedPosition.getValues().get(0)); @@ -389,14 +386,14 @@ public void testSaveAndRestoreWithSignURL() throws IOException { } @Test - public void testRuntimeExceptionWithSignURL() throws MalformedURLException { - String exceptionMessage = "invalid signURL"; - expect(new BlobWriteChannel(options, new URL(SIGN_URL))) + public void testRuntimeExceptionWithSignedURL() throws MalformedURLException { + String exceptionMessage = "invalid signedURL"; + expect(new BlobWriteChannel(options, new URL(SIGNED_URL))) .andThrow(new RuntimeException(exceptionMessage)); replay(storageRpcMock); thrown.expect(StorageException.class); thrown.expectMessage(exceptionMessage); - writer = new BlobWriteChannel(options, new URL(SIGN_URL)); + writer = new BlobWriteChannel(options, new URL(SIGNED_URL)); } private static ByteBuffer randomBuffer(int size) { diff --git a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java index 8c2c301b9bfa..a1e5ed6f0a7c 100644 --- a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java +++ b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java @@ -320,7 +320,7 @@ public class StorageImplTest { + "EkPPhszldvQTY486uPxyD/D7HdfnGW/Nbw5JUhfvecAdudDEhNAQ3PNabyDMI+TpiHy4NTWOrgdcWrzj6VXcdc" + "+uuABnPwRCdcyJ1xl2kOrPksRnp1auNGMLOe4IpEBjGY7baX9UG8+A45MbG0aHmkR59Op/aR9XowIDAQAB"; - private static final String SIGN_URL = + private static final String SIGNED_URL = "http://www.test.com/test-bucket/test1.txt?GoogleAccessId=testClient-test@test.com&Expires=1553839761&Signature=MJUBXAZ7"; private static final ApiClock TIME_SOURCE = @@ -2841,11 +2841,11 @@ public void testRuntimeException() { } @Test - public void testWriterWithSignURL() throws MalformedURLException { - EasyMock.expect(storageRpcMock.open(SIGN_URL)).andReturn("upload-id"); + public void testWriterWithSignedURL() throws MalformedURLException { + EasyMock.expect(storageRpcMock.open(SIGNED_URL)).andReturn("upload-id"); EasyMock.replay(storageRpcMock); initializeService(); - WriteChannel writer = new BlobWriteChannel(options, new URL(SIGN_URL)); + WriteChannel writer = new BlobWriteChannel(options, new URL(SIGNED_URL)); assertNotNull(writer); assertTrue(writer.isOpen()); } diff --git a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java index 919fc5030e71..50aaa74b159e 100644 --- a/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java +++ b/google-cloud-clients/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java @@ -2544,7 +2544,7 @@ public void testEnableAndDisableBucketPolicyOnlyOnExistingBucket() throws Except } @Test - public void testUploadUsingSignURL() throws Exception { + public void testUploadUsingSignedURL() throws Exception { String blobName = "test-signed-url-upload"; BlobInfo blob = BlobInfo.newBuilder(BUCKET, blobName).build(); assertNotNull(storage.create(blob)); From d3fbff7a455e843fe028650070b1ce52e4236d8c Mon Sep 17 00:00:00 2001 From: abhinav Date: Mon, 8 Apr 2019 14:25:54 +0530 Subject: [PATCH 10/14] signedURL validation with googleacessid and expires field also. --- .../java/com/google/cloud/storage/BlobWriteChannel.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java index 5b5507070cd2..563bc9855be8 100644 --- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java +++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java @@ -99,10 +99,9 @@ private static String open(final URL signedURL, final StorageOptions options) { @Override public String call() { String signedURLQuery = signedURL.getQuery(); - if (null != signedURLQuery - && signedURLQuery.startsWith("GoogleAccessId=") - && signedURLQuery.contains("&Expires=") - && !signedURL.getQuery().contains("&Signature=")) { + if (!signedURLQuery.startsWith("GoogleAccessId=") + || !signedURLQuery.contains("&Expires=") + || !signedURL.getQuery().contains("&Signature=")) { throw new StorageException(2, "invalid signedURL"); } return options.getStorageRpcV1().open(signedURL.toString()); From 9c0d0e4bbc18c76edfd9249f79a5d513eefb66d2 Mon Sep 17 00:00:00 2001 From: abhinav Date: Tue, 9 Apr 2019 12:56:19 +0530 Subject: [PATCH 11/14] fix forsignedURL validation with V4 Signing support. --- .../cloud/storage/BlobWriteChannel.java | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java index 563bc9855be8..ec5376697ce3 100644 --- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java +++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java @@ -98,10 +98,7 @@ private static String open(final URL signedURL, final StorageOptions options) { new Callable() { @Override public String call() { - String signedURLQuery = signedURL.getQuery(); - if (!signedURLQuery.startsWith("GoogleAccessId=") - || !signedURLQuery.contains("&Expires=") - || !signedURL.getQuery().contains("&Signature=")) { + if (!isValidSignedURL(signedURL.getQuery())) { throw new StorageException(2, "invalid signedURL"); } return options.getStorageRpcV1().open(signedURL.toString()); @@ -115,6 +112,26 @@ public String call() { } } + private static boolean isValidSignedURL(String signedURLQuery) { + boolean isValid = true; + if (signedURLQuery.startsWith("X-Goog-Algorithm=")) { + if (!signedURLQuery.contains("&X-Goog-Credential=") + || !signedURLQuery.contains("&X-Goog-Date=") + || !signedURLQuery.contains("&X-Goog-Expires=") + || !signedURLQuery.contains("&X-Goog-SignedHeaders=") + || !signedURLQuery.contains("&X-Goog-Signature=")) { + isValid = false; + } + } else if (signedURLQuery.startsWith("GoogleAccessId=")) { + if (!signedURLQuery.contains("&Expires=") || !signedURLQuery.contains("&Signature=")) { + isValid = false; + } + } else { + isValid = false; + } + return isValid; + } + static class StateImpl extends BaseWriteChannel.BaseState { private static final long serialVersionUID = -9028324143780151286L; From 0ee885e02ab92b3e463e72599b0f5bd6027daa5e Mon Sep 17 00:00:00 2001 From: abhinav Date: Thu, 11 Apr 2019 12:13:48 +0530 Subject: [PATCH 12/14] fix forproviding example of writing content using signedURL through Writer. --- .../java/com/google/cloud/storage/Storage.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java index 751e3e900bfe..dd1436233b73 100644 --- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java +++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java @@ -2069,7 +2069,21 @@ Blob create( WriteChannel writer(BlobInfo blobInfo, BlobWriteOption... options); /** - * accept signURL and return a channel for writing content. + * Accepts signed URL and return a channel for writing content. + * + *

Example of writing content through a writer using signed URL. + * + *

{@code
+   * String bucketName = "my_unique_bucket";
+   * String blobName = "my_blob_name";
+   * BlobId blobId = BlobId.of(bucketName, blobName);
+   * byte[] content = "Hello, World!".getBytes(UTF_8);
+   * BlobInfo blobInfo = BlobInfo.newBuilder(blobId).setContentType("text/plain").build();
+   * URL signedURL = storage.signUrl(blobInfo, 1, TimeUnit.HOURS, Storage.SignUrlOption.httpMethod(HttpMethod.POST));
+   * try (WriteChannel writer = storage.writer(signedURL)) {
+   *    writer.write(ByteBuffer.wrap(content, 0, content.length));
+   * }
+   * }
* * @throws StorageException upon failure */ From 28464d1d033d9c9cb070e442e358c53efc2b9c99 Mon Sep 17 00:00:00 2001 From: abhinav Date: Fri, 12 Apr 2019 11:19:51 +0530 Subject: [PATCH 13/14] fix forStorageRpc open method argument change. --- .../main/java/com/google/cloud/storage/spi/v1/StorageRpc.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java index cf1ae3e2a274..7d978a9e2e16 100644 --- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java +++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java @@ -294,7 +294,7 @@ StorageObject compose( * * @throws StorageException upon failure */ - String open(String signURL); + String open(String signedURL); /** * Writes the provided bytes to a storage object at the provided location. From 0b9be72efe7261abc07be0a69c8893ea4704c345 Mon Sep 17 00:00:00 2001 From: abhinav Date: Fri, 12 Apr 2019 12:15:07 +0530 Subject: [PATCH 14/14] fix forStorageRpc open method doc comment changes. --- .../main/java/com/google/cloud/storage/spi/v1/StorageRpc.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java index 7d978a9e2e16..c85958176d69 100644 --- a/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java +++ b/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java @@ -290,7 +290,7 @@ StorageObject compose( String open(StorageObject object, Map options); /** - * Opens a resumable upload channel for a given signUrl. + * Opens a resumable upload channel for a given signedURL. * * @throws StorageException upon failure */