Log the error when the WebSocket receives a error message (#136492)

* Log the error when the WebSocket receives a non-text message

related issue #126754

Right now we only log that it was a non-Text message
and silently swallow the exception

* coverage
This commit is contained in:
J. Nick Koston 2025-01-27 10:38:18 -10:00 committed by GitHub
parent c12fa34e33
commit 7cf20c95c2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 88 additions and 5 deletions

View File

@ -387,7 +387,14 @@ class WebSocketHandler:
raise Disconnect("Received close message during auth phase") raise Disconnect("Received close message during auth phase")
if msg.type is not WSMsgType.TEXT: if msg.type is not WSMsgType.TEXT:
raise Disconnect("Received non-Text message during auth phase") if msg.type is WSMsgType.ERROR:
# msg.data is the exception
raise Disconnect(
f"Received error message during auth phase: {msg.data}"
)
raise Disconnect(
f"Received non-Text message of type {msg.type} during auth phase"
)
try: try:
auth_msg_data = json_loads(msg.data) auth_msg_data = json_loads(msg.data)
@ -477,7 +484,12 @@ class WebSocketHandler:
continue continue
if msg_type is not WSMsgType.TEXT: if msg_type is not WSMsgType.TEXT:
raise Disconnect("Received non-Text message.") if msg_type is WSMsgType.ERROR:
# msg.data is the exception
raise Disconnect(
f"Received error message during command phase: {msg.data}"
)
raise Disconnect(f"Received non-Text message of type {msg_type}.")
try: try:
command_msg_data = json_loads(msg_data) command_msg_data = json_loads(msg_data)

View File

@ -3,7 +3,7 @@
from unittest.mock import patch from unittest.mock import patch
import aiohttp import aiohttp
from aiohttp import WSMsgType from aiohttp import WSMsgType, web
import pytest import pytest
from homeassistant.auth.providers.homeassistant import HassAuthProvider from homeassistant.auth.providers.homeassistant import HassAuthProvider
@ -258,7 +258,7 @@ async def test_auth_sending_binary_disconnects(
await ws.send_bytes(b"[INVALID]") await ws.send_bytes(b"[INVALID]")
auth_msg = await ws.receive() auth_msg = await ws.receive()
assert auth_msg.type == WSMsgType.close assert auth_msg.type is WSMsgType.CLOSE
async def test_auth_close_disconnects( async def test_auth_close_disconnects(
@ -277,7 +277,40 @@ async def test_auth_close_disconnects(
await ws.close() await ws.close()
auth_msg = await ws.receive() auth_msg = await ws.receive()
assert auth_msg.type == WSMsgType.CLOSED assert auth_msg.type is WSMsgType.CLOSED
async def test_auth_error_disconnects(
hass: HomeAssistant,
hass_client_no_auth: ClientSessionGenerator,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test error during auth."""
assert await async_setup_component(hass, "websocket_api", {})
await hass.async_block_till_done()
client = await hass_client_no_auth()
ws_response = web.WebSocketResponse()
with patch(
"homeassistant.components.websocket_api.http.web.WebSocketResponse",
return_value=ws_response,
):
async with client.ws_connect(URL) as ws:
auth_msg = await ws.receive_json()
assert auth_msg["type"] == TYPE_AUTH_REQUIRED
ws_response._reader.feed_data(
aiohttp.WSMessage(
type=WSMsgType.ERROR, data=Exception("explode"), extra=None
),
0,
)
auth_msg = await ws.receive()
assert auth_msg.type is WSMsgType.CLOSE
assert "Received error message during auth phase: explode" in caplog.text
async def test_auth_sending_unknown_type_disconnects( async def test_auth_sending_unknown_type_disconnects(
@ -296,3 +329,41 @@ async def test_auth_sending_unknown_type_disconnects(
await ws._writer.send_frame(b"1" * 130, 0x30) await ws._writer.send_frame(b"1" * 130, 0x30)
auth_msg = await ws.receive() auth_msg = await ws.receive()
assert auth_msg.type == WSMsgType.close assert auth_msg.type == WSMsgType.close
async def test_error_right_after_auth_disconnects(
hass: HomeAssistant,
hass_client_no_auth: ClientSessionGenerator,
hass_access_token: str,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test error right after auth."""
assert await async_setup_component(hass, "websocket_api", {})
await hass.async_block_till_done()
client = await hass_client_no_auth()
ws_response = web.WebSocketResponse()
with patch(
"homeassistant.components.websocket_api.http.web.WebSocketResponse",
return_value=ws_response,
):
async with client.ws_connect(URL) as ws:
auth_msg = await ws.receive_json()
assert auth_msg["type"] == TYPE_AUTH_REQUIRED
await ws.send_json({"type": TYPE_AUTH, "access_token": hass_access_token})
auth_msg = await ws.receive_json()
assert auth_msg["type"] == TYPE_AUTH_OK
ws_response._reader.feed_data(
aiohttp.WSMessage(
type=WSMsgType.ERROR, data=Exception("explode"), extra=None
),
0,
)
close_error_msg = await ws.receive()
assert close_error_msg.type is WSMsgType.CLOSE
assert "Received error message during command phase: explode" in caplog.text