49 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			49 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			Python
		
	
	
"""Static file handling for HTTP component."""
 | 
						|
from pathlib import Path
 | 
						|
 | 
						|
from aiohttp import hdrs
 | 
						|
from aiohttp.web import FileResponse
 | 
						|
from aiohttp.web_exceptions import HTTPForbidden, HTTPNotFound
 | 
						|
from aiohttp.web_urldispatcher import StaticResource
 | 
						|
 | 
						|
# mypy: allow-untyped-defs
 | 
						|
 | 
						|
CACHE_TIME = 31 * 86400  # = 1 month
 | 
						|
CACHE_HEADERS = {hdrs.CACHE_CONTROL: f"public, max-age={CACHE_TIME}"}
 | 
						|
 | 
						|
 | 
						|
class CachingStaticResource(StaticResource):
 | 
						|
    """Static Resource handler that will add cache headers."""
 | 
						|
 | 
						|
    async def _handle(self, request):
 | 
						|
        rel_url = request.match_info["filename"]
 | 
						|
        try:
 | 
						|
            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)
 | 
						|
        except (ValueError, FileNotFoundError) as error:
 | 
						|
            # relatively safe
 | 
						|
            raise HTTPNotFound() from error
 | 
						|
        except Exception as error:
 | 
						|
            # perm error or other kind!
 | 
						|
            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 FileResponse(
 | 
						|
                filepath,
 | 
						|
                chunk_size=self._chunk_size,
 | 
						|
                # type ignore: https://github.com/aio-libs/aiohttp/pull/3976
 | 
						|
                headers=CACHE_HEADERS,  # type: ignore
 | 
						|
            )
 | 
						|
        raise HTTPNotFound
 |