mirror of
https://github.com/square/okhttp.git
synced 2025-08-08 23:42:08 +03:00
Log gzipped bodies when HttpLoggingInterceptor is used as a NetworkInterceptor (#3792)
* (in-progress) Support gzipped bodies as a networkInterceptor * Fixed buffer cloning, added test for a still-unsupported encoding (Brotli) * Avoid try-with-resources and too-long lines to appease build checks * Fixed method name typo * Added suggested comma between byte and gzipped-byte count * Account for added comma in test * Use buffer.writeAll to ensure all body content is read * Indentation consistency * Added test to confirm response body remains valid
This commit is contained in:
committed by
Jesse Wilson
parent
17b5dbbe14
commit
bb304b9c2c
@@ -32,6 +32,7 @@ import okhttp3.internal.http.HttpHeaders;
|
|||||||
import okhttp3.internal.platform.Platform;
|
import okhttp3.internal.platform.Platform;
|
||||||
import okio.Buffer;
|
import okio.Buffer;
|
||||||
import okio.BufferedSource;
|
import okio.BufferedSource;
|
||||||
|
import okio.GzipSource;
|
||||||
|
|
||||||
import static okhttp3.internal.platform.Platform.INFO;
|
import static okhttp3.internal.platform.Platform.INFO;
|
||||||
|
|
||||||
@@ -182,7 +183,7 @@ public final class HttpLoggingInterceptor implements Interceptor {
|
|||||||
|
|
||||||
if (!logBody || !hasRequestBody) {
|
if (!logBody || !hasRequestBody) {
|
||||||
logger.log("--> END " + request.method());
|
logger.log("--> END " + request.method());
|
||||||
} else if (bodyEncoded(request.headers())) {
|
} else if (bodyHasUnknownEncoding(request.headers())) {
|
||||||
logger.log("--> END " + request.method() + " (encoded body omitted)");
|
logger.log("--> END " + request.method() + " (encoded body omitted)");
|
||||||
} else {
|
} else {
|
||||||
Buffer buffer = new Buffer();
|
Buffer buffer = new Buffer();
|
||||||
@@ -233,13 +234,28 @@ public final class HttpLoggingInterceptor implements Interceptor {
|
|||||||
|
|
||||||
if (!logBody || !HttpHeaders.hasBody(response)) {
|
if (!logBody || !HttpHeaders.hasBody(response)) {
|
||||||
logger.log("<-- END HTTP");
|
logger.log("<-- END HTTP");
|
||||||
} else if (bodyEncoded(response.headers())) {
|
} else if (bodyHasUnknownEncoding(response.headers())) {
|
||||||
logger.log("<-- END HTTP (encoded body omitted)");
|
logger.log("<-- END HTTP (encoded body omitted)");
|
||||||
} else {
|
} else {
|
||||||
BufferedSource source = responseBody.source();
|
BufferedSource source = responseBody.source();
|
||||||
source.request(Long.MAX_VALUE); // Buffer the entire body.
|
source.request(Long.MAX_VALUE); // Buffer the entire body.
|
||||||
Buffer buffer = source.buffer();
|
Buffer buffer = source.buffer();
|
||||||
|
|
||||||
|
Long gzippedLength = null;
|
||||||
|
if ("gzip".equalsIgnoreCase(headers.get("Content-Encoding"))) {
|
||||||
|
gzippedLength = buffer.size();
|
||||||
|
GzipSource gzippedResponseBody = null;
|
||||||
|
try {
|
||||||
|
gzippedResponseBody = new GzipSource(buffer.clone());
|
||||||
|
buffer = new Buffer();
|
||||||
|
buffer.writeAll(gzippedResponseBody);
|
||||||
|
} finally {
|
||||||
|
if (gzippedResponseBody != null) {
|
||||||
|
gzippedResponseBody.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Charset charset = UTF8;
|
Charset charset = UTF8;
|
||||||
MediaType contentType = responseBody.contentType();
|
MediaType contentType = responseBody.contentType();
|
||||||
if (contentType != null) {
|
if (contentType != null) {
|
||||||
@@ -257,7 +273,12 @@ public final class HttpLoggingInterceptor implements Interceptor {
|
|||||||
logger.log(buffer.clone().readString(charset));
|
logger.log(buffer.clone().readString(charset));
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.log("<-- END HTTP (" + buffer.size() + "-byte body)");
|
if (gzippedLength != null) {
|
||||||
|
logger.log("<-- END HTTP (" + buffer.size() + "-byte, "
|
||||||
|
+ gzippedLength + "-gzipped-byte body)");
|
||||||
|
} else {
|
||||||
|
logger.log("<-- END HTTP (" + buffer.size() + "-byte body)");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,8 +309,10 @@ public final class HttpLoggingInterceptor implements Interceptor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean bodyEncoded(Headers headers) {
|
private boolean bodyHasUnknownEncoding(Headers headers) {
|
||||||
String contentEncoding = headers.get("Content-Encoding");
|
String contentEncoding = headers.get("Content-Encoding");
|
||||||
return contentEncoding != null && !contentEncoding.equalsIgnoreCase("identity");
|
return contentEncoding != null
|
||||||
|
&& !contentEncoding.equalsIgnoreCase("identity")
|
||||||
|
&& !contentEncoding.equalsIgnoreCase("gzip");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -31,6 +31,7 @@ import okhttp3.RecordingHostnameVerifier;
|
|||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
import okhttp3.RequestBody;
|
import okhttp3.RequestBody;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
|
import okhttp3.ResponseBody;
|
||||||
import okhttp3.internal.tls.SslClient;
|
import okhttp3.internal.tls.SslClient;
|
||||||
import okhttp3.logging.HttpLoggingInterceptor.Level;
|
import okhttp3.logging.HttpLoggingInterceptor.Level;
|
||||||
import okhttp3.mockwebserver.MockResponse;
|
import okhttp3.mockwebserver.MockResponse;
|
||||||
@@ -532,7 +533,7 @@ public final class HttpLoggingInterceptorTest {
|
|||||||
.assertNoMoreLogs();
|
.assertNoMoreLogs();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test public void bodyResponseNotIdentityEncoded() throws IOException {
|
@Test public void bodyResponseGzipEncoded() throws IOException {
|
||||||
setLevel(Level.BODY);
|
setLevel(Level.BODY);
|
||||||
|
|
||||||
server.enqueue(new MockResponse()
|
server.enqueue(new MockResponse()
|
||||||
@@ -541,7 +542,10 @@ public final class HttpLoggingInterceptorTest {
|
|||||||
.setBody(new Buffer().write(ByteString.decodeBase64(
|
.setBody(new Buffer().write(ByteString.decodeBase64(
|
||||||
"H4sIAAAAAAAAAPNIzcnJ11HwQKIAdyO+9hMAAAA="))));
|
"H4sIAAAAAAAAAPNIzcnJ11HwQKIAdyO+9hMAAAA="))));
|
||||||
Response response = client.newCall(request().build()).execute();
|
Response response = client.newCall(request().build()).execute();
|
||||||
response.body().close();
|
|
||||||
|
ResponseBody responseBody = response.body();
|
||||||
|
assertEquals("Expected response body to be valid","Hello, Hello, Hello", responseBody.string());
|
||||||
|
responseBody.close();
|
||||||
|
|
||||||
networkLogs
|
networkLogs
|
||||||
.assertLogEqual("--> GET " + url + " http/1.1")
|
.assertLogEqual("--> GET " + url + " http/1.1")
|
||||||
@@ -554,7 +558,9 @@ public final class HttpLoggingInterceptorTest {
|
|||||||
.assertLogEqual("Content-Encoding: gzip")
|
.assertLogEqual("Content-Encoding: gzip")
|
||||||
.assertLogEqual("Content-Type: text/plain; charset=utf-8")
|
.assertLogEqual("Content-Type: text/plain; charset=utf-8")
|
||||||
.assertLogMatch("Content-Length: \\d+")
|
.assertLogMatch("Content-Length: \\d+")
|
||||||
.assertLogEqual("<-- END HTTP (encoded body omitted)")
|
.assertLogEqual("")
|
||||||
|
.assertLogEqual("Hello, Hello, Hello")
|
||||||
|
.assertLogEqual("<-- END HTTP (19-byte, 29-gzipped-byte body)")
|
||||||
.assertNoMoreLogs();
|
.assertNoMoreLogs();
|
||||||
|
|
||||||
applicationLogs
|
applicationLogs
|
||||||
@@ -568,6 +574,43 @@ public final class HttpLoggingInterceptorTest {
|
|||||||
.assertNoMoreLogs();
|
.assertNoMoreLogs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test public void bodyResponseUnknownEncoded() throws IOException {
|
||||||
|
setLevel(Level.BODY);
|
||||||
|
|
||||||
|
server.enqueue(new MockResponse()
|
||||||
|
// It's invalid to return this if not requested, but the server might anyway
|
||||||
|
.setHeader("Content-Encoding", "br")
|
||||||
|
.setHeader("Content-Type", PLAIN)
|
||||||
|
.setBody(new Buffer().write(ByteString.decodeBase64(
|
||||||
|
"iwmASGVsbG8sIEhlbGxvLCBIZWxsbwoD"))));
|
||||||
|
Response response = client.newCall(request().build()).execute();
|
||||||
|
response.body().close();
|
||||||
|
|
||||||
|
networkLogs
|
||||||
|
.assertLogEqual("--> GET " + url + " http/1.1")
|
||||||
|
.assertLogEqual("Host: " + host)
|
||||||
|
.assertLogEqual("Connection: Keep-Alive")
|
||||||
|
.assertLogEqual("Accept-Encoding: gzip")
|
||||||
|
.assertLogMatch("User-Agent: okhttp/.+")
|
||||||
|
.assertLogEqual("--> END GET")
|
||||||
|
.assertLogMatch("<-- 200 OK " + url + " \\(\\d+ms\\)")
|
||||||
|
.assertLogEqual("Content-Encoding: br")
|
||||||
|
.assertLogEqual("Content-Type: text/plain; charset=utf-8")
|
||||||
|
.assertLogMatch("Content-Length: \\d+")
|
||||||
|
.assertLogEqual("<-- END HTTP (encoded body omitted)")
|
||||||
|
.assertNoMoreLogs();
|
||||||
|
|
||||||
|
applicationLogs
|
||||||
|
.assertLogEqual("--> GET " + url)
|
||||||
|
.assertLogEqual("--> END GET")
|
||||||
|
.assertLogMatch("<-- 200 OK " + url + " \\(\\d+ms\\)")
|
||||||
|
.assertLogEqual("Content-Encoding: br")
|
||||||
|
.assertLogEqual("Content-Type: text/plain; charset=utf-8")
|
||||||
|
.assertLogMatch("Content-Length: \\d+")
|
||||||
|
.assertLogEqual("<-- END HTTP (encoded body omitted)")
|
||||||
|
.assertNoMoreLogs();
|
||||||
|
}
|
||||||
|
|
||||||
@Test public void bodyGetMalformedCharset() throws IOException {
|
@Test public void bodyGetMalformedCharset() throws IOException {
|
||||||
setLevel(Level.BODY);
|
setLevel(Level.BODY);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user