Hass.io: logo support / timeout handling (#8668)

* Disable auth on logo / no timeout for addons update/install

* fix tests
This commit is contained in:
Pascal Vizeli 2017-07-27 21:23:22 +02:00 committed by Paulus Schoutsen
parent 9e6817b6d0
commit 51108b8fe9
2 changed files with 51 additions and 6 deletions

View file

@ -25,8 +25,15 @@ _LOGGER = logging.getLogger(__name__)
DOMAIN = 'hassio' DOMAIN = 'hassio'
DEPENDENCIES = ['http'] DEPENDENCIES = ['http']
TIMEOUT = 10 NO_TIMEOUT = {
NO_TIMEOUT = set(['homeassistant/update', 'host/update', 'supervisor/update']) re.compile(r'^homeassistant/update$'), re.compile(r'^host/update$'),
re.compile(r'^supervisor/update$'), re.compile(r'^addons/[^/]*/update$'),
re.compile(r'^addons/[^/]*/install$')
}
NO_AUTH = {
re.compile(r'^panel$'), re.compile(r'^addons/[^/]*/logo$')
}
@asyncio.coroutine @asyncio.coroutine
@ -71,7 +78,7 @@ class HassIO(object):
This method is a coroutine. This method is a coroutine.
""" """
try: try:
with async_timeout.timeout(TIMEOUT, loop=self.loop): with async_timeout.timeout(10, loop=self.loop):
request = yield from self.websession.get( request = yield from self.websession.get(
"http://{}{}".format(self._ip, "/supervisor/ping") "http://{}{}".format(self._ip, "/supervisor/ping")
) )
@ -97,12 +104,12 @@ class HassIO(object):
This method is a coroutine. This method is a coroutine.
""" """
read_timeout = 0 if path in NO_TIMEOUT else 300 read_timeout = _get_timeout(path)
try: try:
data = None data = None
headers = None headers = None
with async_timeout.timeout(TIMEOUT, loop=self.loop): with async_timeout.timeout(10, loop=self.loop):
data = yield from request.read() data = yield from request.read()
if data: if data:
headers = {CONTENT_TYPE: request.content_type} headers = {CONTENT_TYPE: request.content_type}
@ -140,7 +147,7 @@ class HassIOView(HomeAssistantView):
@asyncio.coroutine @asyncio.coroutine
def _handle(self, request, path): def _handle(self, request, path):
"""Route data to hassio.""" """Route data to hassio."""
if path != 'panel' and not request[KEY_AUTHENTICATED]: if _need_auth(path) and not request[KEY_AUTHENTICATED]:
return web.Response(status=401) return web.Response(status=401)
client = yield from self.hassio.command_proxy(path, request) client = yield from self.hassio.command_proxy(path, request)
@ -173,3 +180,19 @@ def _create_response_log(client, data):
status=client.status, status=client.status,
content_type=CONTENT_TYPE_TEXT_PLAIN, content_type=CONTENT_TYPE_TEXT_PLAIN,
) )
def _get_timeout(path):
"""Return timeout for a url path."""
for re_path in NO_TIMEOUT:
if re_path.match(path):
return 0
return 300
def _need_auth(path):
"""Return if a path need a auth."""
for re_path in NO_AUTH:
if re_path.match(path):
return False
return True

View file

@ -106,6 +106,28 @@ def test_forward_request_no_auth_for_panel(hassio_client):
assert mresp.mock_calls[0][1] == (response, 'data') assert mresp.mock_calls[0][1] == (response, 'data')
@asyncio.coroutine
def test_forward_request_no_auth_for_logo(hassio_client):
"""Test no auth needed for ."""
response = MagicMock()
response.read.return_value = mock_coro('data')
with patch('homeassistant.components.hassio.HassIO.command_proxy',
Mock(return_value=mock_coro(response))), \
patch('homeassistant.components.hassio._create_response') as mresp:
mresp.return_value = 'response'
resp = yield from hassio_client.get('/api/hassio/addons/bl_b392/logo')
# Check we got right response
assert resp.status == 200
body = yield from resp.text()
assert body == 'response'
# Check we forwarded command
assert len(mresp.mock_calls) == 1
assert mresp.mock_calls[0][1] == (response, 'data')
@asyncio.coroutine @asyncio.coroutine
def test_forward_log_request(hassio_client): def test_forward_log_request(hassio_client):
"""Test fetching normal log path.""" """Test fetching normal log path."""