mirror of
https://github.com/home-assistant/core.git
synced 2025-09-03 03:41:40 +02:00
Improve handling decode errors in rest (#150699)
This commit is contained in:
committed by
Franck Nijhof
parent
22e19e768e
commit
c551a133c1
@@ -45,6 +45,7 @@ class RestData:
|
||||
self._method = method
|
||||
self._resource = resource
|
||||
self._encoding = encoding
|
||||
self._force_use_set_encoding = False
|
||||
|
||||
# Convert auth tuple to aiohttp.BasicAuth if needed
|
||||
if isinstance(auth, tuple) and len(auth) == 2:
|
||||
@@ -152,10 +153,19 @@ class RestData:
|
||||
# Read the response
|
||||
# Only use configured encoding if no charset in Content-Type header
|
||||
# If charset is present in Content-Type, let aiohttp use it
|
||||
if response.charset:
|
||||
if self._force_use_set_encoding is False and response.charset:
|
||||
# Let aiohttp use the charset from Content-Type header
|
||||
self.data = await response.text()
|
||||
else:
|
||||
try:
|
||||
self.data = await response.text()
|
||||
except UnicodeDecodeError as ex:
|
||||
self._force_use_set_encoding = True
|
||||
_LOGGER.debug(
|
||||
"Response charset came back as %s but could not be decoded, continue with configured encoding %s. %s",
|
||||
response.charset,
|
||||
self._encoding,
|
||||
ex,
|
||||
)
|
||||
if self._force_use_set_encoding or not response.charset:
|
||||
# Use configured encoding as fallback
|
||||
self.data = await response.text(encoding=self._encoding)
|
||||
self.headers = response.headers
|
||||
|
@@ -1,13 +1,17 @@
|
||||
"""Test REST data module logging improvements."""
|
||||
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
from unittest.mock import patch
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.rest import DOMAIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.common import async_fire_time_changed
|
||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
|
||||
|
||||
@@ -89,6 +93,59 @@ async def test_rest_data_no_warning_on_200_with_wrong_content_type(
|
||||
)
|
||||
|
||||
|
||||
async def test_rest_data_with_incorrect_charset_in_header(
|
||||
hass: HomeAssistant,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test that we can handle sites which provides an incorrect charset."""
|
||||
aioclient_mock.get(
|
||||
"http://example.com/api",
|
||||
status=200,
|
||||
text="<p>Some html</p>",
|
||||
headers={"Content-Type": "text/html; charset=utf-8"},
|
||||
)
|
||||
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
DOMAIN,
|
||||
{
|
||||
DOMAIN: {
|
||||
"resource": "http://example.com/api",
|
||||
"method": "GET",
|
||||
"encoding": "windows-1250",
|
||||
"sensor": [
|
||||
{
|
||||
"name": "test_sensor",
|
||||
"value_template": "{{ value }}",
|
||||
}
|
||||
],
|
||||
}
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
with patch(
|
||||
"tests.test_util.aiohttp.AiohttpClientMockResponse.text",
|
||||
side_effect=UnicodeDecodeError("utf-8", b"", 1, 0, ""),
|
||||
):
|
||||
freezer.tick(timedelta(minutes=1))
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
log_text = "Response charset came back as utf-8 but could not be decoded, continue with configured encoding windows-1250."
|
||||
assert log_text in caplog.text
|
||||
|
||||
caplog.clear()
|
||||
freezer.tick(timedelta(minutes=1))
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Only log once as we only try once with automatic decoding
|
||||
assert log_text not in caplog.text
|
||||
|
||||
|
||||
async def test_rest_data_no_warning_on_success_json(
|
||||
hass: HomeAssistant,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
|
Reference in New Issue
Block a user