aio-libs / aiohttp

Asynchronous HTTP client/server framework for asyncio and Python
https://docs.aiohttp.org
Other
15.03k stars 2k forks source link

Enabling gzip compression throws exception on 204 No content responses #3166

Closed dchaplinsky closed 2 weeks ago

dchaplinsky commented 6 years ago

Long story short

I've enabled gzip compression like that but it throws exception on 204 responses

Expected behaviour

Do not throw exception if body is absent

Actual behaviour

Traceback (most recent call last):
  File "my_awesome_project/venv/lib/python3.6/site-packages/aiohttp/web_protocol.py", line 398, in start
    await resp.prepare(request)
  File "my_awesome_project/venv/lib/python3.6/site-packages/aiohttp/web_response.py", line 300, in prepare
    return await self._start(request)
  File "my_awesome_project/venv/lib/python3.6/site-packages/aiohttp/web_response.py", line 605, in _start
    return await super()._start(request)
  File "my_awesome_project/venv/lib/python3.6/site-packages/aiohttp/web_response.py", line 329, in _start
    self._start_compression(request)
  File "my_awesome_project/venv/lib/python3.6/site-packages/aiohttp/web_response.py", line 290, in _start_compression
    self._do_start_compression(coding)
  File "my_awesome_project/venv/lib/python3.6/site-packages/aiohttp/web_response.py", line 616, in _do_start_compression
    self._compressed_body = compressobj.compress(self._body) +\
TypeError: a bytes-like object is required, not 'NoneType'

Steps to reproduce


async def enable_compression(request, response):
    response.enable_compression()
....

app.on_response_prepare.append(remove_server_header)
....

but when I do

async def whatever(request):
    raise web.HTTPNoContent()

exception above happens

Your environment

python 3.6.5 aiohttp (both) 3.3.2 MacOS 10.13.5 (17F77)

ljluestc commented 7 months ago

from aiohttp import web

async def enable_compression(request, response):
    # Only enable compression if response has a body
    if response.body is not None:
        response.enable_compression()

async def remove_server_header(request, response):
    response.headers.pop('Server', None)

async def whatever(request):
    raise web.HTTPNoContent()

app = web.Application()
app.on_response_prepare.append(enable_compression)
app.on_response_prepare.append(remove_server_header)

app.router.add_get('/', whatever)

if __name__ == '__main__':
    web.run_app(app)
Dreamsorcerer commented 7 months ago

I suspect this assert should be changed to be part of the if statement: https://github.com/aio-libs/aiohttp/blob/0ec65c0f4dc08d027f659256b09ae9cff10ab404/aiohttp/web_response.py#L707

If someone can add a test that reproduces the issue with a 204 response, then we can fix that.

Dreamsorcerer commented 2 weeks ago

9108