mirror of
https://github.com/home-assistant/core.git
synced 2025-07-17 10:17:09 +00:00
Fix API POST endpoints json parsing error-handling (#134326)
* Fix API POST endpoints json parsing error-handling * Add tests * Fix mypy and ruff errors * Fix coverage by removing non-needed error handling * Correct error handling and improve tests --------- Co-authored-by: Robert Resch <robert@resch.dev> Co-authored-by: Erik <erik@montnemery.com>
This commit is contained in:
parent
809aced9cc
commit
e210681751
@ -260,11 +260,18 @@ class APIEntityStateView(HomeAssistantView):
|
|||||||
if not user.is_admin:
|
if not user.is_admin:
|
||||||
raise Unauthorized(entity_id=entity_id)
|
raise Unauthorized(entity_id=entity_id)
|
||||||
hass = request.app[KEY_HASS]
|
hass = request.app[KEY_HASS]
|
||||||
|
|
||||||
|
body = await request.text()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
data = await request.json()
|
data: Any = json_loads(body) if body else None
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return self.json_message("Invalid JSON specified.", HTTPStatus.BAD_REQUEST)
|
return self.json_message("Invalid JSON specified.", HTTPStatus.BAD_REQUEST)
|
||||||
|
|
||||||
|
if not isinstance(data, dict):
|
||||||
|
return self.json_message(
|
||||||
|
"State data should be a JSON object.", HTTPStatus.BAD_REQUEST
|
||||||
|
)
|
||||||
if (new_state := data.get("state")) is None:
|
if (new_state := data.get("state")) is None:
|
||||||
return self.json_message("No state specified.", HTTPStatus.BAD_REQUEST)
|
return self.json_message("No state specified.", HTTPStatus.BAD_REQUEST)
|
||||||
|
|
||||||
@ -477,9 +484,19 @@ class APITemplateView(HomeAssistantView):
|
|||||||
@require_admin
|
@require_admin
|
||||||
async def post(self, request: web.Request) -> web.Response:
|
async def post(self, request: web.Request) -> web.Response:
|
||||||
"""Render a template."""
|
"""Render a template."""
|
||||||
|
body = await request.text()
|
||||||
|
|
||||||
|
try:
|
||||||
|
data: Any = json_loads(body) if body else None
|
||||||
|
except ValueError:
|
||||||
|
return self.json_message("Invalid JSON specified.", HTTPStatus.BAD_REQUEST)
|
||||||
|
|
||||||
|
if not isinstance(data, dict):
|
||||||
|
return self.json_message(
|
||||||
|
"Template data should be a JSON object.", HTTPStatus.BAD_REQUEST
|
||||||
|
)
|
||||||
|
tpl = _cached_template(data["template"], request.app[KEY_HASS])
|
||||||
try:
|
try:
|
||||||
data = await request.json()
|
|
||||||
tpl = _cached_template(data["template"], request.app[KEY_HASS])
|
|
||||||
return tpl.async_render(variables=data.get("variables"), parse_result=False) # type: ignore[no-any-return]
|
return tpl.async_render(variables=data.get("variables"), parse_result=False) # type: ignore[no-any-return]
|
||||||
except (ValueError, TemplateError) as ex:
|
except (ValueError, TemplateError) as ex:
|
||||||
return self.json_message(
|
return self.json_message(
|
||||||
|
@ -129,6 +129,28 @@ async def test_api_state_change_with_bad_data(
|
|||||||
assert resp.status == HTTPStatus.BAD_REQUEST
|
assert resp.status == HTTPStatus.BAD_REQUEST
|
||||||
|
|
||||||
|
|
||||||
|
async def test_api_state_change_with_invalid_json(
|
||||||
|
hass: HomeAssistant, mock_api_client: TestClient
|
||||||
|
) -> None:
|
||||||
|
"""Test if API sends appropriate error if send invalid json data."""
|
||||||
|
resp = await mock_api_client.post("/api/states/test.test", data="{,}")
|
||||||
|
|
||||||
|
assert resp.status == HTTPStatus.BAD_REQUEST
|
||||||
|
assert await resp.json() == {"message": "Invalid JSON specified."}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_api_state_change_with_string_body(
|
||||||
|
hass: HomeAssistant, mock_api_client: TestClient
|
||||||
|
) -> None:
|
||||||
|
"""Test if API sends appropriate error if we send a string instead of a JSON object."""
|
||||||
|
resp = await mock_api_client.post(
|
||||||
|
"/api/states/bad.entity.id", json='"{"state": "new_state"}"'
|
||||||
|
)
|
||||||
|
|
||||||
|
assert resp.status == HTTPStatus.BAD_REQUEST
|
||||||
|
assert await resp.json() == {"message": "State data should be a JSON object."}
|
||||||
|
|
||||||
|
|
||||||
async def test_api_state_change_to_zero_value(
|
async def test_api_state_change_to_zero_value(
|
||||||
hass: HomeAssistant, mock_api_client: TestClient
|
hass: HomeAssistant, mock_api_client: TestClient
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -529,6 +551,31 @@ async def test_api_template_error(
|
|||||||
assert resp.status == HTTPStatus.BAD_REQUEST
|
assert resp.status == HTTPStatus.BAD_REQUEST
|
||||||
|
|
||||||
|
|
||||||
|
async def test_api_template_with_invalid_json(
|
||||||
|
hass: HomeAssistant, mock_api_client: TestClient
|
||||||
|
) -> None:
|
||||||
|
"""Test if API sends appropriate error if send invalid json data."""
|
||||||
|
resp = await mock_api_client.post(const.URL_API_TEMPLATE, data="{,}")
|
||||||
|
|
||||||
|
assert resp.status == HTTPStatus.BAD_REQUEST
|
||||||
|
assert await resp.json() == {"message": "Invalid JSON specified."}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_api_template_error_with_string_body(
|
||||||
|
hass: HomeAssistant, mock_api_client: TestClient
|
||||||
|
) -> None:
|
||||||
|
"""Test that the API returns an appropriate error when a string is sent in the body."""
|
||||||
|
hass.states.async_set("sensor.temperature", 10)
|
||||||
|
|
||||||
|
resp = await mock_api_client.post(
|
||||||
|
const.URL_API_TEMPLATE,
|
||||||
|
json='"{"template": "{{ states.sensor.temperature.state"}"',
|
||||||
|
)
|
||||||
|
|
||||||
|
assert resp.status == HTTPStatus.BAD_REQUEST
|
||||||
|
assert await resp.json() == {"message": "Template data should be a JSON object."}
|
||||||
|
|
||||||
|
|
||||||
async def test_stream(hass: HomeAssistant, mock_api_client: TestClient) -> None:
|
async def test_stream(hass: HomeAssistant, mock_api_client: TestClient) -> None:
|
||||||
"""Test the stream."""
|
"""Test the stream."""
|
||||||
listen_count = _listen_count(hass)
|
listen_count = _listen_count(hass)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user