11package securehttpclient .okhttp ;
22
3+ import java .io .EOFException ;
34import java .io .IOException ;
5+ import java .io .InputStream ;
6+ import java .io .BufferedInputStream ;
47import java .util .zip .Inflater ;
8+ import java .util .zip .InflaterInputStream ;
9+ import java .util .zip .GZIPInputStream ;
10+ import org .brotli .dec .BrotliInputStream ;
511
612import okhttp3 .Headers ;
713import okhttp3 .Interceptor ;
8- import okhttp3 .Request ;
914import okhttp3 .Response ;
1015import okhttp3 .ResponseBody ;
11- import okio .GzipSource ;
12- import okio .InflaterSource ;
13- import okio .Source ;
16+ import okio .BufferedSource ;
1417import okio .Okio ;
1518
16- import org .brotli .dec .BrotliInputStream ;
17-
1819public class DecompressInterceptor implements Interceptor {
1920 @ Override
2021 public Response intercept (Chain chain ) throws IOException {
@@ -33,25 +34,44 @@ private Response decompress(final Response response) throws IOException {
3334 return response ;
3435 }
3536
36- Source source = null ;
37+ BufferedSource source = response .body ().source ();
38+ InputStream inputStream = null ;
39+
3740 switch (response .header ("Content-Encoding" ).toLowerCase ()) {
3841 case "gzip" : {
39- source = new GzipSource ( response . body (). source ());
42+ inputStream = new GZIPInputStream ( source . inputStream ());
4043 break ;
4144 }
4245 case "deflate" : {
43- source = new InflaterSource (response .body ().source (), new Inflater ());
46+ boolean hasZlibHeader = false ;
47+ BufferedInputStream bufferedInputStream = new BufferedInputStream (source .inputStream ());
48+ try {
49+ source .require (2 ); // throws EOFException if size < 2
50+ byte [] headerBytes = new byte [2 ];
51+ bufferedInputStream .mark (0 );
52+ bufferedInputStream .read (headerBytes );
53+ bufferedInputStream .reset ();
54+ hasZlibHeader = (headerBytes [0 ] & 0xFF ) == 0x78 && (headerBytes [1 ] & 0xFF ) <= 0xDA ;
55+ } catch (EOFException e ) {
56+ }
57+ if (hasZlibHeader ) {
58+ // zlib decompression (rfc 1951)
59+ inputStream = new InflaterInputStream (bufferedInputStream , new Inflater ());
60+ } else {
61+ // raw deflate decompression (rfc 1950)
62+ inputStream = new InflaterInputStream (bufferedInputStream , new Inflater (true ));
63+ }
4464 break ;
4565 }
4666 case "br" : {
47- source = Okio . source ( new BrotliInputStream (response . body (). source () .inputStream () ));
67+ inputStream = new BrotliInputStream (source .inputStream ());
4868 break ;
4969 }
5070 }
5171
52- String bodyString = Okio .buffer (source ). readUtf8 ();
53-
54- ResponseBody responseBody = ResponseBody . create ( bodyString , response . body (). contentType () );
72+ byte [] bodyBytes = Okio .buffer (Okio . source ( inputStream )). readByteArray ();
73+ ResponseBody responseBody = ResponseBody . create ( bodyBytes , response . body (). contentType ());
74+ inputStream . close ( );
5575
5676 Headers strippedHeaders = response .headers ().newBuilder ()
5777 .removeAll ("Content-Encoding" )
@@ -65,9 +85,8 @@ private Response decompress(final Response response) throws IOException {
6585 }
6686
6787 private Boolean isCompressed (Response response ) {
68- return response .header ("Content-Encoding" ) != null
69- && (response .header ("Content-Encoding" ).toLowerCase ().equals ("gzip" )
70- || response .header ("Content-Encoding" ).toLowerCase ().equals ("deflate" )
71- || response .header ("Content-Encoding" ).toLowerCase ().equals ("br" ));
88+ String contentEncoding = response .header ("Content-Encoding" );
89+ return contentEncoding != null
90+ && (contentEncoding .equalsIgnoreCase ("gzip" ) || contentEncoding .equalsIgnoreCase ("deflate" ) || contentEncoding .equalsIgnoreCase ("br" ));
7291 }
7392}
0 commit comments