Skip to content

Commit 88b8b4a

Browse files
authored
Allow storage.reader to read gzip blobs in compressed chunks (#1301)
1 parent dcee473 commit 88b8b4a

File tree

2 files changed

+55
-1
lines changed

2 files changed

+55
-1
lines changed

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

+22-1
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,11 @@
5151
import com.google.api.client.http.HttpResponseException;
5252
import com.google.api.client.http.HttpTransport;
5353
import com.google.api.client.http.InputStreamContent;
54+
import com.google.api.client.http.LowLevelHttpResponse;
5455
import com.google.api.client.http.json.JsonHttpContent;
5556
import com.google.api.client.json.JsonFactory;
5657
import com.google.api.client.json.jackson.JacksonFactory;
58+
import com.google.api.client.util.IOUtils;
5759
import com.google.api.services.storage.Storage;
5860
import com.google.api.services.storage.Storage.Objects.Get;
5961
import com.google.api.services.storage.Storage.Objects.Insert;
@@ -65,6 +67,7 @@
6567
import com.google.api.services.storage.model.ObjectAccessControl;
6668
import com.google.api.services.storage.model.Objects;
6769
import com.google.api.services.storage.model.StorageObject;
70+
import com.google.cloud.BaseServiceException;
6871
import com.google.cloud.storage.StorageException;
6972
import com.google.cloud.storage.StorageOptions;
7073
import com.google.common.base.Function;
@@ -78,6 +81,7 @@
7881
import java.io.ByteArrayOutputStream;
7982
import java.io.IOException;
8083
import java.io.InputStream;
84+
import java.lang.reflect.Field;
8185
import java.math.BigInteger;
8286
import java.util.ArrayList;
8387
import java.util.LinkedList;
@@ -500,7 +504,24 @@ public Tuple<String, byte[]> read(StorageObject from, Map<Option, ?> options, lo
500504
requestHeaders.setRange(range.toString());
501505
setEncryptionHeaders(requestHeaders, ENCRYPTION_KEY_PREFIX, options);
502506
ByteArrayOutputStream output = new ByteArrayOutputStream(bytes);
503-
req.executeMedia().download(output);
507+
HttpResponse httpResponse = req.executeMedia();
508+
// todo(mziccard) remove when
509+
// https://github.com/GoogleCloudPlatform/google-cloud-java/issues/982 is fixed
510+
String contentEncoding = httpResponse.getContentEncoding();
511+
if (contentEncoding != null && contentEncoding.contains("gzip")) {
512+
try {
513+
Field responseField = httpResponse.getClass().getDeclaredField("response");
514+
responseField.setAccessible(true);
515+
LowLevelHttpResponse lowLevelHttpResponse =
516+
(LowLevelHttpResponse) responseField.get(httpResponse);
517+
IOUtils.copy(lowLevelHttpResponse.getContent(), output);
518+
} catch (IllegalAccessException|NoSuchFieldException ex) {
519+
throw new StorageException(
520+
BaseServiceException.UNKNOWN_CODE, "Error parsing gzip response", ex);
521+
}
522+
} else {
523+
httpResponse.download(output);
524+
}
504525
String etag = req.getLastResponseHeaders().getETag();
505526
return Tuple.of(etag, output.toByteArray());
506527
} catch (IOException ex) {

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

+33
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import com.google.common.collect.Lists;
5454
import com.google.common.collect.Sets;
5555
import com.google.common.io.BaseEncoding;
56+
import com.google.common.io.ByteStreams;
5657

5758
import org.junit.AfterClass;
5859
import org.junit.BeforeClass;
@@ -79,6 +80,7 @@
7980
import java.util.concurrent.TimeUnit;
8081
import java.util.logging.Level;
8182
import java.util.logging.Logger;
83+
import java.util.zip.GZIPInputStream;
8284

8385
import javax.crypto.spec.SecretKeySpec;
8486

@@ -96,6 +98,8 @@ public class ITStorageTest {
9698
private static final String OTHER_BASE64_KEY = "IcOIQGlliNr5pr3vJb63l+XMqc7NjXqjfw/deBoNxPA=";
9799
private static final Key KEY =
98100
new SecretKeySpec(BaseEncoding.base64().decode(BASE64_KEY), "AES256");
101+
private static final byte[] COMPRESSED_CONTENT = BaseEncoding.base64()
102+
.decode("H4sIAAAAAAAAAPNIzcnJV3DPz0/PSVVwzskvTVEILskvSkxPVQQA/LySchsAAAA=");
99103

100104
@BeforeClass
101105
public static void beforeClass() throws NoSuchAlgorithmException, InvalidKeySpecException {
@@ -1381,4 +1385,33 @@ public void testBlobAcl() {
13811385
// expected
13821386
}
13831387
}
1388+
1389+
@Test
1390+
public void testReadCompressedBlob() throws IOException {
1391+
String blobName = "test-read-compressed-blob";
1392+
BlobInfo blobInfo = BlobInfo.builder(BlobId.of(BUCKET, blobName))
1393+
.contentType("text/plain")
1394+
.contentEncoding("gzip")
1395+
.build();
1396+
Blob blob = storage.create(blobInfo, COMPRESSED_CONTENT);
1397+
try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
1398+
try (ReadChannel reader = storage.reader(BlobId.of(BUCKET, blobName))) {
1399+
reader.chunkSize(8);
1400+
ByteBuffer buffer = ByteBuffer.allocate(8);
1401+
while (reader.read(buffer) != -1) {
1402+
buffer.flip();
1403+
output.write(buffer.array(), 0, buffer.limit());
1404+
buffer.clear();
1405+
}
1406+
}
1407+
assertArrayEquals(BLOB_STRING_CONTENT.getBytes(UTF_8),
1408+
storage.readAllBytes(BUCKET, blobName));
1409+
assertArrayEquals(COMPRESSED_CONTENT, output.toByteArray());
1410+
try (GZIPInputStream zipInput =
1411+
new GZIPInputStream(new ByteArrayInputStream(output.toByteArray()))) {
1412+
assertArrayEquals(BLOB_STRING_CONTENT.getBytes(UTF_8), ByteStreams.toByteArray(zipInput));
1413+
}
1414+
}
1415+
blob.delete();
1416+
}
13841417
}

0 commit comments

Comments
 (0)