From 0e7a2f163c6c819981c7eb26fa945531402753cc Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Tue, 16 Apr 2019 00:27:13 +0200 Subject: [PATCH 1/2] Fix ingress bug with Firefox (#23121) * Fix ingress bug with Firefox * Fix mock * Fix tests * Fix test lint --- homeassistant/components/hassio/ingress.py | 6 +- homeassistant/components/http/view.py | 3 +- tests/components/hassio/test_ingress.py | 76 ++++++++++++++++++++-- tests/test_util/aiohttp.py | 6 +- 4 files changed, 81 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/hassio/ingress.py b/homeassistant/components/hassio/ingress.py index f4cc97c385392..0ba83f1ca1bd2 100644 --- a/homeassistant/components/hassio/ingress.py +++ b/homeassistant/components/hassio/ingress.py @@ -65,6 +65,8 @@ async def _handle( post = _handle put = _handle delete = _handle + patch = _handle + options = _handle async def _handle_websocket( self, request: web.Request, token: str, path: str @@ -209,8 +211,8 @@ def _is_websocket(request: web.Request) -> bool: """Return True if request is a websocket.""" headers = request.headers - if headers.get(hdrs.CONNECTION) == "Upgrade" and \ - headers.get(hdrs.UPGRADE) == "websocket": + if "upgrade" in headers.get(hdrs.CONNECTION, "").lower() and \ + headers.get(hdrs.UPGRADE, "").lower() == "websocket": return True return False diff --git a/homeassistant/components/http/view.py b/homeassistant/components/http/view.py index 8d5e0ee88b136..ea9ca6ac31f8e 100644 --- a/homeassistant/components/http/view.py +++ b/homeassistant/components/http/view.py @@ -66,7 +66,8 @@ def register(self, app, router): urls = [self.url] + self.extra_urls routes = [] - for method in ('get', 'post', 'delete', 'put'): + for method in ('get', 'post', 'delete', 'put', 'patch', 'head', + 'options'): handler = getattr(self, method, None) if not handler: diff --git a/tests/components/hassio/test_ingress.py b/tests/components/hassio/test_ingress.py index 343068375decd..b4699dfbf8c5e 100644 --- a/tests/components/hassio/test_ingress.py +++ b/tests/components/hassio/test_ingress.py @@ -1,7 +1,6 @@ """The tests for the hassio component.""" from aiohttp.hdrs import X_FORWARDED_FOR, X_FORWARDED_HOST, X_FORWARDED_PROTO -from aiohttp.client_exceptions import WSServerHandshakeError import pytest @@ -137,6 +136,72 @@ async def test_ingress_request_delete( assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_PROTO] +@pytest.mark.parametrize( + 'build_type', [ + ("a3_vl", "test/beer/ping?index=1"), ("core", "index.html"), + ("local", "panel/config"), ("jk_921", "editor.php?idx=3&ping=5"), + ("fsadjf10312", "") + ]) +async def test_ingress_request_patch( + hassio_client, build_type, aioclient_mock): + """Test no auth needed for .""" + aioclient_mock.patch("http://127.0.0.1/ingress/{}/{}".format( + build_type[0], build_type[1]), text="test") + + resp = await hassio_client.patch( + '/api/hassio_ingress/{}/{}'.format(build_type[0], build_type[1]), + headers={"X-Test-Header": "beer"} + ) + + # Check we got right response + assert resp.status == 200 + body = await resp.text() + assert body == "test" + + # Check we forwarded command + assert len(aioclient_mock.mock_calls) == 1 + assert aioclient_mock.mock_calls[-1][3]["X-Hassio-Key"] == "123456" + assert aioclient_mock.mock_calls[-1][3]["X-Ingress-Path"] == \ + "/api/hassio_ingress/{}".format(build_type[0]) + assert aioclient_mock.mock_calls[-1][3]["X-Test-Header"] == "beer" + assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_FOR] + assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_HOST] + assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_PROTO] + + +@pytest.mark.parametrize( + 'build_type', [ + ("a3_vl", "test/beer/ping?index=1"), ("core", "index.html"), + ("local", "panel/config"), ("jk_921", "editor.php?idx=3&ping=5"), + ("fsadjf10312", "") + ]) +async def test_ingress_request_options( + hassio_client, build_type, aioclient_mock): + """Test no auth needed for .""" + aioclient_mock.options("http://127.0.0.1/ingress/{}/{}".format( + build_type[0], build_type[1]), text="test") + + resp = await hassio_client.options( + '/api/hassio_ingress/{}/{}'.format(build_type[0], build_type[1]), + headers={"X-Test-Header": "beer"} + ) + + # Check we got right response + assert resp.status == 200 + body = await resp.text() + assert body == "test" + + # Check we forwarded command + assert len(aioclient_mock.mock_calls) == 1 + assert aioclient_mock.mock_calls[-1][3]["X-Hassio-Key"] == "123456" + assert aioclient_mock.mock_calls[-1][3]["X-Ingress-Path"] == \ + "/api/hassio_ingress/{}".format(build_type[0]) + assert aioclient_mock.mock_calls[-1][3]["X-Test-Header"] == "beer" + assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_FOR] + assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_HOST] + assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_PROTO] + + @pytest.mark.parametrize( 'build_type', [ ("a3_vl", "test/beer/ws"), ("core", "ws.php"), @@ -150,11 +215,10 @@ async def test_ingress_websocket( build_type[0], build_type[1])) # Ignore error because we can setup a full IO infrastructure - with pytest.raises(WSServerHandshakeError): - await hassio_client.ws_connect( - '/api/hassio_ingress/{}/{}'.format(build_type[0], build_type[1]), - headers={"X-Test-Header": "beer"} - ) + await hassio_client.ws_connect( + '/api/hassio_ingress/{}/{}'.format(build_type[0], build_type[1]), + headers={"X-Test-Header": "beer"} + ) # Check we forwarded command assert len(aioclient_mock.mock_calls) == 1 diff --git a/tests/test_util/aiohttp.py b/tests/test_util/aiohttp.py index ab759f03058f1..8c4a2073ad833 100644 --- a/tests/test_util/aiohttp.py +++ b/tests/test_util/aiohttp.py @@ -82,6 +82,10 @@ def options(self, *args, **kwargs): """Register a mock options request.""" self.request('options', *args, **kwargs) + def patch(self, *args, **kwargs): + """Register a mock patch request.""" + self.request('patch', *args, **kwargs) + @property def call_count(self): """Return the number of requests made.""" @@ -102,7 +106,7 @@ def create_session(self, loop): async def match_request(self, method, url, *, data=None, auth=None, params=None, headers=None, allow_redirects=None, - timeout=None, json=None, cookies=None): + timeout=None, json=None, cookies=None, **kwargs): """Match a request against pre-registered requests.""" data = data or json url = URL(url) From c90219ad2e53a798ecbd11cfb91c250ea90723ed Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Tue, 16 Apr 2019 08:47:36 +0000 Subject: [PATCH 2/2] Bumped version to 0.91.4 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 6a8a7fe6a1d01..caaee0a8af162 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 91 -PATCH_VERSION = '3' +PATCH_VERSION = '4' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3)