web/lib/django/core/handlers/base.py
changeset 0 0d40e90630ef
child 29 cc9b7e14412b
equal deleted inserted replaced
-1:000000000000 0:0d40e90630ef
       
     1 import sys
       
     2 
       
     3 from django import http
       
     4 from django.core import signals
       
     5 from django.utils.encoding import force_unicode
       
     6 from django.utils.importlib import import_module
       
     7 
       
     8 class BaseHandler(object):
       
     9     # Changes that are always applied to a response (in this order).
       
    10     response_fixes = [
       
    11         http.fix_location_header,
       
    12         http.conditional_content_removal,
       
    13         http.fix_IE_for_attach,
       
    14         http.fix_IE_for_vary,
       
    15     ]
       
    16 
       
    17     def __init__(self):
       
    18         self._request_middleware = self._view_middleware = self._response_middleware = self._exception_middleware = None
       
    19 
       
    20     def load_middleware(self):
       
    21         """
       
    22         Populate middleware lists from settings.MIDDLEWARE_CLASSES.
       
    23 
       
    24         Must be called after the environment is fixed (see __call__).
       
    25         """
       
    26         from django.conf import settings
       
    27         from django.core import exceptions
       
    28         self._view_middleware = []
       
    29         self._response_middleware = []
       
    30         self._exception_middleware = []
       
    31 
       
    32         request_middleware = []
       
    33         for middleware_path in settings.MIDDLEWARE_CLASSES:
       
    34             try:
       
    35                 dot = middleware_path.rindex('.')
       
    36             except ValueError:
       
    37                 raise exceptions.ImproperlyConfigured, '%s isn\'t a middleware module' % middleware_path
       
    38             mw_module, mw_classname = middleware_path[:dot], middleware_path[dot+1:]
       
    39             try:
       
    40                 mod = import_module(mw_module)
       
    41             except ImportError, e:
       
    42                 raise exceptions.ImproperlyConfigured, 'Error importing middleware %s: "%s"' % (mw_module, e)
       
    43             try:
       
    44                 mw_class = getattr(mod, mw_classname)
       
    45             except AttributeError:
       
    46                 raise exceptions.ImproperlyConfigured, 'Middleware module "%s" does not define a "%s" class' % (mw_module, mw_classname)
       
    47 
       
    48             try:
       
    49                 mw_instance = mw_class()
       
    50             except exceptions.MiddlewareNotUsed:
       
    51                 continue
       
    52 
       
    53             if hasattr(mw_instance, 'process_request'):
       
    54                 request_middleware.append(mw_instance.process_request)
       
    55             if hasattr(mw_instance, 'process_view'):
       
    56                 self._view_middleware.append(mw_instance.process_view)
       
    57             if hasattr(mw_instance, 'process_response'):
       
    58                 self._response_middleware.insert(0, mw_instance.process_response)
       
    59             if hasattr(mw_instance, 'process_exception'):
       
    60                 self._exception_middleware.insert(0, mw_instance.process_exception)
       
    61 
       
    62         # We only assign to this when initialization is complete as it is used
       
    63         # as a flag for initialization being complete.
       
    64         self._request_middleware = request_middleware
       
    65 
       
    66     def get_response(self, request):
       
    67         "Returns an HttpResponse object for the given HttpRequest"
       
    68         from django.core import exceptions, urlresolvers
       
    69         from django.conf import settings
       
    70 
       
    71         # Apply request middleware
       
    72         for middleware_method in self._request_middleware:
       
    73             response = middleware_method(request)
       
    74             if response:
       
    75                 return response
       
    76 
       
    77         # Get urlconf from request object, if available.  Otherwise use default.
       
    78         urlconf = getattr(request, "urlconf", settings.ROOT_URLCONF)
       
    79 
       
    80         resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
       
    81         try:
       
    82             callback, callback_args, callback_kwargs = resolver.resolve(
       
    83                     request.path_info)
       
    84 
       
    85             # Apply view middleware
       
    86             for middleware_method in self._view_middleware:
       
    87                 response = middleware_method(request, callback, callback_args, callback_kwargs)
       
    88                 if response:
       
    89                     return response
       
    90 
       
    91             try:
       
    92                 response = callback(request, *callback_args, **callback_kwargs)
       
    93             except Exception, e:
       
    94                 # If the view raised an exception, run it through exception
       
    95                 # middleware, and if the exception middleware returns a
       
    96                 # response, use that. Otherwise, reraise the exception.
       
    97                 for middleware_method in self._exception_middleware:
       
    98                     response = middleware_method(request, e)
       
    99                     if response:
       
   100                         return response
       
   101                 raise
       
   102 
       
   103             # Complain if the view returned None (a common error).
       
   104             if response is None:
       
   105                 try:
       
   106                     view_name = callback.func_name # If it's a function
       
   107                 except AttributeError:
       
   108                     view_name = callback.__class__.__name__ + '.__call__' # If it's a class
       
   109                 raise ValueError, "The view %s.%s didn't return an HttpResponse object." % (callback.__module__, view_name)
       
   110 
       
   111             return response
       
   112         except http.Http404, e:
       
   113             if settings.DEBUG:
       
   114                 from django.views import debug
       
   115                 return debug.technical_404_response(request, e)
       
   116             else:
       
   117                 try:
       
   118                     callback, param_dict = resolver.resolve404()
       
   119                     return callback(request, **param_dict)
       
   120                 except:
       
   121                     try:
       
   122                         return self.handle_uncaught_exception(request, resolver, sys.exc_info())
       
   123                     finally:
       
   124                         receivers = signals.got_request_exception.send(sender=self.__class__, request=request)
       
   125         except exceptions.PermissionDenied:
       
   126             return http.HttpResponseForbidden('<h1>Permission denied</h1>')
       
   127         except SystemExit:
       
   128             # Allow sys.exit() to actually exit. See tickets #1023 and #4701
       
   129             raise
       
   130         except: # Handle everything else, including SuspiciousOperation, etc.
       
   131             # Get the exception info now, in case another exception is thrown later.
       
   132             exc_info = sys.exc_info()
       
   133             receivers = signals.got_request_exception.send(sender=self.__class__, request=request)
       
   134             return self.handle_uncaught_exception(request, resolver, exc_info)
       
   135 
       
   136     def handle_uncaught_exception(self, request, resolver, exc_info):
       
   137         """
       
   138         Processing for any otherwise uncaught exceptions (those that will
       
   139         generate HTTP 500 responses). Can be overridden by subclasses who want
       
   140         customised 500 handling.
       
   141 
       
   142         Be *very* careful when overriding this because the error could be
       
   143         caused by anything, so assuming something like the database is always
       
   144         available would be an error.
       
   145         """
       
   146         from django.conf import settings
       
   147         from django.core.mail import mail_admins
       
   148 
       
   149         if settings.DEBUG_PROPAGATE_EXCEPTIONS:
       
   150             raise
       
   151 
       
   152         if settings.DEBUG:
       
   153             from django.views import debug
       
   154             return debug.technical_500_response(request, *exc_info)
       
   155 
       
   156         # When DEBUG is False, send an error message to the admins.
       
   157         subject = 'Error (%s IP): %s' % ((request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS and 'internal' or 'EXTERNAL'), request.path)
       
   158         try:
       
   159             request_repr = repr(request)
       
   160         except:
       
   161             request_repr = "Request repr() unavailable"
       
   162         message = "%s\n\n%s" % (self._get_traceback(exc_info), request_repr)
       
   163         mail_admins(subject, message, fail_silently=True)
       
   164         # Return an HttpResponse that displays a friendly error message.
       
   165         callback, param_dict = resolver.resolve500()
       
   166         return callback(request, **param_dict)
       
   167 
       
   168     def _get_traceback(self, exc_info=None):
       
   169         "Helper function to return the traceback as a string"
       
   170         import traceback
       
   171         return '\n'.join(traceback.format_exception(*(exc_info or sys.exc_info())))
       
   172 
       
   173     def apply_response_fixes(self, request, response):
       
   174         """
       
   175         Applies each of the functions in self.response_fixes to the request and
       
   176         response, modifying the response in the process. Returns the new
       
   177         response.
       
   178         """
       
   179         for func in self.response_fixes:
       
   180             response = func(request, response)
       
   181         return response
       
   182 
       
   183 def get_script_name(environ):
       
   184     """
       
   185     Returns the equivalent of the HTTP request's SCRIPT_NAME environment
       
   186     variable. If Apache mod_rewrite has been used, returns what would have been
       
   187     the script name prior to any rewriting (so it's the script name as seen
       
   188     from the client's perspective), unless DJANGO_USE_POST_REWRITE is set (to
       
   189     anything).
       
   190     """
       
   191     from django.conf import settings
       
   192     if settings.FORCE_SCRIPT_NAME is not None:
       
   193         return force_unicode(settings.FORCE_SCRIPT_NAME)
       
   194 
       
   195     # If Apache's mod_rewrite had a whack at the URL, Apache set either
       
   196     # SCRIPT_URL or REDIRECT_URL to the full resource URL before applying any
       
   197     # rewrites. Unfortunately not every webserver (lighttpd!) passes this
       
   198     # information through all the time, so FORCE_SCRIPT_NAME, above, is still
       
   199     # needed.
       
   200     script_url = environ.get('SCRIPT_URL', u'')
       
   201     if not script_url:
       
   202         script_url = environ.get('REDIRECT_URL', u'')
       
   203     if script_url:
       
   204         return force_unicode(script_url[:-len(environ.get('PATH_INFO', ''))])
       
   205     return force_unicode(environ.get('SCRIPT_NAME', u''))
       
   206