2005-07-13 09:25:57 +08:00
from django . conf import settings
2006-05-02 09:31:56 +08:00
from django import http
2005-07-13 09:25:57 +08:00
from django . core . mail import mail_managers
2006-07-22 00:20:22 +08:00
import md5
2006-09-27 02:49:28 +08:00
import re
2005-07-13 09:25:57 +08:00
2006-06-08 13:00:13 +08:00
class CommonMiddleware ( object ) :
2005-07-13 09:25:57 +08:00
"""
" Common " middleware for taking care of some basic operations :
- Forbids access to User - Agents in settings . DISALLOWED_USER_AGENTS
2005-11-07 05:55:57 +08:00
- URL rewriting : Based on the APPEND_SLASH and PREPEND_WWW settings ,
2007-06-17 15:21:09 +08:00
this middleware appends missing slashes and / or prepends missing
" www. " s .
2005-07-13 09:25:57 +08:00
2005-11-07 05:55:57 +08:00
- ETags : If the USE_ETAGS setting is set , ETags will be calculated from
2005-07-13 09:25:57 +08:00
the entire page content and Not Modified responses will be returned
appropriately .
"""
def process_request ( self , request ) :
"""
Check for denied User - Agents and rewrite the URL based on
settings . APPEND_SLASH and settings . PREPEND_WWW
"""
# Check for denied User-Agents
2007-04-26 21:30:48 +08:00
if ' HTTP_USER_AGENT ' in request . META :
2005-07-13 09:25:57 +08:00
for user_agent_regex in settings . DISALLOWED_USER_AGENTS :
if user_agent_regex . search ( request . META [ ' HTTP_USER_AGENT ' ] ) :
2006-05-02 09:31:56 +08:00
return http . HttpResponseForbidden ( ' <h1>Forbidden</h1> ' )
2005-07-13 09:25:57 +08:00
# Check for a redirect based on settings.APPEND_SLASH and settings.PREPEND_WWW
2006-05-02 09:31:56 +08:00
host = http . get_host ( request )
old_url = [ host , request . path ]
2005-07-13 09:25:57 +08:00
new_url = old_url [ : ]
2005-12-05 23:25:55 +08:00
if settings . PREPEND_WWW and old_url [ 0 ] and not old_url [ 0 ] . startswith ( ' www. ' ) :
2005-07-13 09:25:57 +08:00
new_url [ 0 ] = ' www. ' + old_url [ 0 ]
# Append a slash if append_slash is set and the URL doesn't have a
# trailing slash or a file extension.
2007-07-13 22:33:46 +08:00
if settings . APPEND_SLASH and ( not old_url [ 1 ] . endswith ( ' / ' ) ) and ( ' . ' not in old_url [ 1 ] . split ( ' / ' ) [ - 1 ] ) :
2005-07-13 09:25:57 +08:00
new_url [ 1 ] = new_url [ 1 ] + ' / '
2006-06-20 12:34:13 +08:00
if settings . DEBUG and request . method == ' POST ' :
2006-06-08 11:47:18 +08:00
raise RuntimeError , " You called this URL via POST, but the URL doesn ' t end in a slash and you have APPEND_SLASH set. Django can ' t redirect to the slash URL while maintaining POST data. Change your form to point to %s %s (note the trailing slash), or set APPEND_SLASH=False in your Django settings. " % ( new_url [ 0 ] , new_url [ 1 ] )
2005-07-13 09:25:57 +08:00
if new_url != old_url :
# Redirect
2005-12-05 23:25:55 +08:00
if new_url [ 0 ] :
2006-07-22 00:20:22 +08:00
newurl = " %s :// %s %s " % ( request . is_secure ( ) and ' https ' or ' http ' , new_url [ 0 ] , new_url [ 1 ] )
2005-12-05 23:25:55 +08:00
else :
newurl = new_url [ 1 ]
2005-07-13 09:25:57 +08:00
if request . GET :
2005-09-03 03:39:47 +08:00
newurl + = ' ? ' + request . GET . urlencode ( )
2006-05-02 09:31:56 +08:00
return http . HttpResponsePermanentRedirect ( newurl )
2005-07-13 09:25:57 +08:00
return None
def process_response ( self , request , response ) :
2005-10-06 07:36:17 +08:00
" Check for a flat page (for 404s) and calculate the Etag, if needed. "
2005-07-13 09:25:57 +08:00
if response . status_code == 404 :
2005-10-06 07:36:17 +08:00
if settings . SEND_BROKEN_LINK_EMAILS :
2005-07-13 09:25:57 +08:00
# If the referrer was from an internal link or a non-search-engine site,
# send a note to the managers.
2006-05-02 09:31:56 +08:00
domain = http . get_host ( request )
2005-10-06 07:36:17 +08:00
referer = request . META . get ( ' HTTP_REFERER ' , None )
2006-09-27 02:49:28 +08:00
is_internal = _is_internal_request ( domain , referer )
2005-10-06 07:36:17 +08:00
path = request . get_full_path ( )
if referer and not _is_ignorable_404 ( path ) and ( is_internal or ' ? ' not in referer ) :
2006-09-26 01:25:39 +08:00
ua = request . META . get ( ' HTTP_USER_AGENT ' , ' <none> ' )
2007-04-20 19:24:53 +08:00
ip = request . META . get ( ' REMOTE_ADDR ' , ' <none> ' )
2005-10-06 07:36:17 +08:00
mail_managers ( " Broken %s link on %s " % ( ( is_internal and ' INTERNAL ' or ' ' ) , domain ) ,
2007-04-20 19:24:53 +08:00
" Referrer: %s \n Requested URL: %s \n User agent: %s \n IP address: %s \n " \
% ( referer , request . get_full_path ( ) , ua , ip ) )
2005-07-13 09:25:57 +08:00
return response
2005-10-06 07:36:17 +08:00
# Use ETags, if requested.
2005-07-13 09:25:57 +08:00
if settings . USE_ETAGS :
2007-06-17 15:21:09 +08:00
if response . has_header ( ' ETag ' ) :
etag = response [ ' ETag ' ]
else :
etag = md5 . new ( response . content ) . hexdigest ( )
2007-06-02 15:55:41 +08:00
if response . status_code > = 200 and response . status_code < 300 and request . META . get ( ' HTTP_IF_NONE_MATCH ' ) == etag :
2006-05-02 09:31:56 +08:00
response = http . HttpResponseNotModified ( )
2005-07-13 09:25:57 +08:00
else :
response [ ' ETag ' ] = etag
return response
def _is_ignorable_404 ( uri ) :
" Returns True if a 404 at the given URL *shouldn ' t* notify the site managers "
for start in settings . IGNORABLE_404_STARTS :
if uri . startswith ( start ) :
return True
for end in settings . IGNORABLE_404_ENDS :
if uri . endswith ( end ) :
return True
return False
2006-09-27 02:49:28 +08:00
def _is_internal_request ( domain , referer ) :
" Return true if the referring URL is the same domain as the current request "
# Different subdomains are treated as different domains.
return referer is not None and re . match ( " ^https?:// %s / " % re . escape ( domain ) , referer )