diff --git a/homeassistant/components/http/view.py b/homeassistant/components/http/view.py index 30d4ed0ab8d..c8f5d788dd2 100644 --- a/homeassistant/components/http/view.py +++ b/homeassistant/components/http/view.py @@ -45,8 +45,9 @@ class HomeAssistantView: """Return a JSON response.""" try: msg = json.dumps( - result, sort_keys=True, cls=JSONEncoder).encode('UTF-8') - except TypeError as err: + result, sort_keys=True, cls=JSONEncoder, allow_nan=False + ).encode('UTF-8') + except (ValueError, TypeError) as err: _LOGGER.error('Unable to serialize to JSON: %s\n%s', err, result) raise HTTPInternalServerError response = web.Response( diff --git a/homeassistant/components/websocket_api/http.py b/homeassistant/components/websocket_api/http.py index 13be503a009..42c2c0a5751 100644 --- a/homeassistant/components/websocket_api/http.py +++ b/homeassistant/components/websocket_api/http.py @@ -13,11 +13,12 @@ from homeassistant.core import callback from homeassistant.components.http import HomeAssistantView from homeassistant.helpers.json import JSONEncoder -from .const import MAX_PENDING_MSG, CANCELLATION_ERRORS, URL +from .const import MAX_PENDING_MSG, CANCELLATION_ERRORS, URL, ERR_UNKNOWN_ERROR from .auth import AuthPhase, auth_required_message from .error import Disconnect +from .messages import error_message -JSON_DUMP = partial(json.dumps, cls=JSONEncoder) +JSON_DUMP = partial(json.dumps, cls=JSONEncoder, allow_nan=False) class WebsocketAPIView(HomeAssistantView): @@ -58,9 +59,12 @@ class WebSocketHandler: self._logger.debug("Sending %s", message) try: await self.wsock.send_json(message, dumps=JSON_DUMP) - except TypeError as err: + except (ValueError, TypeError) as err: self._logger.error('Unable to serialize to JSON: %s\n%s', err, message) + await self.wsock.send_json(error_message( + message['id'], ERR_UNKNOWN_ERROR, + 'Invalid JSON in response')) @callback def _send_message(self, message): diff --git a/tests/components/http/test_view.py b/tests/components/http/test_view.py index ac0e23edd64..ed97af9c764 100644 --- a/tests/components/http/test_view.py +++ b/tests/components/http/test_view.py @@ -10,6 +10,6 @@ async def test_invalid_json(caplog): view = HomeAssistantView() with pytest.raises(HTTPInternalServerError): - view.json(object) + view.json(float("NaN")) - assert str(object) in caplog.text + assert str(float("NaN")) in caplog.text diff --git a/tests/components/websocket_api/test_commands.py b/tests/components/websocket_api/test_commands.py index b83d4051356..dc9d0318fd1 100644 --- a/tests/components/websocket_api/test_commands.py +++ b/tests/components/websocket_api/test_commands.py @@ -300,3 +300,19 @@ async def test_states_filters_visible(hass, hass_admin_user, websocket_client): assert len(msg['result']) == 1 assert msg['result'][0]['entity_id'] == 'test.entity' + + +async def test_get_states_not_allows_nan(hass, websocket_client): + """Test get_states command not allows NaN floats.""" + hass.states.async_set('greeting.hello', 'world', { + 'hello': float("NaN") + }) + + await websocket_client.send_json({ + 'id': 5, + 'type': commands.TYPE_GET_STATES, + }) + + msg = await websocket_client.receive_json() + assert not msg['success'] + assert msg['error']['code'] == const.ERR_UNKNOWN_ERROR