Skip to content

Commit e70387d

Browse files
committed
Merge pull request #725 from aozarov/master
Fix writes with 0 length
2 parents d3224b3 + 36ebabd commit e70387d

File tree

4 files changed

+59
-11
lines changed

4 files changed

+59
-11
lines changed

gcloud-java-core/src/main/java/com/google/gcloud/BaseServiceException.java

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,17 @@ public BaseServiceException(IOException exception, boolean idempotent) {
9797
String debugInfo = null;
9898
if (exception instanceof GoogleJsonResponseException) {
9999
GoogleJsonError jsonError = ((GoogleJsonResponseException) exception).getDetails();
100-
Error error = error(jsonError);
101-
code = error.code;
102-
reason = error.reason;
103-
if (reason != null) {
104-
GoogleJsonError.ErrorInfo errorInfo = jsonError.getErrors().get(0);
105-
location = errorInfo.getLocation();
106-
debugInfo = (String) errorInfo.get("debugInfo");
100+
if (jsonError != null) {
101+
Error error = error(jsonError);
102+
code = error.code;
103+
reason = error.reason;
104+
if (reason != null) {
105+
GoogleJsonError.ErrorInfo errorInfo = jsonError.getErrors().get(0);
106+
location = errorInfo.getLocation();
107+
debugInfo = (String) errorInfo.get("debugInfo");
108+
}
109+
} else {
110+
code = ((GoogleJsonResponseException) exception).getStatusCode();
107111
}
108112
}
109113
this.code = code;
@@ -207,7 +211,10 @@ protected static Error error(GoogleJsonError error) {
207211

208212
protected static String message(IOException exception) {
209213
if (exception instanceof GoogleJsonResponseException) {
210-
return ((GoogleJsonResponseException) exception).getDetails().getMessage();
214+
GoogleJsonError details = ((GoogleJsonResponseException) exception).getDetails();
215+
if (details != null) {
216+
return details.getMessage();
217+
}
211218
}
212219
return exception.getMessage();
213220
}

gcloud-java-storage/src/main/java/com/google/gcloud/spi/DefaultStorageRpc.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import static com.google.gcloud.spi.StorageRpc.Option.PREFIX;
3232
import static com.google.gcloud.spi.StorageRpc.Option.VERSIONS;
3333
import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
34+
import static javax.servlet.http.HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE;
3435

3536
import com.google.api.client.googleapis.batch.json.JsonBatchCallback;
3637
import com.google.api.client.googleapis.json.GoogleJsonError;
@@ -453,20 +454,32 @@ public Tuple<String, byte[]> read(StorageObject from, Map<Option, ?> options, lo
453454
String etag = req.getLastResponseHeaders().getETag();
454455
return Tuple.of(etag, output.toByteArray());
455456
} catch (IOException ex) {
456-
throw translate(ex);
457+
StorageException serviceException = translate(ex);
458+
if (serviceException.code() == SC_REQUESTED_RANGE_NOT_SATISFIABLE) {
459+
return Tuple.of(null, new byte[0]);
460+
}
461+
throw serviceException;
457462
}
458463
}
459464

460465
@Override
461466
public void write(String uploadId, byte[] toWrite, int toWriteOffset, long destOffset, int length,
462467
boolean last) {
463468
try {
469+
if (length == 0 && !last) {
470+
return;
471+
}
464472
GenericUrl url = new GenericUrl(uploadId);
465473
HttpRequest httpRequest = storage.getRequestFactory().buildPutRequest(url,
466474
new ByteArrayContent(null, toWrite, toWriteOffset, length));
467475
long limit = destOffset + length;
468476
StringBuilder range = new StringBuilder("bytes ");
469-
range.append(destOffset).append('-').append(limit - 1).append('/');
477+
if (length == 0) {
478+
range.append('*');
479+
} else {
480+
range.append(destOffset).append('-').append(limit - 1);
481+
}
482+
range.append('/');
470483
if (last) {
471484
range.append(limit);
472485
} else {

gcloud-java-storage/src/main/java/com/google/gcloud/storage/BlobReadChannel.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ public Tuple<String, byte[]> call() {
127127
return storageRpc.read(storageObject, requestOptions, position, toRead);
128128
}
129129
}, serviceOptions.retryParams(), StorageImpl.EXCEPTION_HANDLER);
130-
if (lastEtag != null && !Objects.equals(result.x(), lastEtag)) {
130+
if (result.y().length > 0 && lastEtag != null && !Objects.equals(result.x(), lastEtag)) {
131131
StringBuilder messageBuilder = new StringBuilder();
132132
messageBuilder.append("Blob ").append(blob).append(" was updated while reading");
133133
throw new StorageException(0, messageBuilder.toString());

gcloud-java-storage/src/test/java/com/google/gcloud/storage/it/ITStorageTest.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import org.junit.Test;
5555

5656
import java.io.ByteArrayInputStream;
57+
import java.io.ByteArrayOutputStream;
5758
import java.io.IOException;
5859
import java.io.InputStream;
5960
import java.net.URL;
@@ -823,6 +824,33 @@ public void testReadAndWriteChannels() throws IOException {
823824
assertTrue(storage.delete(BUCKET, blobName));
824825
}
825826

827+
@Test
828+
public void testReadAndWriteChannelsWithDifferentFileSize() throws IOException {
829+
String blobNamePrefix = "test-read-and-write-channels-blob-";
830+
int[] blobSizes = {0, 700, 1024 * 256, 2 * 1024 * 1024, 4 * 1024 * 1024, 4 * 1024 * 1024 + 1};
831+
Random rnd = new Random();
832+
for (int blobSize : blobSizes) {
833+
String blobName = blobNamePrefix + blobSize;
834+
BlobInfo blob = BlobInfo.builder(BUCKET, blobName).build();
835+
byte[] bytes = new byte[blobSize];
836+
rnd.nextBytes(bytes);
837+
try (WriteChannel writer = storage.writer(blob)) {
838+
writer.write(ByteBuffer.wrap(bytes));
839+
}
840+
ByteArrayOutputStream output = new ByteArrayOutputStream();
841+
try (ReadChannel reader = storage.reader(blob.blobId())) {
842+
ByteBuffer buffer = ByteBuffer.allocate(64 * 1024);
843+
while (reader.read(buffer) > 0) {
844+
buffer.flip();
845+
output.write(buffer.array(), 0, buffer.limit());
846+
buffer.clear();
847+
}
848+
}
849+
assertArrayEquals(bytes, output.toByteArray());
850+
assertTrue(storage.delete(BUCKET, blobName));
851+
}
852+
}
853+
826854
@Test
827855
public void testReadAndWriteCaptureChannels() throws IOException {
828856
String blobName = "test-read-and-write-capture-channels-blob";

0 commit comments

Comments
 (0)