diff --git a/library/src/main/java/com/readystatesoftware/chuck/ChuckInterceptor.java b/library/src/main/java/com/readystatesoftware/chuck/ChuckInterceptor.java index 2712ad72..f0f973bf 100644 --- a/library/src/main/java/com/readystatesoftware/chuck/ChuckInterceptor.java +++ b/library/src/main/java/com/readystatesoftware/chuck/ChuckInterceptor.java @@ -18,6 +18,7 @@ import android.content.ContentValues; import android.content.Context; import android.net.Uri; +import android.util.Log; import com.readystatesoftware.chuck.internal.data.ChuckContentProvider; import com.readystatesoftware.chuck.internal.data.HttpTransaction; @@ -42,6 +43,8 @@ import okhttp3.internal.http.HttpHeaders; import okio.Buffer; import okio.BufferedSource; +import okio.GzipSource; +import okio.Okio; /** * An OkHttp Interceptor which persists and displays HTTP activity in your application for later inspection. @@ -67,6 +70,7 @@ public enum Period { FOREVER } + private static final String LOG_TAG = "ChuckInterceptor"; private static final Period DEFAULT_RETENTION = Period.ONE_WEEK; private static final Charset UTF8 = Charset.forName("UTF-8"); @@ -143,9 +147,10 @@ public ChuckInterceptor retainDataFor(Period period) { } } - transaction.setRequestBodyIsPlainText(!bodyEncoded(request.headers())); + transaction.setRequestBodyIsPlainText(!bodyHasUnsupportedEncoding(request.headers())); if (hasRequestBody && transaction.requestBodyIsPlainText()) { - Buffer buffer = new Buffer(); + BufferedSource source = getNativeSource(new Buffer(), bodyGzipped(request.headers())); + Buffer buffer = source.buffer(); requestBody.writeTo(buffer); Charset charset = UTF8; MediaType contentType = requestBody.contentType(); @@ -187,9 +192,9 @@ public ChuckInterceptor retainDataFor(Period period) { } transaction.setResponseHeaders(response.headers()); - transaction.setResponseBodyIsPlainText(!bodyEncoded(response.headers())); + transaction.setResponseBodyIsPlainText(!bodyHasUnsupportedEncoding(response.headers())); if (HttpHeaders.hasBody(response) && transaction.responseBodyIsPlainText()) { - BufferedSource source = responseBody.source(); + BufferedSource source = getNativeSource(response); source.request(Long.MAX_VALUE); Buffer buffer = source.buffer(); Charset charset = UTF8; @@ -259,9 +264,16 @@ private boolean isPlaintext(Buffer buffer) { } } - private boolean bodyEncoded(Headers headers) { + private boolean bodyHasUnsupportedEncoding(Headers headers) { + String contentEncoding = headers.get("Content-Encoding"); + return contentEncoding != null && + !contentEncoding.equalsIgnoreCase("identity") && + !contentEncoding.equalsIgnoreCase("gzip"); + } + + private boolean bodyGzipped(Headers headers) { String contentEncoding = headers.get("Content-Encoding"); - return contentEncoding != null && !contentEncoding.equalsIgnoreCase("identity"); + return "gzip".equalsIgnoreCase(contentEncoding); } private String readFromBuffer(Buffer buffer, Charset charset) { @@ -278,4 +290,25 @@ private String readFromBuffer(Buffer buffer, Charset charset) { } return body; } + + private BufferedSource getNativeSource(BufferedSource input, boolean isGzipped) { + if (isGzipped) { + GzipSource source = new GzipSource(input); + return Okio.buffer(source); + } else { + return input; + } + } + + private BufferedSource getNativeSource(Response response) throws IOException { + if (bodyGzipped(response.headers())) { + BufferedSource source = response.peekBody(maxContentLength).source(); + if (source.buffer().size() < maxContentLength) { + return getNativeSource(source, true); + } else { + Log.w(LOG_TAG, "gzip encoded response was too long"); + } + } + return response.body().source(); + } } diff --git a/sample/src/main/java/com/readystatesoftware/chuck/sample/MainActivity.java b/sample/src/main/java/com/readystatesoftware/chuck/sample/MainActivity.java index 5576c430..7e29e5bd 100644 --- a/sample/src/main/java/com/readystatesoftware/chuck/sample/MainActivity.java +++ b/sample/src/main/java/com/readystatesoftware/chuck/sample/MainActivity.java @@ -66,7 +66,7 @@ private void doHttpActivity() { SampleApiService.HttpbinApi api = SampleApiService.getInstance(getClient(this)); Callback cb = new Callback() { @Override public void onResponse(Call call, Response response) {} - @Override public void onFailure(Call call, Throwable t) {} + @Override public void onFailure(Call call, Throwable t) { t.printStackTrace(); } }; api.get().enqueue(cb); api.post(new SampleApiService.Data("posted")).enqueue(cb);