diff --git a/karapace/rapu.py b/karapace/rapu.py index 5ba90b3d5..7108b7631 100644 --- a/karapace/rapu.py +++ b/karapace/rapu.py @@ -393,6 +393,11 @@ async def _handle_request( ) headers = {"Content-Type": "application/json"} resp = aiohttp.web.Response(body=body, status=status.value, headers=headers) + except ConnectionError as connection_error: + # TCP level connection errors, e.g. TCP reset, client closes connection. + self.log.debug("Connection error.", exc_info=connection_error) + # No response can be returned and written to client, aiohttp expects some response here. + resp = aiohttp.web.Response(text="Connection error", status=HTTPStatus.INTERNAL_SERVER_ERROR.value) except asyncio.CancelledError: self.log.debug("Client closed connection") raise diff --git a/tests/unit/test_rapu.py b/tests/unit/test_rapu.py index 7205fc8d2..bb3e5df4e 100644 --- a/tests/unit/test_rapu.py +++ b/tests/unit/test_rapu.py @@ -2,7 +2,11 @@ Copyright (c) 2023 Aiven Ltd See LICENSE for details """ +from aiohttp.web import Request +from karapace.config import DEFAULTS +from karapace.karapace import KarapaceBase from karapace.rapu import HTTPRequest, REST_ACCEPT_RE, REST_CONTENT_TYPE_RE +from unittest.mock import Mock async def test_header_get(): @@ -154,3 +158,21 @@ def test_content_type_re(): "serialization_format": "json", "general_format": None, } + + +async def test_raise_connection_error_handling() -> None: + request_mock = Mock(spec=Request) + request_mock.read.side_effect = ConnectionError("Connection error test.") + callback_mock = Mock() + + app = KarapaceBase(config=DEFAULTS) + + response = await app._handle_request( # pylint: disable=protected-access + request=request_mock, + path_for_stats="/", + callback=callback_mock, + ) + + assert response.status == 500 + request_mock.read.assert_has_calls([]) + callback_mock.assert_not_called()