mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-11-09 02:49:43 +00:00
Fix WebSocket transport None race condition in proxy
Add a transport validity check before WebSocket upgrade to prevent AssertionError when clients disconnect during handshake. The issue occurs when a client connection is lost between the API state check and server.prepare() call, causing request.transport to become None and triggering "assert transport is not None" in aiohttp's _pre_start(). The fix detects the closed connection early and raises HTTPBadRequest with a clear reason instead of crashing with an AssertionError. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -222,6 +222,11 @@ class APIProxy(CoreSysAttributes):
|
||||
raise HTTPBadGateway()
|
||||
_LOGGER.info("Home Assistant WebSocket API request initialize")
|
||||
|
||||
# Check if transport is still valid before WebSocket upgrade
|
||||
if request.transport is None:
|
||||
_LOGGER.warning("WebSocket connection lost before upgrade")
|
||||
raise web.HTTPBadRequest(reason="Connection closed")
|
||||
|
||||
# init server
|
||||
server = web.WebSocketResponse(heartbeat=30)
|
||||
await server.prepare(request)
|
||||
|
||||
@@ -223,6 +223,34 @@ async def test_proxy_auth_abort_log(
|
||||
)
|
||||
|
||||
|
||||
async def test_websocket_transport_none(
|
||||
coresys,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
):
|
||||
"""Test WebSocket connection with transport None is handled gracefully."""
|
||||
from aiohttp import web
|
||||
|
||||
# Get the API proxy instance from coresys
|
||||
api_proxy = APIProxy.__new__(APIProxy)
|
||||
api_proxy.coresys = coresys
|
||||
|
||||
# Create a mock request with transport set to None to simulate connection loss
|
||||
mock_request = AsyncMock(spec=web.Request)
|
||||
mock_request.transport = None
|
||||
|
||||
caplog.clear()
|
||||
with caplog.at_level(logging.WARNING):
|
||||
# This should raise HTTPBadRequest, not AssertionError
|
||||
with pytest.raises(web.HTTPBadRequest) as exc_info:
|
||||
await api_proxy.websocket(mock_request)
|
||||
|
||||
# Verify the error reason
|
||||
assert exc_info.value.reason == "Connection closed"
|
||||
|
||||
# Verify the warning was logged
|
||||
assert "WebSocket connection lost before upgrade" in caplog.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize("path", ["", "mock_path"])
|
||||
async def test_api_proxy_get_request(
|
||||
api_client: TestClient,
|
||||
|
||||
Reference in New Issue
Block a user