diff --git a/homeassistant/components/rest_command/__init__.py b/homeassistant/components/rest_command/__init__.py index 81e63371717..bf51fc2692d 100644 --- a/homeassistant/components/rest_command/__init__.py +++ b/homeassistant/components/rest_command/__init__.py @@ -10,6 +10,7 @@ from typing import Any import aiohttp from aiohttp import hdrs import voluptuous as vol +from yarl import URL from homeassistant.const import ( CONF_AUTHENTICATION, @@ -51,6 +52,7 @@ SUPPORT_REST_METHODS = ["get", "patch", "post", "put", "delete"] CONF_CONTENT_TYPE = "content_type" CONF_INSECURE_CIPHER = "insecure_cipher" +CONF_SKIP_URL_ENCODING = "skip_url_encoding" COMMAND_SCHEMA = vol.Schema( { @@ -69,6 +71,7 @@ COMMAND_SCHEMA = vol.Schema( vol.Optional(CONF_CONTENT_TYPE): cv.string, vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): cv.boolean, vol.Optional(CONF_INSECURE_CIPHER, default=False): cv.boolean, + vol.Optional(CONF_SKIP_URL_ENCODING, default=False): cv.boolean, } ) @@ -113,6 +116,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: method = command_config[CONF_METHOD] template_url = command_config[CONF_URL] + skip_url_encoding = command_config[CONF_SKIP_URL_ENCODING] auth = None digest_middleware = None @@ -179,7 +183,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: request_kwargs["middlewares"] = (digest_middleware,) async with getattr(websession, method)( - request_url, + URL(request_url, encoded=skip_url_encoding), **request_kwargs, ) as response: if response.status < HTTPStatus.BAD_REQUEST: diff --git a/tests/components/rest_command/test_init.py b/tests/components/rest_command/test_init.py index 0c8f8a93f65..fdb7c1dd747 100644 --- a/tests/components/rest_command/test_init.py +++ b/tests/components/rest_command/test_init.py @@ -6,6 +6,7 @@ from unittest.mock import patch import aiohttp import pytest +from yarl import URL from homeassistant.components.rest_command import DOMAIN from homeassistant.const import ( @@ -455,3 +456,34 @@ async def test_rest_command_response_iter_chunked( # Verify iter_chunked was called with a chunk size assert mock_iter_chunked.called + + +async def test_rest_command_skip_url_encoding( + hass: HomeAssistant, + setup_component: ComponentSetup, + aioclient_mock: AiohttpClientMocker, +) -> None: + """Check URL encoding.""" + config = { + "skip_url_encoding_test": { + "url": "0%2C", + "method": "get", + "skip_url_encoding": True, + }, + "with_url_encoding_test": { + "url": "1,", + "method": "get", + }, + } + + await setup_component(config) + + aioclient_mock.get(URL("0%2C", encoded=True), content=b"success") + aioclient_mock.get(URL("1,"), content=b"success") + + await hass.services.async_call(DOMAIN, "skip_url_encoding_test", {}, blocking=True) + await hass.services.async_call(DOMAIN, "with_url_encoding_test", {}, blocking=True) + + assert len(aioclient_mock.mock_calls) == 2 + assert str(aioclient_mock.mock_calls[0][1]) == "0%2C" + assert str(aioclient_mock.mock_calls[1][1]) == "1," diff --git a/tests/test_util/aiohttp.py b/tests/test_util/aiohttp.py index c3a8be77b77..687de2ece0b 100644 --- a/tests/test_util/aiohttp.py +++ b/tests/test_util/aiohttp.py @@ -221,8 +221,8 @@ class AiohttpClientMockResponse: if ( self._url.scheme != url.scheme - or self._url.host != url.host - or self._url.path != url.path + or self._url.raw_host != url.raw_host + or self._url.raw_path != url.raw_path ): return False