Skip to content

Commit

Permalink
Refactor http CachingStaticResource (#21062)
Browse files Browse the repository at this point in the history
* 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 pylint-dev/astroid#633 (comment)

* Remove pylint ignore

* Ignore pylint duplicate-base warning
  • Loading branch information
awarecan authored and balloob committed Feb 15, 2019
1 parent 383813b commit 46efc0e
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 30 deletions.
5 changes: 2 additions & 3 deletions homeassistant/components/http/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,12 @@
from homeassistant.util import ssl as ssl_util
from homeassistant.util.logging import HideSensitiveDataFilter

# Import as alias
from .auth import setup_auth
from .ban import setup_bans
from .const import KEY_AUTHENTICATED, KEY_REAL_IP # noqa
from .cors import setup_cors
from .real_ip import setup_real_ip
from .static import CachingFileResponse, CachingStaticResource
from .static import CACHE_HEADERS, CachingStaticResource
from .view import HomeAssistantView # noqa

REQUIREMENTS = ['aiohttp_cors==0.7.0']
Expand Down Expand Up @@ -272,7 +271,7 @@ def register_static_path(self, url_path, path, cache_headers=True):
if cache_headers:
async def serve_file(request):
"""Serve file from disk."""
return CachingFileResponse(path)
return web.FileResponse(path, headers=CACHE_HEADERS)
else:
async def serve_file(request):
"""Serve file from disk."""
Expand Down
45 changes: 18 additions & 27 deletions homeassistant/components/http/static.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
"""Static file handling for HTTP component."""
from pathlib import Path

from aiohttp import hdrs
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 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):
"""Static Resource handler that will add cache headers."""

async def _handle(self, request):
filename = URL(request.match_info['filename']).path
rel_url = request.match_info['filename']
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()
if not self._follow_symlinks:
filepath.relative_to(self._directory)
Expand All @@ -24,30 +35,10 @@ async def _handle(self, request):
request.app.logger.exception(error)
raise HTTPNotFound() from error

# on opening a dir, load its contents if allowed
if filepath.is_dir():
return await super()._handle(request)
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


# 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

0 comments on commit 46efc0e

Please sign in to comment.