Skip to content

Commit 400feb6

Browse files
Return 500 error when handler has wrong return type (#8845) (#8891)
(cherry picked from commit 48a5e07)
1 parent 996204a commit 400feb6

3 files changed

Lines changed: 23 additions & 31 deletions

File tree

CHANGES/8845.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Changed behaviour when returning an invalid response to send a 500 response -- by :user:`Dreamsorcerer`.

aiohttp/web_protocol.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
from .log import access_logger, server_logger
3939
from .streams import EMPTY_PAYLOAD, StreamReader
4040
from .tcp_helpers import tcp_keepalive
41-
from .web_exceptions import HTTPException
41+
from .web_exceptions import HTTPException, HTTPInternalServerError
4242
from .web_log import AccessLogger
4343
from .web_request import BaseRequest
4444
from .web_response import Response, StreamResponse
@@ -464,16 +464,16 @@ async def _handle_request(
464464
self._current_request = None
465465
except HTTPException as exc:
466466
resp = exc
467-
reset = await self.finish_response(request, resp, start_time)
467+
resp, reset = await self.finish_response(request, resp, start_time)
468468
except asyncio.CancelledError:
469469
raise
470470
except asyncio.TimeoutError as exc:
471471
self.log_debug("Request handler timed out.", exc_info=exc)
472472
resp = self.handle_error(request, 504)
473-
reset = await self.finish_response(request, resp, start_time)
473+
resp, reset = await self.finish_response(request, resp, start_time)
474474
except Exception as exc:
475475
resp = self.handle_error(request, 500, exc)
476-
reset = await self.finish_response(request, resp, start_time)
476+
resp, reset = await self.finish_response(request, resp, start_time)
477477
else:
478478
# Deprecation warning (See #2415)
479479
if getattr(resp, "__http_exception__", False):
@@ -484,7 +484,7 @@ async def _handle_request(
484484
DeprecationWarning,
485485
)
486486

487-
reset = await self.finish_response(request, resp, start_time)
487+
resp, reset = await self.finish_response(request, resp, start_time)
488488
finally:
489489
self._handler_waiter.set_result(None)
490490

@@ -584,10 +584,6 @@ async def start(self) -> None:
584584
except asyncio.CancelledError:
585585
self.log_debug("Ignored premature client disconnection ")
586586
break
587-
except RuntimeError as exc:
588-
if self.debug:
589-
self.log_exception("Unhandled runtime exception", exc_info=exc)
590-
self.force_close()
591587
except Exception as exc:
592588
self.log_exception("Unhandled exception", exc_info=exc)
593589
self.force_close()
@@ -616,7 +612,7 @@ async def start(self) -> None:
616612

617613
async def finish_response(
618614
self, request: BaseRequest, resp: StreamResponse, start_time: float
619-
) -> bool:
615+
) -> Tuple[StreamResponse, bool]:
620616
"""Prepare the response and write_eof, then log access.
621617
622618
This has to
@@ -635,22 +631,26 @@ async def finish_response(
635631
prepare_meth = resp.prepare
636632
except AttributeError:
637633
if resp is None:
638-
raise RuntimeError("Missing return " "statement on request handler")
634+
self.log_exception("Missing return statement on request handler")
639635
else:
640-
raise RuntimeError(
641-
"Web-handler should return "
642-
"a response instance, "
636+
self.log_exception(
637+
"Web-handler should return a response instance, "
643638
"got {!r}".format(resp)
644639
)
640+
exc = HTTPInternalServerError()
641+
resp = Response(
642+
status=exc.status, reason=exc.reason, text=exc.text, headers=exc.headers
643+
)
644+
prepare_meth = resp.prepare
645645
try:
646646
await prepare_meth(request)
647647
await resp.write_eof()
648648
except ConnectionError:
649649
self.log_access(request, resp, start_time)
650-
return True
651-
else:
652-
self.log_access(request, resp, start_time)
653-
return False
650+
return resp, True
651+
652+
self.log_access(request, resp, start_time)
653+
return resp, False
654654

655655
def handle_error(
656656
self,

tests/test_web_functional.py

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,8 @@ async def handler(request):
101101
server = await aiohttp_server(app, logger=logger)
102102
client = await aiohttp_client(server)
103103

104-
with pytest.raises(aiohttp.ServerDisconnectedError):
105-
await client.get("/")
106-
107-
logger.exception.assert_called_with(
108-
"Unhandled runtime exception", exc_info=mock.ANY
109-
)
104+
async with client.get("/") as resp:
105+
assert resp.status == 500
110106

111107

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

124-
with pytest.raises(aiohttp.ServerDisconnectedError):
125-
await client.get("/")
126-
127-
# Actual error text is placed in exc_info
128-
logger.exception.assert_called_with(
129-
"Unhandled runtime exception", exc_info=mock.ANY
130-
)
120+
async with client.get("/") as resp:
121+
assert resp.status == 500
131122

132123

133124
async def test_head_returns_empty_body(aiohttp_client) -> None:

0 commit comments

Comments
 (0)