{"record":{"id":"4b5f1fc1ef80dc88","repo":"aio-libs/aiohttp","slug":"deflate","errorCode":null,"errorMessage":"deflate","messagePattern":"deflate","errorType":"http","errorClass":"ContentEncodingError","httpStatus":400,"severity":"error","filePath":"aiohttp/http_parser.py","lineNumber":1218,"sourceCode":"            raise ContentEncodingError(\n                \"Can not decode content-encoding: %s\" % self.encoding\n            )\n\n        if chunk:\n            self.out.feed_data(chunk)\n        return self.decompressor.data_available\n\n    def feed_eof(self) -> None:\n        chunk = self.decompressor.flush()\n        # This should never contain data as we defer the call until exhausting\n        # the decompression. If .flush() is returning data, this may indicate a\n        # zip bomb vulnerability as it will decompress all remaining data at once.\n        assert not chunk\n\n        if self.size > 0:\n            # decompressor is not brotli unless encoding is \"br\"\n            if self.encoding == \"deflate\" and not self.decompressor.eof:  # type: ignore[union-attr]\n                raise ContentEncodingError(\"deflate\")\n\n        self.out.feed_eof()\n\n    def begin_http_chunk_receiving(self) -> None:\n        self.out.begin_http_chunk_receiving()\n\n    def end_http_chunk_receiving(self) -> None:\n        self.out.end_http_chunk_receiving()\n\n\nHttpRequestParserPy = HttpRequestParser\nHttpResponseParserPy = HttpResponseParser\nRawRequestMessagePy = RawRequestMessage\nRawResponseMessagePy = RawResponseMessage\n\nwith suppress(ImportError):\n    if not NO_EXTENSIONS:\n        from ._http_parser import (  # type: ignore[import-not-found,no-redef]","sourceCodeStart":1200,"sourceCodeEnd":1236,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/http_parser.py#L1200-L1236","documentation":"Raised as ContentEncodingError (message 'deflate') at EOF when a deflate-compressed body did not finish cleanly — specifically when encoding is 'deflate' and self.decompressor.eof is False after flush() in feed_eof. The flush() is asserted to return no data; if the zlib stream did not reach its end marker, this fires, signalling a truncated or malformed deflate stream.","triggerScenarios":"A response with 'Content-Encoding: deflate' where the compressed stream is incomplete or corrupt such that the ZLibDecompressor.eof is False at EOF. Triggers in DeflateBuffer.feed_eof when self.size > 0 and the deflate decompressor has not seen its end marker.","commonSituations":"Server sends a truncated deflate stream (connection dropped mid-body); a server computing deflate incorrectly; a proxy stripping trailing bytes; raw deflate vs zlib-wrapped deflate mismatch that initially decoded but did not terminate; clients that abort reading before completion.","solutions":["Ensure the server emits a complete, properly terminated deflate stream.","Check the connection was not severed before the full body arrived.","Verify whether the body is zlib-wrapped (RFC 1950) or raw deflate (RFC 1951) — the parser tries to auto-detect via the first byte; mismatches can still partially decode then fail at EOF.","Capture the raw bytes and test with python's zlib to localize the fault.","If the body is intentionally raw, confirm the server emits the correct format."],"exampleFix":"# before (server sends incomplete deflate)\r\nresp = web.Response(body=truncated_raw_deflate, headers={'Content-Encoding': 'deflate'})\r\n\r\n# after (send a complete zlib stream)\r\nimport zlib\r\ncompressed = zlib.compress(data, wbits=15)  # zlib-wrapped deflate\r\nresp = web.Response(body=compressed, headers={'Content-Encoding': 'deflate'})","handlingStrategy":"try-catch","validationCode":"import zlib\n\ndef validate_deflate_stream(raw: bytes) -> bool:\n    # try zlib-wrapped first, then raw deflate\n    for wbits in (15, -15):\n        try:\n            d = zlib.decompressobj(wbits)\n            d.decompress(raw)\n            d.flush()\n            if d.eof:\n                return True\n        except zlib.error:\n            continue\n    return False","typeGuard":null,"tryCatchPattern":"from aiohttp.http_exceptions import ContentEncodingError\nimport aiohttp\n\nasync def get_deflate_safe(url):\n    try:\n        async with aiohttp.ClientSession() as s:\n            async with s.get(url) as r:\n                return await r.read()\n    except ContentEncodingError as e:\n        if str(e) == 'deflate':\n            # server may send raw vs zlib-wrapped; fetch raw and decode manually\n            async with aiohttp.ClientSession(auto_decompress=False) as s:\n                async with s.get(url) as r:\n                    raw = await r.read()\n            import zlib\n            try:\n                return zlib.decompress(raw, -15)\n            except zlib.error:\n                return zlib.decompress(raw, 15)\n        raise","preventionTips":["Ensure servers emit a complete, terminated deflate stream.","Confirm zlib-wrapped (RFC 1950) vs raw (RFC 1951) consistency with the header.","Check the connection is not dropping the tail.","Validate with python's zlib before blaming the client."],"tags":["content-encoding","deflate","decompression","truncated","zlib"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}