Skip to content

Commit 756987a

Browse files
committed
feat: wrap GZIPInputStream for connection reuse
If a connection is closed and there are some bytes that have not been read that connection can't be reused. Now GZIPInputStream will have all of its bytes read on close automatically to promote connection reuse. Cherry-picked: googleapis#749 Fixes: googleapis#367
1 parent abf01a5 commit 756987a

File tree

4 files changed

+123
-41
lines changed

4 files changed

+123
-41
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright 2019 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.api.client.http;
18+
19+
import com.google.api.client.util.Preconditions;
20+
import com.google.common.io.ByteStreams;
21+
import java.io.IOException;
22+
import java.io.InputStream;
23+
24+
/**
25+
* This class in meant to wrap an {@link InputStream} so that all bytes in the steam are read and
26+
* discarded on {@link InputStream#close()}. This ensures that the underlying connection has the
27+
* option to be reused.
28+
*/
29+
final class ConsumingInputStream extends InputStream {
30+
private InputStream inputStream;
31+
private boolean closed = false;
32+
33+
ConsumingInputStream(InputStream inputStream) {
34+
this.inputStream = Preconditions.checkNotNull(inputStream);
35+
}
36+
37+
@Override
38+
public int read() throws IOException {
39+
return inputStream.read();
40+
}
41+
42+
@Override
43+
public int read(byte[] b, int off, int len) throws IOException {
44+
return inputStream.read(b, off, len);
45+
}
46+
47+
@Override
48+
public void close() throws IOException {
49+
if (!closed && inputStream != null) {
50+
try {
51+
ByteStreams.exhaust(this);
52+
inputStream.close();
53+
} finally {
54+
this.closed = true;
55+
}
56+
}
57+
}
58+
}

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

+2-40
Original file line numberDiff line numberDiff line change
@@ -331,8 +331,8 @@ public InputStream getContent() throws IOException {
331331
if (!returnRawInputStream
332332
&& contentEncoding != null
333333
&& contentEncoding.contains("gzip")) {
334-
lowLevelResponseContent = new ConsumingInputStream(
335-
new GZIPInputStream(lowLevelResponseContent));
334+
lowLevelResponseContent =
335+
new ConsumingInputStream(new GZIPInputStream(lowLevelResponseContent));
336336
}
337337
// logging (wrap content with LoggingInputStream)
338338
Logger logger = HttpTransport.LOGGER;
@@ -357,44 +357,6 @@ public InputStream getContent() throws IOException {
357357
return content;
358358
}
359359

360-
static class ConsumingInputStream extends InputStream {
361-
private InputStream inputStream;
362-
private boolean closed = false;
363-
364-
private ConsumingInputStream(InputStream inputStream) {
365-
this.inputStream = Preconditions.checkNotNull(inputStream);
366-
}
367-
368-
@Override
369-
public int read() throws IOException {
370-
return inputStream.read();
371-
}
372-
373-
@Override
374-
public int read(byte[] b, int off, int len) throws IOException {
375-
return inputStream.read(b, off, len);
376-
}
377-
378-
@Override
379-
public void close() throws IOException {
380-
if (!closed && inputStream != null) {
381-
try {
382-
drainInputStream(this);
383-
inputStream.close();
384-
} finally {
385-
this.closed = true;
386-
}
387-
}
388-
}
389-
390-
static void drainInputStream(final InputStream inputStream) throws IOException {
391-
byte buffer[] = new byte[1024];
392-
while (inputStream.read(buffer) >= 0) {
393-
// do nothing
394-
}
395-
}
396-
}
397-
398360
/**
399361
* Writes the content of the HTTP response into the given destination output stream.
400362
*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2019 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.api.client.http;
18+
19+
import static org.junit.Assert.assertEquals;
20+
21+
import java.io.IOException;
22+
import java.io.InputStream;
23+
import org.junit.Test;
24+
25+
public class ConsumingInputStreamTest {
26+
27+
@Test
28+
public void testClose_drainsBytesOnClose() throws IOException {
29+
MockInputStream mockInputStream = new MockInputStream("abc123".getBytes());
30+
InputStream consumingInputStream = new ConsumingInputStream(mockInputStream);
31+
32+
assertEquals(6, mockInputStream.getBytesToRead());
33+
34+
// read one byte
35+
consumingInputStream.read();
36+
assertEquals(5, mockInputStream.getBytesToRead());
37+
38+
// closing the stream should read the remaining bytes
39+
consumingInputStream.close();
40+
assertEquals(0, mockInputStream.getBytesToRead());
41+
}
42+
43+
private class MockInputStream extends InputStream {
44+
private int bytesToRead;
45+
46+
MockInputStream(byte[] data) {
47+
this.bytesToRead = data.length;
48+
}
49+
50+
@Override
51+
public int read() throws IOException {
52+
if (bytesToRead == 0) {
53+
return -1;
54+
}
55+
bytesToRead--;
56+
return 1;
57+
}
58+
59+
int getBytesToRead() {
60+
return bytesToRead;
61+
}
62+
}
63+
}

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

-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import java.util.zip.GZIPInputStream;
3434
import java.util.zip.GZIPOutputStream;
3535
import junit.framework.TestCase;
36-
import sun.net.www.http.ChunkedInputStream;
3736

3837
/**
3938
* Tests {@link HttpResponse}.

0 commit comments

Comments
 (0)