| 1 | """ |
|---|
| 2 | URL Middleware |
|---|
| 3 | Stefano J. Attardi (attardi.org) |
|---|
| 4 | |
|---|
| 5 | $Id$ |
|---|
| 6 | $URL$ |
|---|
| 7 | |
|---|
| 8 | Cleans up urls by adding/removing trailing slashes, adding/removing |
|---|
| 9 | the www. prefix, and allowing the language to be set from the url. |
|---|
| 10 | |
|---|
| 11 | If APPEND_SLASH is set to False, trailing slashes are removed from the |
|---|
| 12 | urls, except for urls which have an explicit trailing slash in |
|---|
| 13 | urls.py, in which case a trailing slash is added. |
|---|
| 14 | |
|---|
| 15 | If REMOVE_WWW is set to True, the www. prefix is removed. |
|---|
| 16 | |
|---|
| 17 | Finally, ?lang=xx can be appended to any url to override the default |
|---|
| 18 | language setting. This override is remembered for the following |
|---|
| 19 | requests. For example, /article?lang=it would show the article in |
|---|
| 20 | Italian regardless of brower settings or cookies, and any following |
|---|
| 21 | request to the site would be shown in Italian by default. |
|---|
| 22 | |
|---|
| 23 | Changelog |
|---|
| 24 | |
|---|
| 25 | 1.3.3 |
|---|
| 26 | Fixed a bug which made the middleware use sessions for languages even |
|---|
| 27 | when they were not used by anything else. |
|---|
| 28 | |
|---|
| 29 | 1.3.2 |
|---|
| 30 | Fixed an indentation issue. Added a check for those backends |
|---|
| 31 | which set an empty path (e.g. runfcgi). |
|---|
| 32 | |
|---|
| 33 | 1.3.1 |
|---|
| 34 | Added support for running in a test |
|---|
| 35 | suite (doesn't assume that HTTP_HOST is set) |
|---|
| 36 | |
|---|
| 37 | 1.3 |
|---|
| 38 | Only use sessions for the language preference if the session |
|---|
| 39 | cookie has already been set (regardless of whether session middleware |
|---|
| 40 | is active). Otherwise use the plain django_language cookie. |
|---|
| 41 | Only import the FlatPages module if it is active. |
|---|
| 42 | |
|---|
| 43 | 1.2 |
|---|
| 44 | Added support for FlatPages. |
|---|
| 45 | Switched to Django's resolve function (with workaround for when it |
|---|
| 46 | returns None). |
|---|
| 47 | |
|---|
| 48 | 1.1 |
|---|
| 49 | Various bugfixes. |
|---|
| 50 | |
|---|
| 51 | 1.0 |
|---|
| 52 | First release. |
|---|
| 53 | """ |
|---|
| 54 | __version__ = "1.3.3" |
|---|
| 55 | __license__ = "Python" |
|---|
| 56 | __copyright__ = "Copyright (C) 2006-2008, Stefano J. Attardi" |
|---|
| 57 | __author__ = "Stefano J. Attardi <http://attardi.org/>" |
|---|
| 58 | __contributors__ = ["Antonio Cavedoni <http://cavedoni.com/>"] |
|---|
| 59 | |
|---|
| 60 | from django.conf import settings |
|---|
| 61 | from django.http import HttpResponseRedirect, Http404 |
|---|
| 62 | from django.core.urlresolvers import resolve |
|---|
| 63 | from django.utils.translation import check_for_language |
|---|
| 64 | import os |
|---|
| 65 | |
|---|
| 66 | class UrlMiddleware: |
|---|
| 67 | |
|---|
| 68 | def process_request(self, request): |
|---|
| 69 | |
|---|
| 70 | # Change the language setting for the current page |
|---|
| 71 | if "lang" in request.GET and check_for_language(request.GET["lang"]): |
|---|
| 72 | if 'sessionid' in request.COOKIES: |
|---|
| 73 | request.session["django_language"] = request.GET["lang"] |
|---|
| 74 | else: |
|---|
| 75 | request.COOKIES["django_language"] = request.GET["lang"] |
|---|
| 76 | |
|---|
| 77 | # work-around for runfcgi |
|---|
| 78 | if request.path == "": request.path = "/" |
|---|
| 79 | |
|---|
| 80 | # Check for a redirect based on settings.APPEND_SLASH and settings.PREPEND_WWW |
|---|
| 81 | old_url = [request.META.get("HTTP_HOST", "localhost"), request.path] |
|---|
| 82 | new_url = old_url[:] |
|---|
| 83 | |
|---|
| 84 | # if REMOVE_WWW is True, remove the www. from the urls if necessary |
|---|
| 85 | if hasattr(settings, "REMOVE_WWW") and settings.REMOVE_WWW and old_url[0].startswith("www."): |
|---|
| 86 | new_url[0] = old_url[0][4:] |
|---|
| 87 | |
|---|
| 88 | if hasattr(settings, "APPEND_SLASH") and not settings.APPEND_SLASH: |
|---|
| 89 | # if the url is not found, try with(out) the trailing slash |
|---|
| 90 | if old_url[1] != "/" and not self._urlExists(old_url[1]): |
|---|
| 91 | |
|---|
| 92 | if old_url[1][-1] == "/": |
|---|
| 93 | other = old_url[1][:-1] |
|---|
| 94 | else: |
|---|
| 95 | other = old_url[1] + "/" |
|---|
| 96 | |
|---|
| 97 | if self._urlExists(other): |
|---|
| 98 | new_url[1] = other |
|---|
| 99 | |
|---|
| 100 | if new_url != old_url: |
|---|
| 101 | # Redirect |
|---|
| 102 | newurl = "%s://%s%s" % (os.environ.get("HTTPS") == "on" and "https" or "http", new_url[0], new_url[1]) |
|---|
| 103 | if request.GET: |
|---|
| 104 | newurl += "?" + request.GET.urlencode() |
|---|
| 105 | |
|---|
| 106 | return HttpResponseRedirect(newurl) |
|---|
| 107 | |
|---|
| 108 | return None |
|---|
| 109 | |
|---|
| 110 | def process_response(self, request, response): |
|---|
| 111 | |
|---|
| 112 | # Change the language setting for future pages |
|---|
| 113 | if "lang" in request.GET and check_for_language(request.GET["lang"]): |
|---|
| 114 | if 'sessionid' in request.COOKIES: |
|---|
| 115 | request.session["django_language"] = request.GET["lang"] |
|---|
| 116 | else: |
|---|
| 117 | response.set_cookie("django_language", request.GET["lang"]) |
|---|
| 118 | |
|---|
| 119 | return response |
|---|
| 120 | |
|---|
| 121 | def _urlExists(self, path): |
|---|
| 122 | try: |
|---|
| 123 | if resolve(path) is None: raise Http404 # None?!? You mean 404... |
|---|
| 124 | return True |
|---|
| 125 | except Http404: |
|---|
| 126 | # check for flatpages |
|---|
| 127 | if "django.contrib.flatpages.middleware.FlatpageFallbackMiddleware" in settings.MIDDLEWARE_CLASSES: |
|---|
| 128 | from django.contrib.flatpages.models import FlatPage |
|---|
| 129 | return FlatPage.objects.filter(url=path, sites__id=settings.SITE_ID).count() == 1 |
|---|