30 lines
1.3 KiB
Python
30 lines
1.3 KiB
Python
from collections.abc import Callable
|
|
|
|
from django.http import HttpRequest, HttpResponse
|
|
|
|
|
|
class ScriptPrefixPathMiddleware:
|
|
"""Re-add the ``FORCE_SCRIPT_NAME`` prefix to ``request.path`` under ASGI.
|
|
|
|
Django's ASGI handler sets ``request.path = scope["path"]`` verbatim (see
|
|
``django/core/handlers/asgi.py``). When the reverse proxy strips the
|
|
script-name prefix (e.g. ``/scores``) before forwarding, ``request.path`` —
|
|
and therefore ``get_full_path()`` — loses the prefix, even though
|
|
``reverse()`` still prepends it via the script prefix. The result is the
|
|
admin login form posting to ``/admin/login/?next=/admin/`` instead of
|
|
``/scores/admin/login/?next=/scores/admin/``.
|
|
|
|
URL resolution is unaffected (it uses ``path_info``), so we only need to
|
|
realign the path-based URLs with the reverse()-based ones. The check is
|
|
idempotent: if the proxy already forwards the prefix, this is a no-op.
|
|
"""
|
|
|
|
def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]) -> None:
|
|
self.get_response = get_response
|
|
|
|
def __call__(self, request: HttpRequest) -> HttpResponse:
|
|
script_name = request.META.get("SCRIPT_NAME", "").rstrip("/")
|
|
if script_name and not request.path.startswith(f"{script_name}/"):
|
|
request.path = f"{script_name}{request.path}"
|
|
return self.get_response(request)
|