mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Refactor http CachingStaticResource (#21062)
* Simplify http.CachingStaticResource implementation * Sync up CachingStaticResource._handle() implementation from aiohttp * Ignore pylint duplicate-base warning * Try to disable pylint for http/static.py Caused by https://github.com/PyCQA/astroid/issues/633#issuecomment-463879288 * Remove pylint ignore * Ignore pylint duplicate-base warning
This commit is contained in:
parent
383813bfe6
commit
46efc0eafb
@ -16,13 +16,12 @@ import homeassistant.util as hass_util
|
|||||||
from homeassistant.util import ssl as ssl_util
|
from homeassistant.util import ssl as ssl_util
|
||||||
from homeassistant.util.logging import HideSensitiveDataFilter
|
from homeassistant.util.logging import HideSensitiveDataFilter
|
||||||
|
|
||||||
# Import as alias
|
|
||||||
from .auth import setup_auth
|
from .auth import setup_auth
|
||||||
from .ban import setup_bans
|
from .ban import setup_bans
|
||||||
from .const import KEY_AUTHENTICATED, KEY_REAL_IP # noqa
|
from .const import KEY_AUTHENTICATED, KEY_REAL_IP # noqa
|
||||||
from .cors import setup_cors
|
from .cors import setup_cors
|
||||||
from .real_ip import setup_real_ip
|
from .real_ip import setup_real_ip
|
||||||
from .static import CachingFileResponse, CachingStaticResource
|
from .static import CACHE_HEADERS, CachingStaticResource
|
||||||
from .view import HomeAssistantView # noqa
|
from .view import HomeAssistantView # noqa
|
||||||
|
|
||||||
REQUIREMENTS = ['aiohttp_cors==0.7.0']
|
REQUIREMENTS = ['aiohttp_cors==0.7.0']
|
||||||
@ -272,7 +271,7 @@ class HomeAssistantHTTP:
|
|||||||
if cache_headers:
|
if cache_headers:
|
||||||
async def serve_file(request):
|
async def serve_file(request):
|
||||||
"""Serve file from disk."""
|
"""Serve file from disk."""
|
||||||
return CachingFileResponse(path)
|
return web.FileResponse(path, headers=CACHE_HEADERS)
|
||||||
else:
|
else:
|
||||||
async def serve_file(request):
|
async def serve_file(request):
|
||||||
"""Serve file from disk."""
|
"""Serve file from disk."""
|
||||||
|
@ -1,18 +1,29 @@
|
|||||||
"""Static file handling for HTTP component."""
|
"""Static file handling for HTTP component."""
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from aiohttp import hdrs
|
from aiohttp import hdrs
|
||||||
from aiohttp.web import FileResponse
|
from aiohttp.web import FileResponse
|
||||||
from aiohttp.web_exceptions import HTTPNotFound
|
from aiohttp.web_exceptions import HTTPNotFound, HTTPForbidden
|
||||||
from aiohttp.web_urldispatcher import StaticResource
|
from aiohttp.web_urldispatcher import StaticResource
|
||||||
from yarl import URL
|
|
||||||
|
CACHE_TIME = 31 * 86400 # = 1 month
|
||||||
|
CACHE_HEADERS = {hdrs.CACHE_CONTROL: "public, max-age={}".format(CACHE_TIME)}
|
||||||
|
|
||||||
|
|
||||||
|
# https://github.com/PyCQA/astroid/issues/633
|
||||||
|
# pylint: disable=duplicate-bases
|
||||||
class CachingStaticResource(StaticResource):
|
class CachingStaticResource(StaticResource):
|
||||||
"""Static Resource handler that will add cache headers."""
|
"""Static Resource handler that will add cache headers."""
|
||||||
|
|
||||||
async def _handle(self, request):
|
async def _handle(self, request):
|
||||||
filename = URL(request.match_info['filename']).path
|
rel_url = request.match_info['filename']
|
||||||
try:
|
try:
|
||||||
# PyLint is wrong about resolve not being a member.
|
filename = Path(rel_url)
|
||||||
|
if filename.anchor:
|
||||||
|
# rel_url is an absolute name like
|
||||||
|
# /static/\\machine_name\c$ or /static/D:\path
|
||||||
|
# where the static dir is totally different
|
||||||
|
raise HTTPForbidden()
|
||||||
filepath = self._directory.joinpath(filename).resolve()
|
filepath = self._directory.joinpath(filename).resolve()
|
||||||
if not self._follow_symlinks:
|
if not self._follow_symlinks:
|
||||||
filepath.relative_to(self._directory)
|
filepath.relative_to(self._directory)
|
||||||
@ -24,30 +35,10 @@ class CachingStaticResource(StaticResource):
|
|||||||
request.app.logger.exception(error)
|
request.app.logger.exception(error)
|
||||||
raise HTTPNotFound() from error
|
raise HTTPNotFound() from error
|
||||||
|
|
||||||
|
# on opening a dir, load its contents if allowed
|
||||||
if filepath.is_dir():
|
if filepath.is_dir():
|
||||||
return await super()._handle(request)
|
return await super()._handle(request)
|
||||||
if filepath.is_file():
|
if filepath.is_file():
|
||||||
return CachingFileResponse(filepath, chunk_size=self._chunk_size)
|
return FileResponse(
|
||||||
|
filepath, chunk_size=self._chunk_size, headers=CACHE_HEADERS)
|
||||||
raise HTTPNotFound
|
raise HTTPNotFound
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=too-many-ancestors
|
|
||||||
class CachingFileResponse(FileResponse):
|
|
||||||
"""FileSender class that caches output if not in dev mode."""
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
"""Initialize the hass file sender."""
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
orig_sendfile = self._sendfile
|
|
||||||
|
|
||||||
async def sendfile(request, fobj, count):
|
|
||||||
"""Sendfile that includes a cache header."""
|
|
||||||
cache_time = 31 * 86400 # = 1 month
|
|
||||||
self.headers[hdrs.CACHE_CONTROL] = "public, max-age={}".format(
|
|
||||||
cache_time)
|
|
||||||
|
|
||||||
await orig_sendfile(request, fobj, count)
|
|
||||||
|
|
||||||
# Overwriting like this because __init__ can change implementation.
|
|
||||||
self._sendfile = sendfile
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user