Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES/8845.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Changed behaviour when returning an invalid response to send a 500 response -- by :user:`Dreamsorcerer`.
36 changes: 18 additions & 18 deletions aiohttp/web_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
from .log import access_logger, server_logger
from .streams import EMPTY_PAYLOAD, StreamReader
from .tcp_helpers import tcp_keepalive
from .web_exceptions import HTTPException
from .web_exceptions import HTTPException, HTTPInternalServerError
from .web_log import AccessLogger
from .web_request import BaseRequest
from .web_response import Response, StreamResponse
Expand Down Expand Up @@ -464,16 +464,16 @@ async def _handle_request(
self._current_request = None
except HTTPException as exc:
resp = exc
reset = await self.finish_response(request, resp, start_time)
resp, reset = await self.finish_response(request, resp, start_time)
except asyncio.CancelledError:
raise
except asyncio.TimeoutError as exc:
self.log_debug("Request handler timed out.", exc_info=exc)
resp = self.handle_error(request, 504)
reset = await self.finish_response(request, resp, start_time)
resp, reset = await self.finish_response(request, resp, start_time)
except Exception as exc:
resp = self.handle_error(request, 500, exc)
reset = await self.finish_response(request, resp, start_time)
resp, reset = await self.finish_response(request, resp, start_time)
else:
# Deprecation warning (See #2415)
if getattr(resp, "__http_exception__", False):
Expand All @@ -484,7 +484,7 @@ async def _handle_request(
DeprecationWarning,
)

reset = await self.finish_response(request, resp, start_time)
resp, reset = await self.finish_response(request, resp, start_time)
finally:
self._handler_waiter.set_result(None)

Expand Down Expand Up @@ -584,10 +584,6 @@ async def start(self) -> None:
except asyncio.CancelledError:
self.log_debug("Ignored premature client disconnection ")
break
except RuntimeError as exc:
if self.debug:
self.log_exception("Unhandled runtime exception", exc_info=exc)
self.force_close()
except Exception as exc:
self.log_exception("Unhandled exception", exc_info=exc)
self.force_close()
Expand Down Expand Up @@ -616,7 +612,7 @@ async def start(self) -> None:

async def finish_response(
self, request: BaseRequest, resp: StreamResponse, start_time: float
) -> bool:
) -> Tuple[StreamResponse, bool]:
"""Prepare the response and write_eof, then log access.

This has to
Expand All @@ -635,22 +631,26 @@ async def finish_response(
prepare_meth = resp.prepare
except AttributeError:
if resp is None:
raise RuntimeError("Missing return " "statement on request handler")
self.log_exception("Missing return statement on request handler")
else:
raise RuntimeError(
"Web-handler should return "
"a response instance, "
self.log_exception(
"Web-handler should return a response instance, "
"got {!r}".format(resp)
)
exc = HTTPInternalServerError()
resp = Response(
status=exc.status, reason=exc.reason, text=exc.text, headers=exc.headers
)
prepare_meth = resp.prepare
try:
await prepare_meth(request)
await resp.write_eof()
except ConnectionError:
self.log_access(request, resp, start_time)
return True
else:
self.log_access(request, resp, start_time)
return False
return resp, True

self.log_access(request, resp, start_time)
return resp, False

def handle_error(
self,
Expand Down
17 changes: 4 additions & 13 deletions tests/test_web_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,8 @@ async def handler(request):
server = await aiohttp_server(app, logger=logger)
client = await aiohttp_client(server)

with pytest.raises(aiohttp.ServerDisconnectedError):
await client.get("/")

logger.exception.assert_called_with(
"Unhandled runtime exception", exc_info=mock.ANY
)
async with client.get("/") as resp:
assert resp.status == 500


async def test_handler_returns_none(aiohttp_server, aiohttp_client) -> None:
Expand All @@ -121,13 +117,8 @@ async def handler(request):
server = await aiohttp_server(app, logger=logger)
client = await aiohttp_client(server)

with pytest.raises(aiohttp.ServerDisconnectedError):
await client.get("/")

# Actual error text is placed in exc_info
logger.exception.assert_called_with(
"Unhandled runtime exception", exc_info=mock.ANY
)
async with client.get("/") as resp:
assert resp.status == 500


async def test_head_returns_empty_body(aiohttp_client) -> None:
Expand Down