Fix ingress bug with Firefox (#23121)
* Fix ingress bug with Firefox * Fix mock * Fix tests * Fix test lint
This commit is contained in:
parent
60c787c2e6
commit
7a78d65633
4 changed files with 81 additions and 10 deletions
|
@ -65,6 +65,8 @@ class HassIOIngress(HomeAssistantView):
|
||||||
post = _handle
|
post = _handle
|
||||||
put = _handle
|
put = _handle
|
||||||
delete = _handle
|
delete = _handle
|
||||||
|
patch = _handle
|
||||||
|
options = _handle
|
||||||
|
|
||||||
async def _handle_websocket(
|
async def _handle_websocket(
|
||||||
self, request: web.Request, token: str, path: str
|
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."""
|
"""Return True if request is a websocket."""
|
||||||
headers = request.headers
|
headers = request.headers
|
||||||
|
|
||||||
if headers.get(hdrs.CONNECTION) == "Upgrade" and \
|
if "upgrade" in headers.get(hdrs.CONNECTION, "").lower() and \
|
||||||
headers.get(hdrs.UPGRADE) == "websocket":
|
headers.get(hdrs.UPGRADE, "").lower() == "websocket":
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,8 @@ class HomeAssistantView:
|
||||||
urls = [self.url] + self.extra_urls
|
urls = [self.url] + self.extra_urls
|
||||||
routes = []
|
routes = []
|
||||||
|
|
||||||
for method in ('get', 'post', 'delete', 'put'):
|
for method in ('get', 'post', 'delete', 'put', 'patch', 'head',
|
||||||
|
'options'):
|
||||||
handler = getattr(self, method, None)
|
handler = getattr(self, method, None)
|
||||||
|
|
||||||
if not handler:
|
if not handler:
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
"""The tests for the hassio component."""
|
"""The tests for the hassio component."""
|
||||||
|
|
||||||
from aiohttp.hdrs import X_FORWARDED_FOR, X_FORWARDED_HOST, X_FORWARDED_PROTO
|
from aiohttp.hdrs import X_FORWARDED_FOR, X_FORWARDED_HOST, X_FORWARDED_PROTO
|
||||||
from aiohttp.client_exceptions import WSServerHandshakeError
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@ -137,6 +136,72 @@ async def test_ingress_request_delete(
|
||||||
assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_PROTO]
|
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(
|
@pytest.mark.parametrize(
|
||||||
'build_type', [
|
'build_type', [
|
||||||
("a3_vl", "test/beer/ws"), ("core", "ws.php"),
|
("a3_vl", "test/beer/ws"), ("core", "ws.php"),
|
||||||
|
@ -150,11 +215,10 @@ async def test_ingress_websocket(
|
||||||
build_type[0], build_type[1]))
|
build_type[0], build_type[1]))
|
||||||
|
|
||||||
# Ignore error because we can setup a full IO infrastructure
|
# Ignore error because we can setup a full IO infrastructure
|
||||||
with pytest.raises(WSServerHandshakeError):
|
await hassio_client.ws_connect(
|
||||||
await hassio_client.ws_connect(
|
'/api/hassio_ingress/{}/{}'.format(build_type[0], build_type[1]),
|
||||||
'/api/hassio_ingress/{}/{}'.format(build_type[0], build_type[1]),
|
headers={"X-Test-Header": "beer"}
|
||||||
headers={"X-Test-Header": "beer"}
|
)
|
||||||
)
|
|
||||||
|
|
||||||
# Check we forwarded command
|
# Check we forwarded command
|
||||||
assert len(aioclient_mock.mock_calls) == 1
|
assert len(aioclient_mock.mock_calls) == 1
|
||||||
|
|
|
@ -82,6 +82,10 @@ class AiohttpClientMocker:
|
||||||
"""Register a mock options request."""
|
"""Register a mock options request."""
|
||||||
self.request('options', *args, **kwargs)
|
self.request('options', *args, **kwargs)
|
||||||
|
|
||||||
|
def patch(self, *args, **kwargs):
|
||||||
|
"""Register a mock patch request."""
|
||||||
|
self.request('patch', *args, **kwargs)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def call_count(self):
|
def call_count(self):
|
||||||
"""Return the number of requests made."""
|
"""Return the number of requests made."""
|
||||||
|
@ -102,7 +106,7 @@ class AiohttpClientMocker:
|
||||||
|
|
||||||
async def match_request(self, method, url, *, data=None, auth=None,
|
async def match_request(self, method, url, *, data=None, auth=None,
|
||||||
params=None, headers=None, allow_redirects=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."""
|
"""Match a request against pre-registered requests."""
|
||||||
data = data or json
|
data = data or json
|
||||||
url = URL(url)
|
url = URL(url)
|
||||||
|
|
Loading…
Add table
Reference in a new issue