Home Assistant Unofficial Reference 2024.12.1
static.py
Go to the documentation of this file.
1 """Static file handling for HTTP component."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Mapping
6 from pathlib import Path
7 import sys
8 from typing import Final
9 
10 from aiohttp.hdrs import CACHE_CONTROL, CONTENT_TYPE
11 from aiohttp.web import FileResponse, Request, StreamResponse
12 from aiohttp.web_fileresponse import CONTENT_TYPES, FALLBACK_CONTENT_TYPE
13 from aiohttp.web_urldispatcher import StaticResource
14 from lru import LRU
15 
16 CACHE_TIME: Final = 31 * 86400 # = 1 month
17 CACHE_HEADER = f"public, max-age={CACHE_TIME}"
18 CACHE_HEADERS: Mapping[str, str] = {CACHE_CONTROL: CACHE_HEADER}
19 RESPONSE_CACHE: LRU[tuple[str, Path], tuple[Path, str]] = LRU(512)
20 
21 if sys.version_info >= (3, 13):
22  # guess_type is soft-deprecated in 3.13
23  # for paths and should only be used for
24  # URLs. guess_file_type should be used
25  # for paths instead.
26  _GUESSER = CONTENT_TYPES.guess_file_type
27 else:
28  _GUESSER = CONTENT_TYPES.guess_type
29 
30 
31 class CachingStaticResource(StaticResource):
32  """Static Resource handler that will add cache headers."""
33 
34  async def _handle(self, request: Request) -> StreamResponse:
35  """Wrap base handler to cache file path resolution and content type guess."""
36  rel_url = request.match_info["filename"]
37  key = (rel_url, self._directory)
38  response: StreamResponse
39 
40  if key in RESPONSE_CACHE:
41  file_path, content_type = RESPONSE_CACHE[key]
42  response = FileResponse(file_path, chunk_size=self._chunk_size)
43  response.headers[CONTENT_TYPE] = content_type
44  else:
45  response = await super()._handle(request)
46  if not isinstance(response, FileResponse):
47  # Must be directory index; ignore caching
48  return response
49  file_path = response._path # noqa: SLF001
50  response.content_type = _GUESSER(file_path)[0] or FALLBACK_CONTENT_TYPE
51  # Cache actual header after setter construction.
52  content_type = response.headers[CONTENT_TYPE]
53  RESPONSE_CACHE[key] = (file_path, content_type)
54 
55  response.headers[CACHE_CONTROL] = CACHE_HEADER
56  return response
StreamResponse _handle(self, Request request)
Definition: static.py:34