Skip to content

Commit c551a13

Browse files
gjohansson-STfrenck
authored andcommitted
Improve handling decode errors in rest (home-assistant#150699)
1 parent 22e19e7 commit c551a13

File tree

2 files changed

+70
-3
lines changed

2 files changed

+70
-3
lines changed

homeassistant/components/rest/data.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ def __init__(
4545
self._method = method
4646
self._resource = resource
4747
self._encoding = encoding
48+
self._force_use_set_encoding = False
4849

4950
# Convert auth tuple to aiohttp.BasicAuth if needed
5051
if isinstance(auth, tuple) and len(auth) == 2:
@@ -152,10 +153,19 @@ async def async_update(self, log_errors: bool = True) -> None:
152153
# Read the response
153154
# Only use configured encoding if no charset in Content-Type header
154155
# If charset is present in Content-Type, let aiohttp use it
155-
if response.charset:
156+
if self._force_use_set_encoding is False and response.charset:
156157
# Let aiohttp use the charset from Content-Type header
157-
self.data = await response.text()
158-
else:
158+
try:
159+
self.data = await response.text()
160+
except UnicodeDecodeError as ex:
161+
self._force_use_set_encoding = True
162+
_LOGGER.debug(
163+
"Response charset came back as %s but could not be decoded, continue with configured encoding %s. %s",
164+
response.charset,
165+
self._encoding,
166+
ex,
167+
)
168+
if self._force_use_set_encoding or not response.charset:
159169
# Use configured encoding as fallback
160170
self.data = await response.text(encoding=self._encoding)
161171
self.headers = response.headers

tests/components/rest/test_data.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
"""Test REST data module logging improvements."""
22

3+
from datetime import timedelta
34
import logging
5+
from unittest.mock import patch
46

7+
from freezegun.api import FrozenDateTimeFactory
58
import pytest
69

710
from homeassistant.components.rest import DOMAIN
811
from homeassistant.core import HomeAssistant
912
from homeassistant.setup import async_setup_component
1013

14+
from tests.common import async_fire_time_changed
1115
from tests.test_util.aiohttp import AiohttpClientMocker
1216

1317

@@ -89,6 +93,59 @@ async def test_rest_data_no_warning_on_200_with_wrong_content_type(
8993
)
9094

9195

96+
async def test_rest_data_with_incorrect_charset_in_header(
97+
hass: HomeAssistant,
98+
aioclient_mock: AiohttpClientMocker,
99+
caplog: pytest.LogCaptureFixture,
100+
freezer: FrozenDateTimeFactory,
101+
) -> None:
102+
"""Test that we can handle sites which provides an incorrect charset."""
103+
aioclient_mock.get(
104+
"http://example.com/api",
105+
status=200,
106+
text="<p>Some html</p>",
107+
headers={"Content-Type": "text/html; charset=utf-8"},
108+
)
109+
110+
assert await async_setup_component(
111+
hass,
112+
DOMAIN,
113+
{
114+
DOMAIN: {
115+
"resource": "http://example.com/api",
116+
"method": "GET",
117+
"encoding": "windows-1250",
118+
"sensor": [
119+
{
120+
"name": "test_sensor",
121+
"value_template": "{{ value }}",
122+
}
123+
],
124+
}
125+
},
126+
)
127+
await hass.async_block_till_done()
128+
129+
with patch(
130+
"tests.test_util.aiohttp.AiohttpClientMockResponse.text",
131+
side_effect=UnicodeDecodeError("utf-8", b"", 1, 0, ""),
132+
):
133+
freezer.tick(timedelta(minutes=1))
134+
async_fire_time_changed(hass)
135+
await hass.async_block_till_done()
136+
137+
log_text = "Response charset came back as utf-8 but could not be decoded, continue with configured encoding windows-1250."
138+
assert log_text in caplog.text
139+
140+
caplog.clear()
141+
freezer.tick(timedelta(minutes=1))
142+
async_fire_time_changed(hass)
143+
await hass.async_block_till_done()
144+
145+
# Only log once as we only try once with automatic decoding
146+
assert log_text not in caplog.text
147+
148+
92149
async def test_rest_data_no_warning_on_success_json(
93150
hass: HomeAssistant,
94151
aioclient_mock: AiohttpClientMocker,

0 commit comments

Comments
 (0)