fix: correct force script name?

This commit is contained in:
Loïc Gremaud 2026-06-20 08:58:19 +02:00
parent bf65dc8be0
commit 03f1e8ea16
Signed by: Legrems
GPG Key ID: D4620E6DF3E0121D
3 changed files with 41 additions and 16 deletions

View File

@ -0,0 +1,29 @@
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)

View File

@ -2,23 +2,18 @@ import subprocess
import sys import sys
from pathlib import Path from pathlib import Path
from app.config import settings as env
def serve() -> None: def serve() -> None:
"""Start the Daphne ASGI server on 0.0.0.0:8080.""" """Start the Daphne ASGI server on 0.0.0.0:8080."""
daphne_path = str(Path(sys.path[0]) / "daphne") daphne_path = str(Path(sys.path[0]) / "daphne")
args = [ subprocess.run( # noqa: S603
[
daphne_path, daphne_path,
"-b", "-b",
"0.0.0.0", # noqa: S104 "0.0.0.0", # noqa: S104
"-p", "-p",
"8080", "8080",
] "app.routing:application",
# FORCE_SCRIPT_NAME is a WSGI-only setting; under ASGI Django derives the URL ],
# script prefix from the scope's root_path. Pass the prefix to Daphne so that check=True,
# reverse()/redirects (e.g. the admin post-login redirect) include it. )
if env.force_script_name:
args += ["--root-path", env.force_script_name.rstrip("/")]
args.append("app.routing:application")
subprocess.run(args, check=True) # noqa: S603

View File

@ -42,6 +42,7 @@ SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
MIDDLEWARE = [ MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware", "django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware", "whitenoise.middleware.WhiteNoiseMiddleware",
"app.middleware.ScriptPrefixPathMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware", "django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware", "django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware", "django.middleware.csrf.CsrfViewMiddleware",