retrofit + okhttp : Retrieve GZIPInputStream-open source projects square/okhttp

After running into a similar issue (in my case, without adding any Accept-Encoding header, it would occasionally fail to un-gzip the response, leaving also the Content-Encoding: gzip header in it, crashing the JSON parser), and with no clear way around this, I manually enabled gzip for Retrofit by creating the delegated Client implementation below. It works great, except that you probably should not use it for very large (e.g. > 250KB) responses, as they are first copied into a byte array.

public class GzippedClient implements Client {

    private Client wrappedClient;

    public GzippedClient(Client wrappedClient) {
        this.wrappedClient = wrappedClient;
    }

    @Override
    public Response execute(Request request) throws IOException {
        Response response = wrappedClient.execute(request);

        boolean gzipped = false;
        for (Header h : response.getHeaders()) {
            if (h.getName() != null && h.getName().toLowerCase().equals("content-encoding") && h.getValue() != null && h.getValue().toLowerCase().equals("gzip")) {
                gzipped = true;
                break;
            }
        }

        Response r = null;
        if (gzipped) {
            InputStream is = null;
            ByteArrayOutputStream bos = null;

            try {
                is = new BufferedInputStream(new GZIPInputStream(response.getBody().in()));
                bos = new ByteArrayOutputStream();

                int b;
                while ((b = is.read()) != -1) {
                    bos.write(b);
                }

                TypedByteArray body = new TypedByteArray(response.getBody().mimeType(), bos.toByteArray());
                r = new Response(response.getUrl(), response.getStatus(), response.getReason(), response.getHeaders(), body);
            } finally {
                if (is != null) {
                    is.close();
                }
                if (bos != null) {
                    bos.close();
                }
            }
        } else {
            r = response;
        }
        return r;
    }

}

You will also have to add an Accept-Encoding header to your requests, e.g. by using a RequestInterceptor

requestFacade.addHeader("Accept-Encoding", "gzip");

Finally, you have to wrap your existing Client into this new GzippedClient, like so:

restBuilder.setClient(new GzippedClient(new OkClient(okHttpClient)));

That’s it. Now your data will be gzipped.

EDIT: It seems that in OkHttp version 1.5.1, a bug (https://github.com/square/okhttp/pull/632) seems to have been fixed related to the transparent gzipping which may (or may not) have been the source of my initial issue. If so, the occasional failure to un-gzip may no longer occur, though it happened rarely enough that I cannot confirm this yet. Either way, if you want to rely on your own, rather than the transparent adding/removing of headers and gzipping, then the solution described will work.