We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
GZIP request body encoding falling back to raw
#### Problem Description
GZIP requests are not decoded correctly.
This only occurs in the request and not in the response. In the response I see the body as uncompromised gzip but not in the request. 

I created a own content view to test the gzip decompression:

```python
from typing import Optional
from mitmproxy import contentviews, flow
from mitmproxy import http
import gzip


class ViewGZIPCase(contentviews.View):
    name = "GZIP"

    def __call__(self, data, **metadata) -> contentviews.TViewResult:
        return "gzip", contentviews.format_text(gzip.decompress(data))

    def render_priority(
            self,
            data: bytes,
            *,
            content_type: Optional[str] = None,
            flow: Optional[flow.Flow] = None,
            http_message: Optional[http.Message] = None,
            **unknown_metadata,
    ) -> float:

        if http_message.headers["content-encoding"] == "GZIP":
            return 1

        else:
            return 0


view = ViewGZIPCase()


def load(l):
    contentviews.add(view)


def done():
    contentviews.remove(view)
```

##### request

with selected self-made view
<img width="1637" alt="Screenshot 2021-08-05 at 16 42 57" src="https://user-images.githubusercontent.com/1338331/128370647-68c5af49-dfca-4862-a3ff-b3413c4226fd.png">

without any special view
<img width="1637" alt="Screenshot 2021-08-05 at 16 42 42" src="https://user-images.githubusercontent.com/1338331/128370652-e2001fd6-0909-491a-8c77-19cfa226b7d6.png">


##### response

Mitmproxy standalone decompression and json parsing in the response but why not in the request?
<img width="1637" alt="Screenshot 2021-08-05 at 16 47 55" src="https://user-images.githubusercontent.com/1338331/128370639-75287a4f-5c54-47e9-a126-3ff95a1dc90f.png">


#### Steps to reproduce the behavior:
1. start Mitmproxy 
2. wait for requests ( iPhone 12 as client is connected)
3. open the request

#### System Information
Mitmproxy: 7.0.2
Python:    3.9.6
OpenSSL:   OpenSSL 1.1.1k  25 Mar 2021
Platform:  macOS-11.5.1-x86_64-i386-64bit



GZIP request body encoding falling back to raw
#### Problem Description
GZIP requests are not decoded correctly.
This only occurs in the request and not in the response. In the response I see the body as uncompromised gzip but not in the request. 

I created a own content view to test the gzip decompression:

```python
from typing import Optional
from mitmproxy import contentviews, flow
from mitmproxy import http
import gzip


class ViewGZIPCase(contentviews.View):
    name = "GZIP"

    def __call__(self, data, **metadata) -> contentviews.TViewResult:
        return "gzip", contentviews.format_text(gzip.decompress(data))

    def render_priority(
            self,
            data: bytes,
            *,
            content_type: Optional[str] = None,
            flow: Optional[flow.Flow] = None,
            http_message: Optional[http.Message] = None,
            **unknown_metadata,
    ) -> float:

        if http_message.headers["content-encoding"] == "GZIP":
            return 1

        else:
            return 0


view = ViewGZIPCase()


def load(l):
    contentviews.add(view)


def done():
    contentviews.remove(view)
```

##### request

with selected self-made view
<img width="1637" alt="Screenshot 2021-08-05 at 16 42 57" src="https://user-images.githubusercontent.com/1338331/128370647-68c5af49-dfca-4862-a3ff-b3413c4226fd.png">

without any special view
<img width="1637" alt="Screenshot 2021-08-05 at 16 42 42" src="https://user-images.githubusercontent.com/1338331/128370652-e2001fd6-0909-491a-8c77-19cfa226b7d6.png">


##### response

Mitmproxy standalone decompression and json parsing in the response but why not in the request?
<img width="1637" alt="Screenshot 2021-08-05 at 16 47 55" src="https://user-images.githubusercontent.com/1338331/128370639-75287a4f-5c54-47e9-a126-3ff95a1dc90f.png">


#### Steps to reproduce the behavior:
1. start Mitmproxy 
2. wait for requests ( iPhone 12 as client is connected)
3. open the request

#### System Information
Mitmproxy: 7.0.2
Python:    3.9.6
OpenSSL:   OpenSSL 1.1.1k  25 Mar 2021
Platform:  macOS-11.5.1-x86_64-i386-64bit




--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mitmproxy/net/encoding.py`
Content:
```
1 """
2 Utility functions for decoding response bodies.
3 """
4 
5 import codecs
6 import collections
7 from io import BytesIO
8 
9 import gzip
10 import zlib
11 import brotli
12 import zstandard as zstd
13 
14 from typing import Union, Optional, AnyStr, overload  # noqa
15 
16 # We have a shared single-element cache for encoding and decoding.
17 # This is quite useful in practice, e.g.
18 # flow.request.content = flow.request.content.replace(b"foo", b"bar")
19 # does not require an .encode() call if content does not contain b"foo"
20 CachedDecode = collections.namedtuple(
21     "CachedDecode", "encoded encoding errors decoded"
22 )
23 _cache = CachedDecode(None, None, None, None)
24 
25 
26 @overload
27 def decode(encoded: None, encoding: str, errors: str = 'strict') -> None:
28     ...
29 
30 
31 @overload
32 def decode(encoded: str, encoding: str, errors: str = 'strict') -> str:
33     ...
34 
35 
36 @overload
37 def decode(encoded: bytes, encoding: str, errors: str = 'strict') -> Union[str, bytes]:
38     ...
39 
40 
41 def decode(
42         encoded: Union[None, str, bytes], encoding: str, errors: str = 'strict'
43 ) -> Union[None, str, bytes]:
44     """
45     Decode the given input object
46 
47     Returns:
48         The decoded value
49 
50     Raises:
51         ValueError, if decoding fails.
52     """
53     if encoded is None:
54         return None
55 
56     global _cache
57     cached = (
58             isinstance(encoded, bytes) and
59             _cache.encoded == encoded and
60             _cache.encoding == encoding and
61             _cache.errors == errors
62     )
63     if cached:
64         return _cache.decoded
65     try:
66         try:
67             decoded = custom_decode[encoding](encoded)
68         except KeyError:
69             decoded = codecs.decode(encoded, encoding, errors)  # type: ignore
70         if encoding in ("gzip", "deflate", "br", "zstd"):
71             _cache = CachedDecode(encoded, encoding, errors, decoded)
72         return decoded
73     except TypeError:
74         raise
75     except Exception as e:
76         raise ValueError("{} when decoding {} with {}: {}".format(
77             type(e).__name__,
78             repr(encoded)[:10],
79             repr(encoding),
80             repr(e),
81         ))
82 
83 
84 @overload
85 def encode(decoded: None, encoding: str, errors: str = 'strict') -> None:
86     ...
87 
88 
89 @overload
90 def encode(decoded: str, encoding: str, errors: str = 'strict') -> Union[str, bytes]:
91     ...
92 
93 
94 @overload
95 def encode(decoded: bytes, encoding: str, errors: str = 'strict') -> bytes:
96     ...
97 
98 
99 def encode(decoded: Union[None, str, bytes], encoding, errors='strict') -> Union[None, str, bytes]:
100     """
101     Encode the given input object
102 
103     Returns:
104         The encoded value
105 
106     Raises:
107         ValueError, if encoding fails.
108     """
109     if decoded is None:
110         return None
111 
112     global _cache
113     cached = (
114             isinstance(decoded, bytes) and
115             _cache.decoded == decoded and
116             _cache.encoding == encoding and
117             _cache.errors == errors
118     )
119     if cached:
120         return _cache.encoded
121     try:
122         try:
123             encoded = custom_encode[encoding](decoded)
124         except KeyError:
125             encoded = codecs.encode(decoded, encoding, errors)  # type: ignore
126         if encoding in ("gzip", "deflate", "br", "zstd"):
127             _cache = CachedDecode(encoded, encoding, errors, decoded)
128         return encoded
129     except TypeError:
130         raise
131     except Exception as e:
132         raise ValueError("{} when encoding {} with {}: {}".format(
133             type(e).__name__,
134             repr(decoded)[:10],
135             repr(encoding),
136             repr(e),
137         ))
138 
139 
140 def identity(content):
141     """
142         Returns content unchanged. Identity is the default value of
143         Accept-Encoding headers.
144     """
145     return content
146 
147 
148 def decode_gzip(content: bytes) -> bytes:
149     if not content:
150         return b""
151     gfile = gzip.GzipFile(fileobj=BytesIO(content))
152     return gfile.read()
153 
154 
155 def encode_gzip(content: bytes) -> bytes:
156     s = BytesIO()
157     gf = gzip.GzipFile(fileobj=s, mode='wb')
158     gf.write(content)
159     gf.close()
160     return s.getvalue()
161 
162 
163 def decode_brotli(content: bytes) -> bytes:
164     if not content:
165         return b""
166     return brotli.decompress(content)
167 
168 
169 def encode_brotli(content: bytes) -> bytes:
170     return brotli.compress(content)
171 
172 
173 def decode_zstd(content: bytes) -> bytes:
174     if not content:
175         return b""
176     zstd_ctx = zstd.ZstdDecompressor()
177     try:
178         return zstd_ctx.decompress(content)
179     except zstd.ZstdError:
180         # If the zstd stream is streamed without a size header,
181         # try decoding with a 10MiB output buffer
182         return zstd_ctx.decompress(content, max_output_size=10 * 2 ** 20)
183 
184 
185 def encode_zstd(content: bytes) -> bytes:
186     zstd_ctx = zstd.ZstdCompressor()
187     return zstd_ctx.compress(content)
188 
189 
190 def decode_deflate(content: bytes) -> bytes:
191     """
192         Returns decompressed data for DEFLATE. Some servers may respond with
193         compressed data without a zlib header or checksum. An undocumented
194         feature of zlib permits the lenient decompression of data missing both
195         values.
196 
197         http://bugs.python.org/issue5784
198     """
199     if not content:
200         return b""
201     try:
202         return zlib.decompress(content)
203     except zlib.error:
204         return zlib.decompress(content, -15)
205 
206 
207 def encode_deflate(content: bytes) -> bytes:
208     """
209         Returns compressed content, always including zlib header and checksum.
210     """
211     return zlib.compress(content)
212 
213 
214 custom_decode = {
215     "none": identity,
216     "identity": identity,
217     "gzip": decode_gzip,
218     "deflate": decode_deflate,
219     "deflateRaw": decode_deflate,
220     "br": decode_brotli,
221     "zstd": decode_zstd,
222 }
223 custom_encode = {
224     "none": identity,
225     "identity": identity,
226     "gzip": encode_gzip,
227     "deflate": encode_deflate,
228     "deflateRaw": encode_deflate,
229     "br": encode_brotli,
230     "zstd": encode_zstd,
231 }
232 
233 __all__ = ["encode", "decode"]
234
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/mitmproxy/net/encoding.py b/mitmproxy/net/encoding.py
--- a/mitmproxy/net/encoding.py
+++ b/mitmproxy/net/encoding.py
@@ -52,6 +52,7 @@
     """
     if encoded is None:
         return None
+    encoding = encoding.lower()
 
     global _cache
     cached = (
@@ -67,7 +68,7 @@
             decoded = custom_decode[encoding](encoded)
         except KeyError:
             decoded = codecs.decode(encoded, encoding, errors)  # type: ignore
-        if encoding in ("gzip", "deflate", "br", "zstd"):
+        if encoding in ("gzip", "deflate", "deflateraw", "br", "zstd"):
             _cache = CachedDecode(encoded, encoding, errors, decoded)
         return decoded
     except TypeError:
@@ -108,6 +109,7 @@
     """
     if decoded is None:
         return None
+    encoding = encoding.lower()
 
     global _cache
     cached = (
@@ -123,7 +125,7 @@
             encoded = custom_encode[encoding](decoded)
         except KeyError:
             encoded = codecs.encode(decoded, encoding, errors)  # type: ignore
-        if encoding in ("gzip", "deflate", "br", "zstd"):
+        if encoding in ("gzip", "deflate", "deflateraw", "br", "zstd"):
             _cache = CachedDecode(encoded, encoding, errors, decoded)
         return encoded
     except TypeError:
@@ -216,7 +218,7 @@
     "identity": identity,
     "gzip": decode_gzip,
     "deflate": decode_deflate,
-    "deflateRaw": decode_deflate,
+    "deflateraw": decode_deflate,
     "br": decode_brotli,
     "zstd": decode_zstd,
 }
@@ -225,7 +227,7 @@
     "identity": identity,
     "gzip": encode_gzip,
     "deflate": encode_deflate,
-    "deflateRaw": encode_deflate,
+    "deflateraw": encode_deflate,
     "br": encode_brotli,
     "zstd": encode_zstd,
 }

{"golden_diff": "diff --git a/mitmproxy/net/encoding.py b/mitmproxy/net/encoding.py\n--- a/mitmproxy/net/encoding.py\n+++ b/mitmproxy/net/encoding.py\n@@ -52,6 +52,7 @@\n     \"\"\"\n     if encoded is None:\n         return None\n+    encoding = encoding.lower()\n \n     global _cache\n     cached = (\n@@ -67,7 +68,7 @@\n             decoded = custom_decode[encoding](encoded)\n         except KeyError:\n             decoded = codecs.decode(encoded, encoding, errors)  # type: ignore\n-        if encoding in (\"gzip\", \"deflate\", \"br\", \"zstd\"):\n+        if encoding in (\"gzip\", \"deflate\", \"deflateraw\", \"br\", \"zstd\"):\n             _cache = CachedDecode(encoded, encoding, errors, decoded)\n         return decoded\n     except TypeError:\n@@ -108,6 +109,7 @@\n     \"\"\"\n     if decoded is None:\n         return None\n+    encoding = encoding.lower()\n \n     global _cache\n     cached = (\n@@ -123,7 +125,7 @@\n             encoded = custom_encode[encoding](decoded)\n         except KeyError:\n             encoded = codecs.encode(decoded, encoding, errors)  # type: ignore\n-        if encoding in (\"gzip\", \"deflate\", \"br\", \"zstd\"):\n+        if encoding in (\"gzip\", \"deflate\", \"deflateraw\", \"br\", \"zstd\"):\n             _cache = CachedDecode(encoded, encoding, errors, decoded)\n         return encoded\n     except TypeError:\n@@ -216,7 +218,7 @@\n     \"identity\": identity,\n     \"gzip\": decode_gzip,\n     \"deflate\": decode_deflate,\n-    \"deflateRaw\": decode_deflate,\n+    \"deflateraw\": decode_deflate,\n     \"br\": decode_brotli,\n     \"zstd\": decode_zstd,\n }\n@@ -225,7 +227,7 @@\n     \"identity\": identity,\n     \"gzip\": encode_gzip,\n     \"deflate\": encode_deflate,\n-    \"deflateRaw\": encode_deflate,\n+    \"deflateraw\": encode_deflate,\n     \"br\": encode_brotli,\n     \"zstd\": encode_zstd,\n }\n", "issue": "GZIP request body encoding falling back to raw\n#### Problem Description\r\nGZIP requests are not decoded correctly.\r\nThis only occurs in the request and not in the response. In the response I see the body as uncompromised gzip but not in the request. \r\n\r\nI created a own content view to test the gzip decompression:\r\n\r\n```python\r\nfrom typing import Optional\r\nfrom mitmproxy import contentviews, flow\r\nfrom mitmproxy import http\r\nimport gzip\r\n\r\n\r\nclass ViewGZIPCase(contentviews.View):\r\n    name = \"GZIP\"\r\n\r\n    def __call__(self, data, **metadata) -> contentviews.TViewResult:\r\n        return \"gzip\", contentviews.format_text(gzip.decompress(data))\r\n\r\n    def render_priority(\r\n            self,\r\n            data: bytes,\r\n            *,\r\n            content_type: Optional[str] = None,\r\n            flow: Optional[flow.Flow] = None,\r\n            http_message: Optional[http.Message] = None,\r\n            **unknown_metadata,\r\n    ) -> float:\r\n\r\n        if http_message.headers[\"content-encoding\"] == \"GZIP\":\r\n            return 1\r\n\r\n        else:\r\n            return 0\r\n\r\n\r\nview = ViewGZIPCase()\r\n\r\n\r\ndef load(l):\r\n    contentviews.add(view)\r\n\r\n\r\ndef done():\r\n    contentviews.remove(view)\r\n```\r\n\r\n##### request\r\n\r\nwith selected self-made view\r\n<img width=\"1637\" alt=\"Screenshot 2021-08-05 at 16 42 57\" src=\"https://user-images.githubusercontent.com/1338331/128370647-68c5af49-dfca-4862-a3ff-b3413c4226fd.png\">\r\n\r\nwithout any special view\r\n<img width=\"1637\" alt=\"Screenshot 2021-08-05 at 16 42 42\" src=\"https://user-images.githubusercontent.com/1338331/128370652-e2001fd6-0909-491a-8c77-19cfa226b7d6.png\">\r\n\r\n\r\n##### response\r\n\r\nMitmproxy standalone decompression and json parsing in the response but why not in the request?\r\n<img width=\"1637\" alt=\"Screenshot 2021-08-05 at 16 47 55\" src=\"https://user-images.githubusercontent.com/1338331/128370639-75287a4f-5c54-47e9-a126-3ff95a1dc90f.png\">\r\n\r\n\r\n#### Steps to reproduce the behavior:\r\n1. start Mitmproxy \r\n2. wait for requests ( iPhone 12 as client is connected)\r\n3. open the request\r\n\r\n#### System Information\r\nMitmproxy: 7.0.2\r\nPython:    3.9.6\r\nOpenSSL:   OpenSSL 1.1.1k  25 Mar 2021\r\nPlatform:  macOS-11.5.1-x86_64-i386-64bit\r\n\r\n\r\n\nGZIP request body encoding falling back to raw\n#### Problem Description\r\nGZIP requests are not decoded correctly.\r\nThis only occurs in the request and not in the response. In the response I see the body as uncompromised gzip but not in the request. \r\n\r\nI created a own content view to test the gzip decompression:\r\n\r\n```python\r\nfrom typing import Optional\r\nfrom mitmproxy import contentviews, flow\r\nfrom mitmproxy import http\r\nimport gzip\r\n\r\n\r\nclass ViewGZIPCase(contentviews.View):\r\n    name = \"GZIP\"\r\n\r\n    def __call__(self, data, **metadata) -> contentviews.TViewResult:\r\n        return \"gzip\", contentviews.format_text(gzip.decompress(data))\r\n\r\n    def render_priority(\r\n            self,\r\n            data: bytes,\r\n            *,\r\n            content_type: Optional[str] = None,\r\n            flow: Optional[flow.Flow] = None,\r\n            http_message: Optional[http.Message] = None,\r\n            **unknown_metadata,\r\n    ) -> float:\r\n\r\n        if http_message.headers[\"content-encoding\"] == \"GZIP\":\r\n            return 1\r\n\r\n        else:\r\n            return 0\r\n\r\n\r\nview = ViewGZIPCase()\r\n\r\n\r\ndef load(l):\r\n    contentviews.add(view)\r\n\r\n\r\ndef done():\r\n    contentviews.remove(view)\r\n```\r\n\r\n##### request\r\n\r\nwith selected self-made view\r\n<img width=\"1637\" alt=\"Screenshot 2021-08-05 at 16 42 57\" src=\"https://user-images.githubusercontent.com/1338331/128370647-68c5af49-dfca-4862-a3ff-b3413c4226fd.png\">\r\n\r\nwithout any special view\r\n<img width=\"1637\" alt=\"Screenshot 2021-08-05 at 16 42 42\" src=\"https://user-images.githubusercontent.com/1338331/128370652-e2001fd6-0909-491a-8c77-19cfa226b7d6.png\">\r\n\r\n\r\n##### response\r\n\r\nMitmproxy standalone decompression and json parsing in the response but why not in the request?\r\n<img width=\"1637\" alt=\"Screenshot 2021-08-05 at 16 47 55\" src=\"https://user-images.githubusercontent.com/1338331/128370639-75287a4f-5c54-47e9-a126-3ff95a1dc90f.png\">\r\n\r\n\r\n#### Steps to reproduce the behavior:\r\n1. start Mitmproxy \r\n2. wait for requests ( iPhone 12 as client is connected)\r\n3. open the request\r\n\r\n#### System Information\r\nMitmproxy: 7.0.2\r\nPython:    3.9.6\r\nOpenSSL:   OpenSSL 1.1.1k  25 Mar 2021\r\nPlatform:  macOS-11.5.1-x86_64-i386-64bit\r\n\r\n\r\n\n", "before_files": [{"content": "\"\"\"\nUtility functions for decoding response bodies.\n\"\"\"\n\nimport codecs\nimport collections\nfrom io import BytesIO\n\nimport gzip\nimport zlib\nimport brotli\nimport zstandard as zstd\n\nfrom typing import Union, Optional, AnyStr, overload  # noqa\n\n# We have a shared single-element cache for encoding and decoding.\n# This is quite useful in practice, e.g.\n# flow.request.content = flow.request.content.replace(b\"foo\", b\"bar\")\n# does not require an .encode() call if content does not contain b\"foo\"\nCachedDecode = collections.namedtuple(\n    \"CachedDecode\", \"encoded encoding errors decoded\"\n)\n_cache = CachedDecode(None, None, None, None)\n\n\n@overload\ndef decode(encoded: None, encoding: str, errors: str = 'strict') -> None:\n    ...\n\n\n@overload\ndef decode(encoded: str, encoding: str, errors: str = 'strict') -> str:\n    ...\n\n\n@overload\ndef decode(encoded: bytes, encoding: str, errors: str = 'strict') -> Union[str, bytes]:\n    ...\n\n\ndef decode(\n        encoded: Union[None, str, bytes], encoding: str, errors: str = 'strict'\n) -> Union[None, str, bytes]:\n    \"\"\"\n    Decode the given input object\n\n    Returns:\n        The decoded value\n\n    Raises:\n        ValueError, if decoding fails.\n    \"\"\"\n    if encoded is None:\n        return None\n\n    global _cache\n    cached = (\n            isinstance(encoded, bytes) and\n            _cache.encoded == encoded and\n            _cache.encoding == encoding and\n            _cache.errors == errors\n    )\n    if cached:\n        return _cache.decoded\n    try:\n        try:\n            decoded = custom_decode[encoding](encoded)\n        except KeyError:\n            decoded = codecs.decode(encoded, encoding, errors)  # type: ignore\n        if encoding in (\"gzip\", \"deflate\", \"br\", \"zstd\"):\n            _cache = CachedDecode(encoded, encoding, errors, decoded)\n        return decoded\n    except TypeError:\n        raise\n    except Exception as e:\n        raise ValueError(\"{} when decoding {} with {}: {}\".format(\n            type(e).__name__,\n            repr(encoded)[:10],\n            repr(encoding),\n            repr(e),\n        ))\n\n\n@overload\ndef encode(decoded: None, encoding: str, errors: str = 'strict') -> None:\n    ...\n\n\n@overload\ndef encode(decoded: str, encoding: str, errors: str = 'strict') -> Union[str, bytes]:\n    ...\n\n\n@overload\ndef encode(decoded: bytes, encoding: str, errors: str = 'strict') -> bytes:\n    ...\n\n\ndef encode(decoded: Union[None, str, bytes], encoding, errors='strict') -> Union[None, str, bytes]:\n    \"\"\"\n    Encode the given input object\n\n    Returns:\n        The encoded value\n\n    Raises:\n        ValueError, if encoding fails.\n    \"\"\"\n    if decoded is None:\n        return None\n\n    global _cache\n    cached = (\n            isinstance(decoded, bytes) and\n            _cache.decoded == decoded and\n            _cache.encoding == encoding and\n            _cache.errors == errors\n    )\n    if cached:\n        return _cache.encoded\n    try:\n        try:\n            encoded = custom_encode[encoding](decoded)\n        except KeyError:\n            encoded = codecs.encode(decoded, encoding, errors)  # type: ignore\n        if encoding in (\"gzip\", \"deflate\", \"br\", \"zstd\"):\n            _cache = CachedDecode(encoded, encoding, errors, decoded)\n        return encoded\n    except TypeError:\n        raise\n    except Exception as e:\n        raise ValueError(\"{} when encoding {} with {}: {}\".format(\n            type(e).__name__,\n            repr(decoded)[:10],\n            repr(encoding),\n            repr(e),\n        ))\n\n\ndef identity(content):\n    \"\"\"\n        Returns content unchanged. Identity is the default value of\n        Accept-Encoding headers.\n    \"\"\"\n    return content\n\n\ndef decode_gzip(content: bytes) -> bytes:\n    if not content:\n        return b\"\"\n    gfile = gzip.GzipFile(fileobj=BytesIO(content))\n    return gfile.read()\n\n\ndef encode_gzip(content: bytes) -> bytes:\n    s = BytesIO()\n    gf = gzip.GzipFile(fileobj=s, mode='wb')\n    gf.write(content)\n    gf.close()\n    return s.getvalue()\n\n\ndef decode_brotli(content: bytes) -> bytes:\n    if not content:\n        return b\"\"\n    return brotli.decompress(content)\n\n\ndef encode_brotli(content: bytes) -> bytes:\n    return brotli.compress(content)\n\n\ndef decode_zstd(content: bytes) -> bytes:\n    if not content:\n        return b\"\"\n    zstd_ctx = zstd.ZstdDecompressor()\n    try:\n        return zstd_ctx.decompress(content)\n    except zstd.ZstdError:\n        # If the zstd stream is streamed without a size header,\n        # try decoding with a 10MiB output buffer\n        return zstd_ctx.decompress(content, max_output_size=10 * 2 ** 20)\n\n\ndef encode_zstd(content: bytes) -> bytes:\n    zstd_ctx = zstd.ZstdCompressor()\n    return zstd_ctx.compress(content)\n\n\ndef decode_deflate(content: bytes) -> bytes:\n    \"\"\"\n        Returns decompressed data for DEFLATE. Some servers may respond with\n        compressed data without a zlib header or checksum. An undocumented\n        feature of zlib permits the lenient decompression of data missing both\n        values.\n\n        http://bugs.python.org/issue5784\n    \"\"\"\n    if not content:\n        return b\"\"\n    try:\n        return zlib.decompress(content)\n    except zlib.error:\n        return zlib.decompress(content, -15)\n\n\ndef encode_deflate(content: bytes) -> bytes:\n    \"\"\"\n        Returns compressed content, always including zlib header and checksum.\n    \"\"\"\n    return zlib.compress(content)\n\n\ncustom_decode = {\n    \"none\": identity,\n    \"identity\": identity,\n    \"gzip\": decode_gzip,\n    \"deflate\": decode_deflate,\n    \"deflateRaw\": decode_deflate,\n    \"br\": decode_brotli,\n    \"zstd\": decode_zstd,\n}\ncustom_encode = {\n    \"none\": identity,\n    \"identity\": identity,\n    \"gzip\": encode_gzip,\n    \"deflate\": encode_deflate,\n    \"deflateRaw\": encode_deflate,\n    \"br\": encode_brotli,\n    \"zstd\": encode_zstd,\n}\n\n__all__ = [\"encode\", \"decode\"]\n", "path": "mitmproxy/net/encoding.py"}], "after_files": [{"content": "\"\"\"\nUtility functions for decoding response bodies.\n\"\"\"\n\nimport codecs\nimport collections\nfrom io import BytesIO\n\nimport gzip\nimport zlib\nimport brotli\nimport zstandard as zstd\n\nfrom typing import Union, Optional, AnyStr, overload  # noqa\n\n# We have a shared single-element cache for encoding and decoding.\n# This is quite useful in practice, e.g.\n# flow.request.content = flow.request.content.replace(b\"foo\", b\"bar\")\n# does not require an .encode() call if content does not contain b\"foo\"\nCachedDecode = collections.namedtuple(\n    \"CachedDecode\", \"encoded encoding errors decoded\"\n)\n_cache = CachedDecode(None, None, None, None)\n\n\n@overload\ndef decode(encoded: None, encoding: str, errors: str = 'strict') -> None:\n    ...\n\n\n@overload\ndef decode(encoded: str, encoding: str, errors: str = 'strict') -> str:\n    ...\n\n\n@overload\ndef decode(encoded: bytes, encoding: str, errors: str = 'strict') -> Union[str, bytes]:\n    ...\n\n\ndef decode(\n        encoded: Union[None, str, bytes], encoding: str, errors: str = 'strict'\n) -> Union[None, str, bytes]:\n    \"\"\"\n    Decode the given input object\n\n    Returns:\n        The decoded value\n\n    Raises:\n        ValueError, if decoding fails.\n    \"\"\"\n    if encoded is None:\n        return None\n    encoding = encoding.lower()\n\n    global _cache\n    cached = (\n            isinstance(encoded, bytes) and\n            _cache.encoded == encoded and\n            _cache.encoding == encoding and\n            _cache.errors == errors\n    )\n    if cached:\n        return _cache.decoded\n    try:\n        try:\n            decoded = custom_decode[encoding](encoded)\n        except KeyError:\n            decoded = codecs.decode(encoded, encoding, errors)  # type: ignore\n        if encoding in (\"gzip\", \"deflate\", \"deflateraw\", \"br\", \"zstd\"):\n            _cache = CachedDecode(encoded, encoding, errors, decoded)\n        return decoded\n    except TypeError:\n        raise\n    except Exception as e:\n        raise ValueError(\"{} when decoding {} with {}: {}\".format(\n            type(e).__name__,\n            repr(encoded)[:10],\n            repr(encoding),\n            repr(e),\n        ))\n\n\n@overload\ndef encode(decoded: None, encoding: str, errors: str = 'strict') -> None:\n    ...\n\n\n@overload\ndef encode(decoded: str, encoding: str, errors: str = 'strict') -> Union[str, bytes]:\n    ...\n\n\n@overload\ndef encode(decoded: bytes, encoding: str, errors: str = 'strict') -> bytes:\n    ...\n\n\ndef encode(decoded: Union[None, str, bytes], encoding, errors='strict') -> Union[None, str, bytes]:\n    \"\"\"\n    Encode the given input object\n\n    Returns:\n        The encoded value\n\n    Raises:\n        ValueError, if encoding fails.\n    \"\"\"\n    if decoded is None:\n        return None\n    encoding = encoding.lower()\n\n    global _cache\n    cached = (\n            isinstance(decoded, bytes) and\n            _cache.decoded == decoded and\n            _cache.encoding == encoding and\n            _cache.errors == errors\n    )\n    if cached:\n        return _cache.encoded\n    try:\n        try:\n            encoded = custom_encode[encoding](decoded)\n        except KeyError:\n            encoded = codecs.encode(decoded, encoding, errors)  # type: ignore\n        if encoding in (\"gzip\", \"deflate\", \"deflateraw\", \"br\", \"zstd\"):\n            _cache = CachedDecode(encoded, encoding, errors, decoded)\n        return encoded\n    except TypeError:\n        raise\n    except Exception as e:\n        raise ValueError(\"{} when encoding {} with {}: {}\".format(\n            type(e).__name__,\n            repr(decoded)[:10],\n            repr(encoding),\n            repr(e),\n        ))\n\n\ndef identity(content):\n    \"\"\"\n        Returns content unchanged. Identity is the default value of\n        Accept-Encoding headers.\n    \"\"\"\n    return content\n\n\ndef decode_gzip(content: bytes) -> bytes:\n    if not content:\n        return b\"\"\n    gfile = gzip.GzipFile(fileobj=BytesIO(content))\n    return gfile.read()\n\n\ndef encode_gzip(content: bytes) -> bytes:\n    s = BytesIO()\n    gf = gzip.GzipFile(fileobj=s, mode='wb')\n    gf.write(content)\n    gf.close()\n    return s.getvalue()\n\n\ndef decode_brotli(content: bytes) -> bytes:\n    if not content:\n        return b\"\"\n    return brotli.decompress(content)\n\n\ndef encode_brotli(content: bytes) -> bytes:\n    return brotli.compress(content)\n\n\ndef decode_zstd(content: bytes) -> bytes:\n    if not content:\n        return b\"\"\n    zstd_ctx = zstd.ZstdDecompressor()\n    try:\n        return zstd_ctx.decompress(content)\n    except zstd.ZstdError:\n        # If the zstd stream is streamed without a size header,\n        # try decoding with a 10MiB output buffer\n        return zstd_ctx.decompress(content, max_output_size=10 * 2 ** 20)\n\n\ndef encode_zstd(content: bytes) -> bytes:\n    zstd_ctx = zstd.ZstdCompressor()\n    return zstd_ctx.compress(content)\n\n\ndef decode_deflate(content: bytes) -> bytes:\n    \"\"\"\n        Returns decompressed data for DEFLATE. Some servers may respond with\n        compressed data without a zlib header or checksum. An undocumented\n        feature of zlib permits the lenient decompression of data missing both\n        values.\n\n        http://bugs.python.org/issue5784\n    \"\"\"\n    if not content:\n        return b\"\"\n    try:\n        return zlib.decompress(content)\n    except zlib.error:\n        return zlib.decompress(content, -15)\n\n\ndef encode_deflate(content: bytes) -> bytes:\n    \"\"\"\n        Returns compressed content, always including zlib header and checksum.\n    \"\"\"\n    return zlib.compress(content)\n\n\ncustom_decode = {\n    \"none\": identity,\n    \"identity\": identity,\n    \"gzip\": decode_gzip,\n    \"deflate\": decode_deflate,\n    \"deflateraw\": decode_deflate,\n    \"br\": decode_brotli,\n    \"zstd\": decode_zstd,\n}\ncustom_encode = {\n    \"none\": identity,\n    \"identity\": identity,\n    \"gzip\": encode_gzip,\n    \"deflate\": encode_deflate,\n    \"deflateraw\": encode_deflate,\n    \"br\": encode_brotli,\n    \"zstd\": encode_zstd,\n}\n\n__all__ = [\"encode\", \"decode\"]\n", "path": "mitmproxy/net/encoding.py"}]}