prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Multiple-compressed responses support
  HTTP response body can be compressed multiple times. In such cases `Content-Encoding` header contains a list of comma-separated encodings. Some servers instead can send multiple `Content-Encoding` headers.
  This fix allows HttpCompressionMiddleware handle that.
  See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding
  Fix #5143
  Fixes #5143 
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `scrapy/downloadermiddlewares/httpcompression.py`
  Content:
  ```
  1 from __future__ import annotations
  2 
  3 import warnings
  4 from logging import getLogger
  5 from typing import TYPE_CHECKING, List, Optional, Union
  6 
  7 from scrapy import Request, Spider, signals
  8 from scrapy.crawler import Crawler
  9 from scrapy.exceptions import IgnoreRequest, NotConfigured
  10 from scrapy.http import Response, TextResponse
  11 from scrapy.responsetypes import responsetypes
  12 from scrapy.statscollectors import StatsCollector
  13 from scrapy.utils._compression import (
  14     _DecompressionMaxSizeExceeded,
  15     _inflate,
  16     _unbrotli,
  17     _unzstd,
  18 )
  19 from scrapy.utils.deprecate import ScrapyDeprecationWarning
  20 from scrapy.utils.gz import gunzip
  21 
  22 if TYPE_CHECKING:
  23     # typing.Self requires Python 3.11
  24     from typing_extensions import Self
  25 
  26 logger = getLogger(__name__)
  27 
  28 ACCEPTED_ENCODINGS: List[bytes] = [b"gzip", b"deflate"]
  29 
  30 try:
  31     import brotli  # noqa: F401
  32 except ImportError:
  33     pass
  34 else:
  35     ACCEPTED_ENCODINGS.append(b"br")
  36 
  37 try:
  38     import zstandard  # noqa: F401
  39 except ImportError:
  40     pass
  41 else:
  42     ACCEPTED_ENCODINGS.append(b"zstd")
  43 
  44 
  45 class HttpCompressionMiddleware:
  46     """This middleware allows compressed (gzip, deflate) traffic to be
  47     sent/received from web sites"""
  48 
  49     def __init__(
  50         self,
  51         stats: Optional[StatsCollector] = None,
  52         *,
  53         crawler: Optional[Crawler] = None,
  54     ):
  55         if not crawler:
  56             self.stats = stats
  57             self._max_size = 1073741824
  58             self._warn_size = 33554432
  59             return
  60         self.stats = crawler.stats
  61         self._max_size = crawler.settings.getint("DOWNLOAD_MAXSIZE")
  62         self._warn_size = crawler.settings.getint("DOWNLOAD_WARNSIZE")
  63         crawler.signals.connect(self.open_spider, signals.spider_opened)
  64 
  65     @classmethod
  66     def from_crawler(cls, crawler: Crawler) -> Self:
  67         if not crawler.settings.getbool("COMPRESSION_ENABLED"):
  68             raise NotConfigured
  69         try:
  70             return cls(crawler=crawler)
  71         except TypeError:
  72             warnings.warn(
  73                 "HttpCompressionMiddleware subclasses must either modify "
  74                 "their '__init__' method to support a 'crawler' parameter or "
  75                 "reimplement their 'from_crawler' method.",
  76                 ScrapyDeprecationWarning,
  77             )
  78             mw = cls()
  79             mw.stats = crawler.stats
  80             mw._max_size = crawler.settings.getint("DOWNLOAD_MAXSIZE")
  81             mw._warn_size = crawler.settings.getint("DOWNLOAD_WARNSIZE")
  82             crawler.signals.connect(mw.open_spider, signals.spider_opened)
  83             return mw
  84 
  85     def open_spider(self, spider):
  86         if hasattr(spider, "download_maxsize"):
  87             self._max_size = spider.download_maxsize
  88         if hasattr(spider, "download_warnsize"):
  89             self._warn_size = spider.download_warnsize
  90 
  91     def process_request(
  92         self, request: Request, spider: Spider
  93     ) -> Union[Request, Response, None]:
  94         request.headers.setdefault("Accept-Encoding", b", ".join(ACCEPTED_ENCODINGS))
  95         return None
  96 
  97     def process_response(
  98         self, request: Request, response: Response, spider: Spider
  99     ) -> Union[Request, Response]:
  100         if request.method == "HEAD":
  101             return response
  102         if isinstance(response, Response):
  103             content_encoding = response.headers.getlist("Content-Encoding")
  104             if content_encoding:
  105                 encoding = content_encoding.pop()
  106                 max_size = request.meta.get("download_maxsize", self._max_size)
  107                 warn_size = request.meta.get("download_warnsize", self._warn_size)
  108                 try:
  109                     decoded_body = self._decode(
  110                         response.body, encoding.lower(), max_size
  111                     )
  112                 except _DecompressionMaxSizeExceeded:
  113                     raise IgnoreRequest(
  114                         f"Ignored response {response} because its body "
  115                         f"({len(response.body)} B) exceeded DOWNLOAD_MAXSIZE "
  116                         f"({max_size} B) during decompression."
  117                     )
  118                 if len(response.body) < warn_size <= len(decoded_body):
  119                     logger.warning(
  120                         f"{response} body size after decompression "
  121                         f"({len(decoded_body)} B) is larger than the "
  122                         f"download warning size ({warn_size} B)."
  123                     )
  124                 if self.stats:
  125                     self.stats.inc_value(
  126                         "httpcompression/response_bytes",
  127                         len(decoded_body),
  128                         spider=spider,
  129                     )
  130                     self.stats.inc_value(
  131                         "httpcompression/response_count", spider=spider
  132                     )
  133                 respcls = responsetypes.from_args(
  134                     headers=response.headers, url=response.url, body=decoded_body
  135                 )
  136                 kwargs = dict(cls=respcls, body=decoded_body)
  137                 if issubclass(respcls, TextResponse):
  138                     # force recalculating the encoding until we make sure the
  139                     # responsetypes guessing is reliable
  140                     kwargs["encoding"] = None
  141                 response = response.replace(**kwargs)
  142                 if not content_encoding:
  143                     del response.headers["Content-Encoding"]
  144 
  145         return response
  146 
  147     def _decode(self, body: bytes, encoding: bytes, max_size: int) -> bytes:
  148         if encoding == b"gzip" or encoding == b"x-gzip":
  149             return gunzip(body, max_size=max_size)
  150         if encoding == b"deflate":
  151             return _inflate(body, max_size=max_size)
  152         if encoding == b"br" and b"br" in ACCEPTED_ENCODINGS:
  153             return _unbrotli(body, max_size=max_size)
  154         if encoding == b"zstd" and b"zstd" in ACCEPTED_ENCODINGS:
  155             return _unzstd(body, max_size=max_size)
  156         return body
  157
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/scrapy/downloadermiddlewares/httpcompression.py b/scrapy/downloadermiddlewares/httpcompression.py
  --- a/scrapy/downloadermiddlewares/httpcompression.py
  +++ b/scrapy/downloadermiddlewares/httpcompression.py
  @@ -1,6 +1,7 @@
   from __future__ import annotations
   
   import warnings
  +from itertools import chain
   from logging import getLogger
   from typing import TYPE_CHECKING, List, Optional, Union
   
  @@ -102,18 +103,18 @@
           if isinstance(response, Response):
               content_encoding = response.headers.getlist("Content-Encoding")
               if content_encoding:
  -                encoding = content_encoding.pop()
                   max_size = request.meta.get("download_maxsize", self._max_size)
                   warn_size = request.meta.get("download_warnsize", self._warn_size)
                   try:
  -                    decoded_body = self._decode(
  -                        response.body, encoding.lower(), max_size
  +                    decoded_body, content_encoding = self._handle_encoding(
  +                        response.body, content_encoding, max_size
                       )
                   except _DecompressionMaxSizeExceeded:
                       raise IgnoreRequest(
                           f"Ignored response {response} because its body "
  -                        f"({len(response.body)} B) exceeded DOWNLOAD_MAXSIZE "
  -                        f"({max_size} B) during decompression."
  +                        f"({len(response.body)} B compressed) exceeded "
  +                        f"DOWNLOAD_MAXSIZE ({max_size} B) during "
  +                        f"decompression."
                       )
                   if len(response.body) < warn_size <= len(decoded_body):
                       logger.warning(
  @@ -121,6 +122,7 @@
                           f"({len(decoded_body)} B) is larger than the "
                           f"download warning size ({warn_size} B)."
                       )
  +                response.headers["Content-Encoding"] = content_encoding
                   if self.stats:
                       self.stats.inc_value(
                           "httpcompression/response_bytes",
  @@ -144,6 +146,28 @@
   
           return response
   
  +    def _handle_encoding(self, body, content_encoding, max_size):
  +        to_decode, to_keep = self._split_encodings(content_encoding)
  +        for encoding in to_decode:
  +            body = self._decode(body, encoding, max_size)
  +        return body, to_keep
  +
  +    def _split_encodings(self, content_encoding):
  +        to_keep = [
  +            encoding.strip().lower()
  +            for encoding in chain.from_iterable(
  +                encodings.split(b",") for encodings in content_encoding
  +            )
  +        ]
  +        to_decode = []
  +        while to_keep:
  +            encoding = to_keep.pop()
  +            if encoding not in ACCEPTED_ENCODINGS:
  +                to_keep.append(encoding)
  +                return to_decode, to_keep
  +            to_decode.append(encoding)
  +        return to_decode, to_keep
  +
       def _decode(self, body: bytes, encoding: bytes, max_size: int) -> bytes:
           if encoding == b"gzip" or encoding == b"x-gzip":
               return gunzip(body, max_size=max_size)
  
verification_info: {"golden_diff": "diff --git a/scrapy/downloadermiddlewares/httpcompression.py b/scrapy/downloadermiddlewares/httpcompression.py\n--- a/scrapy/downloadermiddlewares/httpcompression.py\n+++ b/scrapy/downloadermiddlewares/httpcompression.py\n@@ -1,6 +1,7 @@\n from __future__ import annotations\n \n import warnings\n+from itertools import chain\n from logging import getLogger\n from typing import TYPE_CHECKING, List, Optional, Union\n \n@@ -102,18 +103,18 @@\n         if isinstance(response, Response):\n             content_encoding = response.headers.getlist(\"Content-Encoding\")\n             if content_encoding:\n-                encoding = content_encoding.pop()\n                 max_size = request.meta.get(\"download_maxsize\", self._max_size)\n                 warn_size = request.meta.get(\"download_warnsize\", self._warn_size)\n                 try:\n-                    decoded_body = self._decode(\n-                        response.body, encoding.lower(), max_size\n+                    decoded_body, content_encoding = self._handle_encoding(\n+                        response.body, content_encoding, max_size\n                     )\n                 except _DecompressionMaxSizeExceeded:\n                     raise IgnoreRequest(\n                         f\"Ignored response {response} because its body \"\n-                        f\"({len(response.body)} B) exceeded DOWNLOAD_MAXSIZE \"\n-                        f\"({max_size} B) during decompression.\"\n+                        f\"({len(response.body)} B compressed) exceeded \"\n+                        f\"DOWNLOAD_MAXSIZE ({max_size} B) during \"\n+                        f\"decompression.\"\n                     )\n                 if len(response.body) < warn_size <= len(decoded_body):\n                     logger.warning(\n@@ -121,6 +122,7 @@\n                         f\"({len(decoded_body)} B) is larger than the \"\n                         f\"download warning size ({warn_size} B).\"\n                     )\n+                response.headers[\"Content-Encoding\"] = content_encoding\n                 if self.stats:\n                     self.stats.inc_value(\n                         \"httpcompression/response_bytes\",\n@@ -144,6 +146,28 @@\n \n         return response\n \n+    def _handle_encoding(self, body, content_encoding, max_size):\n+        to_decode, to_keep = self._split_encodings(content_encoding)\n+        for encoding in to_decode:\n+            body = self._decode(body, encoding, max_size)\n+        return body, to_keep\n+\n+    def _split_encodings(self, content_encoding):\n+        to_keep = [\n+            encoding.strip().lower()\n+            for encoding in chain.from_iterable(\n+                encodings.split(b\",\") for encodings in content_encoding\n+            )\n+        ]\n+        to_decode = []\n+        while to_keep:\n+            encoding = to_keep.pop()\n+            if encoding not in ACCEPTED_ENCODINGS:\n+                to_keep.append(encoding)\n+                return to_decode, to_keep\n+            to_decode.append(encoding)\n+        return to_decode, to_keep\n+\n     def _decode(self, body: bytes, encoding: bytes, max_size: int) -> bytes:\n         if encoding == b\"gzip\" or encoding == b\"x-gzip\":\n             return gunzip(body, max_size=max_size)\n", "issue": "Multiple-compressed responses support\nHTTP response body can be compressed multiple times. In such cases `Content-Encoding` header contains a list of comma-separated encodings. Some servers instead can send multiple `Content-Encoding` headers.\r\nThis fix allows HttpCompressionMiddleware handle that.\r\nSee also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding\nFix #5143\nFixes #5143 \n", "before_files": [{"content": "from __future__ import annotations\n\nimport warnings\nfrom logging import getLogger\nfrom typing import TYPE_CHECKING, List, Optional, Union\n\nfrom scrapy import Request, Spider, signals\nfrom scrapy.crawler import Crawler\nfrom scrapy.exceptions import IgnoreRequest, NotConfigured\nfrom scrapy.http import Response, TextResponse\nfrom scrapy.responsetypes import responsetypes\nfrom scrapy.statscollectors import StatsCollector\nfrom scrapy.utils._compression import (\n    _DecompressionMaxSizeExceeded,\n    _inflate,\n    _unbrotli,\n    _unzstd,\n)\nfrom scrapy.utils.deprecate import ScrapyDeprecationWarning\nfrom scrapy.utils.gz import gunzip\n\nif TYPE_CHECKING:\n    # typing.Self requires Python 3.11\n    from typing_extensions import Self\n\nlogger = getLogger(__name__)\n\nACCEPTED_ENCODINGS: List[bytes] = [b\"gzip\", b\"deflate\"]\n\ntry:\n    import brotli  # noqa: F401\nexcept ImportError:\n    pass\nelse:\n    ACCEPTED_ENCODINGS.append(b\"br\")\n\ntry:\n    import zstandard  # noqa: F401\nexcept ImportError:\n    pass\nelse:\n    ACCEPTED_ENCODINGS.append(b\"zstd\")\n\n\nclass HttpCompressionMiddleware:\n    \"\"\"This middleware allows compressed (gzip, deflate) traffic to be\n    sent/received from web sites\"\"\"\n\n    def __init__(\n        self,\n        stats: Optional[StatsCollector] = None,\n        *,\n        crawler: Optional[Crawler] = None,\n    ):\n        if not crawler:\n            self.stats = stats\n            self._max_size = 1073741824\n            self._warn_size = 33554432\n            return\n        self.stats = crawler.stats\n        self._max_size = crawler.settings.getint(\"DOWNLOAD_MAXSIZE\")\n        self._warn_size = crawler.settings.getint(\"DOWNLOAD_WARNSIZE\")\n        crawler.signals.connect(self.open_spider, signals.spider_opened)\n\n    @classmethod\n    def from_crawler(cls, crawler: Crawler) -> Self:\n        if not crawler.settings.getbool(\"COMPRESSION_ENABLED\"):\n            raise NotConfigured\n        try:\n            return cls(crawler=crawler)\n        except TypeError:\n            warnings.warn(\n                \"HttpCompressionMiddleware subclasses must either modify \"\n                \"their '__init__' method to support a 'crawler' parameter or \"\n                \"reimplement their 'from_crawler' method.\",\n                ScrapyDeprecationWarning,\n            )\n            mw = cls()\n            mw.stats = crawler.stats\n            mw._max_size = crawler.settings.getint(\"DOWNLOAD_MAXSIZE\")\n            mw._warn_size = crawler.settings.getint(\"DOWNLOAD_WARNSIZE\")\n            crawler.signals.connect(mw.open_spider, signals.spider_opened)\n            return mw\n\n    def open_spider(self, spider):\n        if hasattr(spider, \"download_maxsize\"):\n            self._max_size = spider.download_maxsize\n        if hasattr(spider, \"download_warnsize\"):\n            self._warn_size = spider.download_warnsize\n\n    def process_request(\n        self, request: Request, spider: Spider\n    ) -> Union[Request, Response, None]:\n        request.headers.setdefault(\"Accept-Encoding\", b\", \".join(ACCEPTED_ENCODINGS))\n        return None\n\n    def process_response(\n        self, request: Request, response: Response, spider: Spider\n    ) -> Union[Request, Response]:\n        if request.method == \"HEAD\":\n            return response\n        if isinstance(response, Response):\n            content_encoding = response.headers.getlist(\"Content-Encoding\")\n            if content_encoding:\n                encoding = content_encoding.pop()\n                max_size = request.meta.get(\"download_maxsize\", self._max_size)\n                warn_size = request.meta.get(\"download_warnsize\", self._warn_size)\n                try:\n                    decoded_body = self._decode(\n                        response.body, encoding.lower(), max_size\n                    )\n                except _DecompressionMaxSizeExceeded:\n                    raise IgnoreRequest(\n                        f\"Ignored response {response} because its body \"\n                        f\"({len(response.body)} B) exceeded DOWNLOAD_MAXSIZE \"\n                        f\"({max_size} B) during decompression.\"\n                    )\n                if len(response.body) < warn_size <= len(decoded_body):\n                    logger.warning(\n                        f\"{response} body size after decompression \"\n                        f\"({len(decoded_body)} B) is larger than the \"\n                        f\"download warning size ({warn_size} B).\"\n                    )\n                if self.stats:\n                    self.stats.inc_value(\n                        \"httpcompression/response_bytes\",\n                        len(decoded_body),\n                        spider=spider,\n                    )\n                    self.stats.inc_value(\n                        \"httpcompression/response_count\", spider=spider\n                    )\n                respcls = responsetypes.from_args(\n                    headers=response.headers, url=response.url, body=decoded_body\n                )\n                kwargs = dict(cls=respcls, body=decoded_body)\n                if issubclass(respcls, TextResponse):\n                    # force recalculating the encoding until we make sure the\n                    # responsetypes guessing is reliable\n                    kwargs[\"encoding\"] = None\n                response = response.replace(**kwargs)\n                if not content_encoding:\n                    del response.headers[\"Content-Encoding\"]\n\n        return response\n\n    def _decode(self, body: bytes, encoding: bytes, max_size: int) -> bytes:\n        if encoding == b\"gzip\" or encoding == b\"x-gzip\":\n            return gunzip(body, max_size=max_size)\n        if encoding == b\"deflate\":\n            return _inflate(body, max_size=max_size)\n        if encoding == b\"br\" and b\"br\" in ACCEPTED_ENCODINGS:\n            return _unbrotli(body, max_size=max_size)\n        if encoding == b\"zstd\" and b\"zstd\" in ACCEPTED_ENCODINGS:\n            return _unzstd(body, max_size=max_size)\n        return body\n", "path": "scrapy/downloadermiddlewares/httpcompression.py"}], "after_files": [{"content": "from __future__ import annotations\n\nimport warnings\nfrom itertools import chain\nfrom logging import getLogger\nfrom typing import TYPE_CHECKING, List, Optional, Union\n\nfrom scrapy import Request, Spider, signals\nfrom scrapy.crawler import Crawler\nfrom scrapy.exceptions import IgnoreRequest, NotConfigured\nfrom scrapy.http import Response, TextResponse\nfrom scrapy.responsetypes import responsetypes\nfrom scrapy.statscollectors import StatsCollector\nfrom scrapy.utils._compression import (\n    _DecompressionMaxSizeExceeded,\n    _inflate,\n    _unbrotli,\n    _unzstd,\n)\nfrom scrapy.utils.deprecate import ScrapyDeprecationWarning\nfrom scrapy.utils.gz import gunzip\n\nif TYPE_CHECKING:\n    # typing.Self requires Python 3.11\n    from typing_extensions import Self\n\nlogger = getLogger(__name__)\n\nACCEPTED_ENCODINGS: List[bytes] = [b\"gzip\", b\"deflate\"]\n\ntry:\n    import brotli  # noqa: F401\nexcept ImportError:\n    pass\nelse:\n    ACCEPTED_ENCODINGS.append(b\"br\")\n\ntry:\n    import zstandard  # noqa: F401\nexcept ImportError:\n    pass\nelse:\n    ACCEPTED_ENCODINGS.append(b\"zstd\")\n\n\nclass HttpCompressionMiddleware:\n    \"\"\"This middleware allows compressed (gzip, deflate) traffic to be\n    sent/received from web sites\"\"\"\n\n    def __init__(\n        self,\n        stats: Optional[StatsCollector] = None,\n        *,\n        crawler: Optional[Crawler] = None,\n    ):\n        if not crawler:\n            self.stats = stats\n            self._max_size = 1073741824\n            self._warn_size = 33554432\n            return\n        self.stats = crawler.stats\n        self._max_size = crawler.settings.getint(\"DOWNLOAD_MAXSIZE\")\n        self._warn_size = crawler.settings.getint(\"DOWNLOAD_WARNSIZE\")\n        crawler.signals.connect(self.open_spider, signals.spider_opened)\n\n    @classmethod\n    def from_crawler(cls, crawler: Crawler) -> Self:\n        if not crawler.settings.getbool(\"COMPRESSION_ENABLED\"):\n            raise NotConfigured\n        try:\n            return cls(crawler=crawler)\n        except TypeError:\n            warnings.warn(\n                \"HttpCompressionMiddleware subclasses must either modify \"\n                \"their '__init__' method to support a 'crawler' parameter or \"\n                \"reimplement their 'from_crawler' method.\",\n                ScrapyDeprecationWarning,\n            )\n            mw = cls()\n            mw.stats = crawler.stats\n            mw._max_size = crawler.settings.getint(\"DOWNLOAD_MAXSIZE\")\n            mw._warn_size = crawler.settings.getint(\"DOWNLOAD_WARNSIZE\")\n            crawler.signals.connect(mw.open_spider, signals.spider_opened)\n            return mw\n\n    def open_spider(self, spider):\n        if hasattr(spider, \"download_maxsize\"):\n            self._max_size = spider.download_maxsize\n        if hasattr(spider, \"download_warnsize\"):\n            self._warn_size = spider.download_warnsize\n\n    def process_request(\n        self, request: Request, spider: Spider\n    ) -> Union[Request, Response, None]:\n        request.headers.setdefault(\"Accept-Encoding\", b\", \".join(ACCEPTED_ENCODINGS))\n        return None\n\n    def process_response(\n        self, request: Request, response: Response, spider: Spider\n    ) -> Union[Request, Response]:\n        if request.method == \"HEAD\":\n            return response\n        if isinstance(response, Response):\n            content_encoding = response.headers.getlist(\"Content-Encoding\")\n            if content_encoding:\n                max_size = request.meta.get(\"download_maxsize\", self._max_size)\n                warn_size = request.meta.get(\"download_warnsize\", self._warn_size)\n                try:\n                    decoded_body, content_encoding = self._handle_encoding(\n                        response.body, content_encoding, max_size\n                    )\n                except _DecompressionMaxSizeExceeded:\n                    raise IgnoreRequest(\n                        f\"Ignored response {response} because its body \"\n                        f\"({len(response.body)} B compressed) exceeded \"\n                        f\"DOWNLOAD_MAXSIZE ({max_size} B) during \"\n                        f\"decompression.\"\n                    )\n                if len(response.body) < warn_size <= len(decoded_body):\n                    logger.warning(\n                        f\"{response} body size after decompression \"\n                        f\"({len(decoded_body)} B) is larger than the \"\n                        f\"download warning size ({warn_size} B).\"\n                    )\n                response.headers[\"Content-Encoding\"] = content_encoding\n                if self.stats:\n                    self.stats.inc_value(\n                        \"httpcompression/response_bytes\",\n                        len(decoded_body),\n                        spider=spider,\n                    )\n                    self.stats.inc_value(\n                        \"httpcompression/response_count\", spider=spider\n                    )\n                respcls = responsetypes.from_args(\n                    headers=response.headers, url=response.url, body=decoded_body\n                )\n                kwargs = dict(cls=respcls, body=decoded_body)\n                if issubclass(respcls, TextResponse):\n                    # force recalculating the encoding until we make sure the\n                    # responsetypes guessing is reliable\n                    kwargs[\"encoding\"] = None\n                response = response.replace(**kwargs)\n                if not content_encoding:\n                    del response.headers[\"Content-Encoding\"]\n\n        return response\n\n    def _handle_encoding(self, body, content_encoding, max_size):\n        to_decode, to_keep = self._split_encodings(content_encoding)\n        for encoding in to_decode:\n            body = self._decode(body, encoding, max_size)\n        return body, to_keep\n\n    def _split_encodings(self, content_encoding):\n        to_keep = [\n            encoding.strip().lower()\n            for encoding in chain.from_iterable(\n                encodings.split(b\",\") for encodings in content_encoding\n            )\n        ]\n        to_decode = []\n        while to_keep:\n            encoding = to_keep.pop()\n            if encoding not in ACCEPTED_ENCODINGS:\n                to_keep.append(encoding)\n                return to_decode, to_keep\n            to_decode.append(encoding)\n        return to_decode, to_keep\n\n    def _decode(self, body: bytes, encoding: bytes, max_size: int) -> bytes:\n        if encoding == b\"gzip\" or encoding == b\"x-gzip\":\n            return gunzip(body, max_size=max_size)\n        if encoding == b\"deflate\":\n            return _inflate(body, max_size=max_size)\n        if encoding == b\"br\" and b\"br\" in ACCEPTED_ENCODINGS:\n            return _unbrotli(body, max_size=max_size)\n        if encoding == b\"zstd\" and b\"zstd\" in ACCEPTED_ENCODINGS:\n            return _unzstd(body, max_size=max_size)\n        return body\n", "path": "scrapy/downloadermiddlewares/httpcompression.py"}]}