Django

Code

Ticket #6213: common_middleware.py.diff

File common_middleware.py.diff, 5.0 kB (added by esaj, 1 year ago)

Patch for CommonMiddleware? to fix handling of APPEND_SLASH and PREPEND_WWW

  • django/middleware/common.py

    old new  
    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: