File size: 1,550 Bytes
0a54372
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
"""Admin response cache policy."""

from fastapi import Response
from starlette.datastructures import MutableHeaders
from starlette.types import ASGIApp, Message, Receive, Scope, Send

_ADMIN_CACHE_CONTROL = "no-store"


class AdminNoStoreMiddleware:
    """Prevent browsers from retaining responses from the admin surface."""

    def __init__(self, app: ASGIApp) -> None:
        self._app = app

    async def __call__(
        self,
        scope: Scope,
        receive: Receive,
        send: Send,
    ) -> None:
        path = scope.get("path", "")
        if scope["type"] != "http" or not _is_admin_path(path):
            await self._app(scope, receive, send)
            return

        async def send_without_cache(message: Message) -> None:
            if message["type"] == "http.response.start":
                message = dict(message)
                raw_headers = list(message.get("headers", ()))
                _set_no_store(MutableHeaders(raw=raw_headers))
                message["headers"] = raw_headers
            await send(message)

        await self._app(scope, receive, send_without_cache)


def attach_admin_no_store(response: Response, *, path: str) -> None:
    """Attach the policy when an outer server-error boundary bypasses middleware."""
    if _is_admin_path(path):
        _set_no_store(response.headers)


def _is_admin_path(path: str) -> bool:
    return path == "/admin" or path.startswith("/admin/")


def _set_no_store(headers: MutableHeaders) -> None:
    headers["Cache-Control"] = _ADMIN_CACHE_CONTROL