9
9
import zlib
10
10
11
11
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
+
12
51
class HTTP20Response (object ):
13
52
"""
14
53
An ``HTTP20Response`` wraps the HTTP/2.0 response from the server. It
@@ -45,7 +84,12 @@ def __init__(self, headers, stream):
45
84
# This 16 + MAX_WBITS nonsense is to force gzip. See this
46
85
# Stack Overflow answer for more:
47
86
# 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
49
93
50
94
def read (self , amt = None , decode_content = True ):
51
95
"""
@@ -66,11 +110,12 @@ def read(self, amt=None, decode_content=True):
66
110
flush_buffer = True
67
111
68
112
# 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 :
70
114
data = self ._decompressobj .decompress (data )
71
115
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 ()
74
119
75
120
return data
76
121
0 commit comments