99import zlib
1010
1111
12+ class DeflateDecoder (object ):
13+ """
14+ This is a decoding object that wraps ``zlib`` and is used for decoding
15+ deflated content.
16+
17+ This rationale for the existence of this object is pretty unpleasant.
18+ The HTTP RFC specifies that 'deflate' is a valid content encoding. However,
19+ the spec _meant_ the zlib encoding form. Unfortunately, people who didn't
20+ read the RFC very carefully actually implemented a different form of
21+ 'deflate'. Insanely, ``zlib`` handles them using two wbits values. This is
22+ such a mess it's hard to adequately articulate.
23+
24+ This class was lovingly borrowed from the excellent urllib3 library. If you
25+ ever see @shazow, you should probably buy him a drink or something.
26+ """
27+ def __init__ (self ):
28+ self ._first_try = True
29+ self ._data = b''
30+ self ._obj = zlib .decompressobj (zlib .MAX_WBITS )
31+
32+ def __getattr__ (self , name ):
33+ return getattr (self ._obj , name )
34+
35+ def decompress (self , data ):
36+ if not self ._first_try :
37+ return self ._obj .decompress (data )
38+
39+ self ._data += data
40+ try :
41+ return self ._obj .decompress (data )
42+ except zlib .error :
43+ self ._first_try = False
44+ self ._obj = zlib .decompressobj (- zlib .MAX_WBITS )
45+ try :
46+ return self .decompress (self ._data )
47+ finally :
48+ self ._data = None
49+
50+
1251class HTTP20Response (object ):
1352 """
1453 An ``HTTP20Response`` wraps the HTTP/2.0 response from the server. It
@@ -45,7 +84,12 @@ def __init__(self, headers, stream):
4584 # This 16 + MAX_WBITS nonsense is to force gzip. See this
4685 # Stack Overflow answer for more:
4786 # http://stackoverflow.com/a/2695466/1401686
48- self ._decompressobj = zlib .decompressobj (16 + zlib .MAX_WBITS )
87+ if self ._headers .get ('content-encoding' , '' ) == 'gzip' :
88+ self ._decompressobj = zlib .decompressobj (16 + zlib .MAX_WBITS )
89+ elif self ._headers .get ('content-encoding' , '' ) == 'deflate' :
90+ self ._decompressobj = DeflateDecoder ()
91+ else :
92+ self ._decompressobj = None
4993
5094 def read (self , amt = None , decode_content = True ):
5195 """
@@ -66,11 +110,12 @@ def read(self, amt=None, decode_content=True):
66110 flush_buffer = True
67111
68112 # We may need to decode the body.
69- if ( decode_content and self .getheader ( 'content-encoding' , False )) :
113+ if decode_content and self ._decompressobj and data :
70114 data = self ._decompressobj .decompress (data )
71115
72- if flush_buffer :
73- data += self ._decompressobj .flush ()
116+ # If we're at the end of the request, flush the buffer.
117+ if decode_content and self ._decompressobj and flush_buffer :
118+ data += self ._decompressobj .flush ()
74119
75120 return data
76121
0 commit comments