Skip to content

Commit 1ba2197

Browse files
authored
fix: Correctly handling chunked response streams with gzip (#990)
Previous implementation doesn't properly cleanup the last chunk of a chunked response when the response is also gzipped. This in turns prevents proper connection reuse. Fixes #367
1 parent d3c42d3 commit 1ba2197

File tree

2 files changed

+14
-1
lines changed

2 files changed

+14
-1
lines changed

google-http-client/src/main/java/com/google/api/client/http/HttpResponse.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,8 +353,13 @@ public InputStream getContent() throws IOException {
353353
if (!returnRawInputStream && this.contentEncoding != null) {
354354
String oontentencoding = this.contentEncoding.trim().toLowerCase(Locale.ENGLISH);
355355
if (CONTENT_ENCODING_GZIP.equals(oontentencoding) || CONTENT_ENCODING_XGZIP.equals(oontentencoding)) {
356+
// Wrap the original stream in a ConsumingInputStream before passing it to
357+
// GZIPInputStream. The GZIPInputStream leaves content unconsumed in the original
358+
// stream (it almost always leaves the last chunk unconsumed in chunked responses).
359+
// ConsumingInputStream ensures that any unconsumed bytes are read at close.
360+
// GZIPInputStream.close() --> ConsumingInputStream.close() --> exhaust(ConsumingInputStream)
356361
lowLevelResponseContent =
357-
new ConsumingInputStream(new GZIPInputStream(lowLevelResponseContent));
362+
new GZIPInputStream(new ConsumingInputStream(lowLevelResponseContent));
358363
}
359364
}
360365
// logging (wrap content with LoggingInputStream)

google-http-client/src/test/java/com/google/api/client/http/HttpResponseTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,12 @@ private void do_testGetContent_gzipEncoding_finishReading(String contentEncoding
567567
) {
568568
zipStream.write(dataToCompress);
569569
zipStream.close();
570+
571+
// GZIPInputStream uses a default buffer of 512B. Add enough content to exceed this
572+
// limit, so that some content will be left in the connection.
573+
for (int i = 0; i < 1024; i++) {
574+
byteStream.write('7');
575+
}
570576
mockBytes = byteStream.toByteArray();
571577
}
572578
final MockLowLevelHttpResponse mockResponse = new MockLowLevelHttpResponse();
@@ -594,6 +600,8 @@ public LowLevelHttpResponse execute() throws IOException {
594600
assertFalse(output.isClosed());
595601
assertEquals("abcd", response.parseAsString());
596602
assertTrue(output.isClosed());
603+
// The underlying stream should be fully consumed, even if gzip only returns some of it.
604+
assertEquals(-1, output.read());
597605
}
598606
}
599607

0 commit comments

Comments
 (0)