From a6f47d46ca46c810bbbfeb204201c2147479548a Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Thu, 20 Sep 2018 14:55:08 -0700 Subject: [PATCH] Decode gzip body if not handled by okhttp (#21187) Summary: When looking at enabling gzip content encoding on Android I stumbled on this old issue where the body content is not decoded. It happens because okhttp only handles gzip decoding if the user does NOT provide an accept-encoding header. This is pretty confusing because on iOS we need to pass the header manually if we want to receive a gzipped response. I think it makes sense to handle the decoding no matter what. See the comment in code for more details. Fixed #5297 Pull Request resolved: https://github.com/facebook/react-native/pull/21187 Differential Revision: D9978889 Pulled By: hramos fbshipit-source-id: b86791fb7d3157f325a0904225d2f63d166080d5 --- .../modules/network/NetworkingModule.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java index 249fc18b3..9b335a4d0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java @@ -47,6 +47,8 @@ import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.ResponseBody; import okio.ByteString; +import okio.GzipSource; +import okio.Okio; /** * Implements the XMLHttpRequest JavaScript interface. @@ -454,8 +456,26 @@ public final class NetworkingModule extends ReactContextBaseJavaModule { translateHeaders(response.headers()), response.request().url().toString()); - ResponseBody responseBody = response.body(); try { + // OkHttp implements something called transparent gzip, which mean that it will + // automatically add the Accept-Encoding gzip header and handle decoding internally. + // The issue is that it won't handle decoding if the user provides a Accept-Encoding + // header. This is also undesirable considering that iOS does handle the decoding even + // when the header is provided. To make sure this works in all cases, handle gzip body + // here also. This works fine since OKHttp will remove the Content-Encoding header if + // it used transparent gzip. + // See https://github.com/square/okhttp/blob/5b37cda9e00626f43acf354df145fd452c3031f1/okhttp/src/main/java/okhttp3/internal/http/BridgeInterceptor.java#L76-L111 + ResponseBody responseBody = response.body(); + if ("gzip".equalsIgnoreCase(response.header("Content-Encoding")) && + responseBody != null) { + GzipSource gzipSource = new GzipSource(responseBody.source()); + String contentType = response.header("Content-Type"); + responseBody = ResponseBody.create( + contentType != null ? MediaType.parse(contentType) : null, + -1L, + Okio.buffer(gzipSource)); + } + // Check if a handler is registered for (ResponseHandler handler : mResponseHandlers) { if (handler.supports(responseType)) {