Ticket #6213: common_middleware.py.diff

File common_middleware.py.diff, 5.0 KB (added by Jason Davies, 16 years ago)

Patch for CommonMiddleware to fix handling of APPEND_SLASH and PREPEND_WWW

  • django/middleware/common.py

     
    4040                if user_agent_regex.search(request.META['HTTP_USER_AGENT']):
    4141                    return http.HttpResponseForbidden('<h1>Forbidden</h1>')
    4242
    43         # Check for a redirect based on settings.APPEND_SLASH
    44         # and settings.PREPEND_WWW
    45         host = request.get_host()
    46         old_url = [host, request.path]
    47         new_url = old_url[:]
     43        _response = _handle_redirects(request)
     44        if _response:
     45            return _response
    4846
    49         if (settings.PREPEND_WWW and old_url[0] and
    50                 not old_url[0].startswith('www.')):
    51             new_url[0] = 'www.' + old_url[0]
    52 
    53         # Append a slash if APPEND_SLASH is set and the URL doesn't have a
    54         # trailing slash and there is no pattern for the current path
    55         if settings.APPEND_SLASH and (not old_url[1].endswith('/')):
    56             try:
    57                 urlresolvers.resolve(request.path)
    58             except urlresolvers.Resolver404:
    59                 new_url[1] = new_url[1] + '/'
    60                 if settings.DEBUG and request.method == 'POST':
    61                     raise RuntimeError, (""
    62                     "You called this URL via POST, but the URL doesn't end "
    63                     "in a slash and you have APPEND_SLASH set. Django can't "
    64                     "redirect to the slash URL while maintaining POST data. "
    65                     "Change your form to point to %s%s (note the trailing "
    66                     "slash), or set APPEND_SLASH=False in your Django "
    67                     "settings.") % (new_url[0], new_url[1])
    68 
    69         if new_url != old_url:
    70             # Redirect if the target url exists
    71             try:
    72                 urlresolvers.resolve(new_url[1])
    73             except urlresolvers.Resolver404:
    74                 pass
    75             else:
    76                 if new_url[0]:
    77                     newurl = "%s://%s%s" % (
    78                         request.is_secure() and 'https' or 'http',
    79                         new_url[0], urlquote(new_url[1]))
    80                 else:
    81                     newurl = urlquote(new_url[1])
    82                 if request.GET:
    83                     newurl += '?' + request.GET.urlencode()
    84                 return http.HttpResponsePermanentRedirect(newurl)
    85 
    8647        return None
    8748
    8849    def process_response(self, request, response):
    8950        "Check for a flat page (for 404s) and calculate the Etag, if needed."
    9051        if response.status_code == 404:
     52            _response = _handle_redirects(request, resolve=False)
     53            if _response:
     54                return _response
    9155            if settings.SEND_BROKEN_LINK_EMAILS:
    9256                # If the referrer was from an internal link or a non-search-engine site,
    9357                # send a note to the managers.
     
    11882
    11983        return response
    12084
     85def _handle_redirects(request, resolve=True):
     86    host = request.get_host()
     87    old_url = [host, request.path]
     88    new_url = old_url[:]
     89
     90    if (settings.PREPEND_WWW and old_url[0] and
     91            not old_url[0].startswith('www.')):
     92        new_url[0] = 'www.' + old_url[0]
     93
     94    # Append a slash if APPEND_SLASH is set and the URL doesn't have a
     95    # trailing slash and there is no pattern for the current path
     96    if settings.APPEND_SLASH and (not old_url[1].endswith('/')):
     97        if resolve:
     98            try:
     99                urlresolvers.resolve(request.path)
     100            except urlresolvers.Resolver404:
     101                new_url[1] = new_url[1] + '/'
     102        else:
     103            new_url[1] = new_url[1] + '/'
     104
     105    if new_url != old_url:
     106        # Redirect if the target url exists
     107        try:
     108            if resolve and new_url[0] == new_url[0] and new_url[1] != old_url[1]:
     109                urlresolvers.resolve(new_url[1])
     110        except urlresolvers.Resolver404:
     111            pass
     112        else:
     113            if new_url[0]:
     114                newurl = "%s://%s%s" % (
     115                    request.is_secure() and 'https' or 'http',
     116                    new_url[0], urlquote(new_url[1]))
     117            else:
     118                newurl = urlquote(new_url[1])
     119            if request.GET:
     120                newurl += '?' + request.GET.urlencode()
     121            if settings.DEBUG and request.method == 'POST':
     122                raise RuntimeError, (""
     123                "You called this URL via POST, but the URL doesn't end "
     124                "in a slash and you have APPEND_SLASH set. Django can't "
     125                "redirect to the slash URL while maintaining POST data. "
     126                "Change your form to point to %s%s (note the trailing "
     127                "slash), or set APPEND_SLASH=False in your Django "
     128                "settings.") % (new_url[0], new_url[1])
     129            return http.HttpResponsePermanentRedirect(newurl)
     130
    121131def _is_ignorable_404(uri):
    122132    "Returns True if a 404 at the given URL *shouldn't* notify the site managers"
    123133    for start in settings.IGNORABLE_404_STARTS:
Back to Top