8000 Fix: Use BufferedInputStream to inspect HttpResponse error (#1411) · rohitvvv/google-http-java-client@33acb86 · GitHub
[go: up one dir, main page]

Skip to content

Commit 33acb86

Browse files
author
Konstantin Lyamshin
authored
Fix: Use BufferedInputStream to inspect HttpResponse error (googleapis#1411)
* Fix: Use BufferedInputStream to inspect HttpResponse error
1 parent 08e6cb4 commit 33acb86

File tree

2 files changed

+86
-2
lines changed

2 files changed

+86
-2
lines changed

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.google.api.client.util.LoggingInputStream;
1919
import com.google.api.client.util.Preconditions;
2020
import com.google.api.client.util.StringUtils;
21+
import java.io.BufferedInputStream;
2122
import java.io.ByteArrayOutputStream;
2223
import java.io.EOFException;
2324
import java.io.IOException;
@@ -371,7 +372,13 @@ public InputStream getContent() throws IOException {
371372
new LoggingInputStream(
372373
lowLevelResponseContent, logger, Level.CONFIG, contentLoggingLimit);
373374
}
374-
content = lowLevelResponseContent;
375+
if (returnRawInputStream) {
376+
content = lowLevelResponseContent;
377+
} else {
378+
// wrap the content with BufferedInputStream to support
379+
// mark()/reset() while error checking in error handlers
380+
content = new BufferedInputStream(lowLevelResponseContent);
381+
}
375382
contentProcessed = true;
376383
} catch (EOFException e) {
377384
// this may happen for example on a HEAD request since there no actual response data read

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

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,13 @@
2222
import com.google.api.client.testing.util.LogRecordingHandler;
2323
import com.google.api.client.testing.util.TestableByteArrayInputStream;
2424
import com.google.api.client.util.Key;
25+
import com.google.common.io.ByteStreams;
26+
import java.io.BufferedInputStream;
2527
import java.io.ByteArrayInputStream;
2628
import java.io.ByteArrayOutputStream;
29+
import java.io.FilterInputStream;
2730
import java.io.IOException;
31+
import java.io.InputStream;
2832
import java.lang.reflect.Type;
2933
import java.nio.charset.StandardCharsets;
3034
import java.text.NumberFormat;
@@ -59,6 +63,8 @@ public void testParseAsString_none() throws Exception {
5963
private static final String SAMPLE = "123\u05D9\u05e0\u05D9\u05D1";
6064
private static final String SAMPLE2 = "123abc";
6165
private static final String JSON_SAMPLE = "{\"foo\": \"ßar\"}";
66+
private static final String ERROR_SAMPLE =
67+
"{domain:'global',reason:'domainPolicy',message:'msg'}";
6268
private static final String VALID_CONTENT_TYPE = "text/plain";
6369
private static final String VALID_CONTENT_TYPE_WITH_PARAMS =
6470
"application/vnd.com.google.datastore.entity+json; charset=utf-8; version=v1; q=0.9";
@@ -543,7 +549,8 @@ public LowLevelHttpResponse execute() throws IOException {
543549
};
544550
HttpRequest request =
545551
transport.createRequestFactory().buildHeadRequest(HttpTesting.SIMPLE_GENERIC_URL);
546-
request.execute().getContent();
552+
InputStream noContent = request.execute().getContent();
553+
assertNull(noContent);
547554
}
548555

549556
public void testGetContent_gzipEncoding_ReturnRawStream() throws IOException {
@@ -570,6 +577,9 @@ public LowLevelHttpResponse execute() throws IOException {
570577
assertFalse(
571578
"it should not decompress stream",
572579
request.execute().getContent() instanceof GZIPInputStream);
580+
assertFalse(
581+
"it should not buffer stream",
582+
request.execute().getContent() instanceof BufferedInputStream);
573583
}
574584

575585
public void testGetContent_gzipEncoding_finishReading() throws IOException {
@@ -665,4 +675,71 @@ public LowLevelHttpResponse execute() throws IOException {
665675
HttpResponse response = request.execute();
666676
assertEquals("abcd", response.parseAsString());
667677
}
678+
679+
public void testGetContent_bufferedContent() throws IOException {
680+
HttpTransport transport =
681+
new MockHttpTransport() {
682+
@Override
683+
public LowLevelHttpRequest buildRequest(String method, String url) throws IOException {
684+
return new MockLowLevelHttpRequest() {
685+
@Override
686+
public LowLevelHttpResponse execute() throws IOException {
687+
// have to use gzip here because MockLowLevelHttpResponse.setContent()
688+
// returns BufferedStream by itself, so test always success
689+
byte[] dataToCompress = ERROR_SAMPLE.getBytes(StandardCharsets.UTF_8);
690+
ByteArrayOutputStream content = new ByteArrayOutputStream(dataToCompress.length);
691+
try (GZIPOutputStream zipStream = new GZIPOutputStream((content))) {
692+
zipStream.write(dataToCompress);
693+
}
694+
695+
MockLowLevelHttpResponse result = new MockLowLevelHttpResponse();
696+
result.setStatusCode(403);
697+
result.setContentType(JSON_CONTENT_TYPE);
698+
result.setContentEncoding("gzip");
699+
result.setContent(content.toByteArray());
700+
701+
return result;
702+
}
703+
};
704+
}
705+
};
706+
HttpRequest request =
707+
transport
708+
.createRequestFactory()
709+
.buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL)
710+
.setThrowExceptionOnExecuteError(false);
711+
712+
HttpResponse response = request.execute();
713+
InputStream content = response.getContent();
714+
assertTrue(content.markSupported());
715+
716+
// inspect content like in HttpUnsuccessfulResponseHandler
717+
try (RollbackInputStream is = new RollbackInputStream(content)) {
718+
byte[] bytes = ByteStreams.toByteArray(is);
719+
String text = new String(bytes, response.getContentCharset());
720+
assertEquals(ERROR_SAMPLE, text);
721+
}
722+
723+
// original response still parsable by HttpResponseException
724+
HttpResponseException exception = new HttpResponseException(response);
725+
assertEquals(exception.getStatusCode(), 403);
726+
assertEquals(exception.getContent(), ERROR_SAMPLE);
727+
}
728+
729+
static class RollbackInputStream extends FilterInputStream {
730+
private boolean closed;
731+
732+
RollbackInputStream(InputStream in) {
733+
super(in);
734+
in.mark(8192); // big enough to keep most error messages
735+
}
736+
737+
@Override
738+
public void close() throws IOException {
739+
if (!closed) {
740+
closed = true;
741+
in.reset();
742+
}
743+
}
744+
}
668745
}

0 commit comments

Comments
 (0)
0