-
-
Save Sepero/2204099 to your computer and use it in GitHub Desktop.
""" Author contact: sepero 111 @ gmail . com """ | |
from django import http | |
from django.utils.http import urlquote | |
from django.core import urlresolvers | |
class RemoveSlashMiddleware(object): | |
""" | |
This middleware works like django's built in APPEND_SLASH, but in reverse. Eg | |
It removes all ending slashes from a URL, and if that doesn't resolve, it will add one slash and try again. | |
Set APPEND_SLASH to False when using this middleware. | |
Forked from the original code at http://gregbrown.co.nz/code/append-or-remove-slash/ | |
""" | |
def process_request(self, request): | |
# check if the url is valid | |
path = new_path = request.path_info | |
# Remove all trailing slashes from new_path. | |
while new_path.endswith('/'): | |
new_path = new_path[:-1] | |
urlconf = getattr(request, 'urlconf', None) | |
if not _is_valid_path(new_path, urlconf): | |
# If removing slashes made new_path invalid, add one slash and try again. | |
new_path = new_path + '/' | |
if path != new_path and _is_valid_path(new_path, urlconf): | |
return self.adjust_path(request, new_path) | |
elif path != new_path: | |
# If new_path is valid and not eq to path, send a permanent redirect. | |
return self.adjust_path(request, new_path) | |
def adjust_path(self, request, new_path): | |
""" | |
Redirect the clients browser to new_path, and tell it that all future requests to the desired URL should be sent to new_path. (This method looks like it may be able to be made more efficient, but I'm not familiar enough with request.path_info and other django variables to know how.) | |
""" | |
if request.get_host(): | |
new_url = "%s://%s%s" % (request.is_secure() and 'https' or 'http', request.get_host(), urlquote(new_path)) | |
else: | |
new_url = urlquote(new_path) | |
if request.GET: | |
new_url += '?' + request.META['QUERY_STRING'] | |
return http.HttpResponseRedirect(new_url) | |
def _is_valid_path(path, urlconf=None): | |
""" | |
Returns True if the given path resolves against the default URL resolver, | |
False otherwise. | |
""" | |
try: | |
urlresolvers.resolve(path, urlconf) | |
return True | |
except urlresolvers.Resolver404: | |
return False | |
""" Author contact: sepero 111 @ gmail . com """ |
That is correct. I edited the explanatory comment block to try to clarify the how the middleware works. Any ideas on how can I make it more clear to say what this middleware does?
Maybe call it RemoveOrAppendMiddleware
instead of AppendOrRemoveMiddleware
? :)
That's definitely a thought, but the predecessor might be better off named "ToggleSlash", as it just toggles slash on/off if the requested url doesn't work.
This middleware doesn't operate as the reverse of it's predecessor, since it doesn't toggle the slash. The predecessor was just a good code base to build from. This middleware is meant to operate as the reverse/opposite of APPEND_SLASH in django settings (like a REMOVE_SLASH setting). Hopefully that explains things. lol
Yes, that makes sense. It's not exactly the opposite of APPEND_SLASH though, because APPEND_SLASH will never return a redirect to a URL that removes a slash.
It's easier to:
rewrite ^(.+)/+$ $1 permanent;
In nginx.
Ah, I see. So it still can add a slash though, it doesn't always only remove slashes. If URL
http://example.com/foo
came in and didn't resolve, it would tryhttp://example.com/foo/
and if that resolved, it would redirect to it. I changed mine to just return right away if the URL doesn't end in a slash. I have no cases where I actually want to add a slash.