From 823ee5a6c773fe74978258e308af2fe64e899cf0 Mon Sep 17 00:00:00 2001 From: Matthias Portzel Date: Mon, 11 Apr 2022 18:30:12 -0400 Subject: [PATCH] Add Middleware to remove slashes --- whispermaphone/middleware.py | 38 ++++++++++++++++++++++++++++++++++++ whispermaphone/settings.py | 3 +++ 2 files changed, 41 insertions(+) create mode 100644 whispermaphone/middleware.py diff --git a/whispermaphone/middleware.py b/whispermaphone/middleware.py new file mode 100644 index 0000000..e742797 --- /dev/null +++ b/whispermaphone/middleware.py @@ -0,0 +1,38 @@ +import re + +from django import http +from django.conf import settings +from django.urls import is_valid_path +from django.core.exceptions import ImproperlyConfigured +from django.utils.deprecation import MiddlewareMixin + + +class RemoveSlashMiddleware(MiddlewareMixin): + def process_request(self, request): + if getattr(settings, "APPEND_SLASH") and getattr(settings, "REMOVE_SLASH"): + raise ImproperlyConfigured("APPEND_SLASH and REMOVE_SLASH may not both be True.") + + old_url = request.path_info # path_info only includes path, query information + if getattr(settings, "REMOVE_SLASH", False) and old_url[-1] == "/": + urlconf = getattr(request, "urlconf", None) + + new_url = old_url[:-1] + + # If the url with a / would 404 and without a slash wouldn't + if (not is_valid_path(old_url, urlconf)) and is_valid_path(new_url, urlconf): + if settings.DEBUG and request.method == "POST": + if old_url.startswith("/api/"): + return api.error("You made a POST request to a URL ending with a slash. Please repeat your request without the slash.") + + raise RuntimeError("" + "You called this URL via POST, but the URL ends in a " + "slash and you have REMOVE_SLASH set. Django can't " + "redirect to the non-slash URL while maintaining POST " + f"data. Change your form to point to {new_url} (without a " + "trailing slash), or set REMOVE_SLASH=False in your " + "Django settings.") + + # The ? and everything after + query_data = re.match(r"^[^?]*(\?.*)?$", request.build_absolute_uri()).group(1) or "" + + return http.HttpResponsePermanentRedirect(new_url + query_data) diff --git a/whispermaphone/settings.py b/whispermaphone/settings.py index 9e30feb..bf3a39d 100644 --- a/whispermaphone/settings.py +++ b/whispermaphone/settings.py @@ -64,6 +64,7 @@ MIDDLEWARE = [ "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", + "whispermaphone.middleware.RemoveSlashMiddleware", ] CSRF_COOKIE_SECURE = False @@ -113,6 +114,8 @@ USE_L10N = True USE_TZ = True +APPEND_SLASH = False +REMOVE_SLASH = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.1/howto/static-files/