|
6 | 6 |
|
7 | 7 | from .util import CaseInsensitiveDict
|
8 | 8 |
|
| 9 | + |
9 | 10 | try:
|
10 | 11 | # This supports both brotli & brotlipy packages
|
11 | 12 | import brotli
|
|
16 | 17 | brotli = None
|
17 | 18 |
|
18 | 19 |
|
19 |
| -AVAILABLE_DECOMPRESSORS = {"gzip", "deflate"} |
| 20 | + |
| 21 | +def decompress_deflate(body): |
| 22 | + try: |
| 23 | + return zlib.decompress(body) |
| 24 | + except zlib.error: |
| 25 | + # Assume the response was already decompressed |
| 26 | + return body |
| 27 | + |
| 28 | + |
| 29 | +def decompress_gzip(body): |
| 30 | + # To (de-)compress gzip format, use wbits = zlib.MAX_WBITS | 16. |
| 31 | + try: |
| 32 | + return zlib.decompress(body, zlib.MAX_WBITS | 16) |
| 33 | + except zlib.error: |
| 34 | + # Assume the response was already decompressed |
| 35 | + return body |
| 36 | + |
| 37 | +AVAILABLE_DECOMPRESSORS = { |
| 38 | + "deflate": decompress_deflate, |
| 39 | + "gzip": decompress_gzip, |
| 40 | +} |
| 41 | + |
20 | 42 | if brotli is not None:
|
21 |
| - AVAILABLE_DECOMPRESSORS.add("br") |
| 43 | + def decompress_brotli(body): |
| 44 | + try: |
| 45 | + return brotli.decompress(body) |
| 46 | + except brotli.error: |
| 47 | + # Assume the response was already decompressed |
| 48 | + return body |
| 49 | + AVAILABLE_DECOMPRESSORS["br"] = decompress_brotli |
22 | 50 |
|
23 | 51 |
|
24 | 52 | def replace_headers(request, replacements):
|
@@ -157,45 +185,23 @@ def decode_response(response):
|
157 | 185 | 3. update content-length header to decompressed length
|
158 | 186 | """
|
159 | 187 |
|
160 |
| - def is_decompressable(headers): |
161 |
| - encoding = headers.get("content-encoding", []) |
162 |
| - return encoding and encoding[0] in AVAILABLE_DECOMPRESSORS |
163 |
| - |
164 |
| - def decompress_body(body, encoding): |
165 |
| - """Returns decompressed body according to encoding using zlib. |
166 |
| - to (de-)compress gzip format, use wbits = zlib.MAX_WBITS | 16 |
167 |
| - """ |
168 |
| - if not body: |
169 |
| - return "" |
170 |
| - if encoding == "gzip": |
171 |
| - try: |
172 |
| - return zlib.decompress(body, zlib.MAX_WBITS | 16) |
173 |
| - except zlib.error: |
174 |
| - return body # assumes that the data was already decompressed |
175 |
| - elif encoding == 'deflate': |
176 |
| - try: |
177 |
| - return zlib.decompress(body) |
178 |
| - except zlib.error: |
179 |
| - return body # assumes that the data was already decompressed |
180 |
| - else: # encoding == 'br' |
181 |
| - try: |
182 |
| - return brotli.decompress(body) |
183 |
| - except brotli.error: |
184 |
| - return body # assumes that the data was already decompressed |
185 |
| - |
186 |
| - |
187 | 188 | # Deepcopy here in case `headers` contain objects that could
|
188 | 189 | # be mutated by a shallow copy and corrupt the real response.
|
189 | 190 | response = copy.deepcopy(response)
|
190 | 191 | headers = CaseInsensitiveDict(response["headers"])
|
191 |
| - if is_decompressable(headers): |
192 |
| - encoding = headers["content-encoding"][0] |
193 |
| - headers["content-encoding"].remove(encoding) |
194 |
| - if not headers["content-encoding"]: |
195 |
| - del headers["content-encoding"] |
196 |
| - |
197 |
| - new_body = decompress_body(response["body"]["string"], encoding) |
198 |
| - response["body"]["string"] = new_body |
199 |
| - headers["content-length"] = [str(len(new_body))] |
200 |
| - response["headers"] = dict(headers) |
| 192 | + content_encoding = headers.get("content-encoding") |
| 193 | + if not content_encoding: |
| 194 | + return response |
| 195 | + decompressor = AVAILABLE_DECOMPRESSORS.get(content_encoding[0]) |
| 196 | + if not decompressor: |
| 197 | + return response |
| 198 | + |
| 199 | + headers["content-encoding"].remove(content_encoding[0]) |
| 200 | + if not headers["content-encoding"]: |
| 201 | + del headers["content-encoding"] |
| 202 | + |
| 203 | + new_body = decompressor(response["body"]["string"]) |
| 204 | + response["body"]["string"] = new_body |
| 205 | + headers["content-length"] = [str(len(new_body))] |
| 206 | + response["headers"] = dict(headers) |
201 | 207 | return response
|
0 commit comments