40 lines
1.9 KiB
Python
40 lines
1.9 KiB
Python
"""Resolve the application-relative request path behind a reverse proxy.
|
|
|
|
A reverse proxy may forward requests under a path prefix, e.g.
|
|
``/xxx/api/v1/auth/login/token``. FastAPI strips that prefix for **routing**
|
|
when it is told about it via the ASGI ``root_path`` (uvicorn ``--root-path`` /
|
|
``--proxy-headers``, or ``X-Forwarded-Prefix`` from the proxy) — which is why
|
|
the route still matches and the request reaches a handler.
|
|
|
|
Starlette middleware, however, runs *before* routing and sees the full,
|
|
prefixed ``request.url.path``. Middlewares that match that raw path against
|
|
fixed whitelists — the CSRF-exempt auth paths and the AuthMiddleware public
|
|
paths — then mis-match, so login and ``/api/public/*`` endpoints get wrongly
|
|
rejected (``CSRF token missing`` / ``401``) on a prefixed deployment.
|
|
|
|
``app_relative_path`` returns the path with the proxy prefix removed so that
|
|
whitelist matching is prefix-agnostic. It is a no-op when no prefix is present
|
|
(direct deployment), and tolerates the prefix already being stripped from the
|
|
path (it only strips when the path actually starts with the prefix).
|
|
"""
|
|
|
|
from fastapi import Request
|
|
|
|
|
|
def app_relative_path(request: Request) -> str:
|
|
"""Return ``request.url.path`` with any reverse-proxy prefix removed.
|
|
|
|
Prefix source order: ASGI ``root_path`` (set by the server when the proxy
|
|
forwards it), then the ``X-Forwarded-Prefix`` header (proxies that add a
|
|
prefix without informing the ASGI server). Returns ``"/"`` for an empty
|
|
result so downstream ``rstrip("/")`` / ``startswith`` checks stay sane.
|
|
"""
|
|
path = request.url.path or "/"
|
|
prefix = (request.scope.get("root_path") or request.headers.get("x-forwarded-prefix") or "").rstrip("/")
|
|
if prefix and path.startswith(prefix):
|
|
stripped = path[len(prefix):]
|
|
if not stripped:
|
|
return "/"
|
|
return stripped if stripped.startswith("/") else "/" + stripped
|
|
return path
|