app/django/core/handlers/base.py
changeset 54 03e267d67478
child 323 ff1a9aa48cfd
equal deleted inserted replaced
53:57b4279d8c4e 54:03e267d67478
       
     1 import sys
       
     2 
       
     3 from django import http
       
     4 from django.core import signals
       
     5 from django.dispatch import dispatcher
       
     6 
       
     7 class BaseHandler(object):
       
     8     # Changes that are always applied to a response (in this order).
       
     9     response_fixes = [http.fix_location_header,
       
    10             http.conditional_content_removal]
       
    11 
       
    12     def __init__(self):
       
    13         self._request_middleware = self._view_middleware = self._response_middleware = self._exception_middleware = None
       
    14 
       
    15     def load_middleware(self):
       
    16         """
       
    17         Populate middleware lists from settings.MIDDLEWARE_CLASSES.
       
    18 
       
    19         Must be called after the environment is fixed (see __call__).
       
    20         """
       
    21         from django.conf import settings
       
    22         from django.core import exceptions
       
    23         self._request_middleware = []
       
    24         self._view_middleware = []
       
    25         self._response_middleware = []
       
    26         self._exception_middleware = []
       
    27         for middleware_path in settings.MIDDLEWARE_CLASSES:
       
    28             try:
       
    29                 dot = middleware_path.rindex('.')
       
    30             except ValueError:
       
    31                 raise exceptions.ImproperlyConfigured, '%s isn\'t a middleware module' % middleware_path
       
    32             mw_module, mw_classname = middleware_path[:dot], middleware_path[dot+1:]
       
    33             try:
       
    34                 mod = __import__(mw_module, {}, {}, [''])
       
    35             except ImportError, e:
       
    36                 raise exceptions.ImproperlyConfigured, 'Error importing middleware %s: "%s"' % (mw_module, e)
       
    37             try:
       
    38                 mw_class = getattr(mod, mw_classname)
       
    39             except AttributeError:
       
    40                 raise exceptions.ImproperlyConfigured, 'Middleware module "%s" does not define a "%s" class' % (mw_module, mw_classname)
       
    41 
       
    42             try:
       
    43                 mw_instance = mw_class()
       
    44             except exceptions.MiddlewareNotUsed:
       
    45                 continue
       
    46 
       
    47             if hasattr(mw_instance, 'process_request'):
       
    48                 self._request_middleware.append(mw_instance.process_request)
       
    49             if hasattr(mw_instance, 'process_view'):
       
    50                 self._view_middleware.append(mw_instance.process_view)
       
    51             if hasattr(mw_instance, 'process_response'):
       
    52                 self._response_middleware.insert(0, mw_instance.process_response)
       
    53             if hasattr(mw_instance, 'process_exception'):
       
    54                 self._exception_middleware.insert(0, mw_instance.process_exception)
       
    55 
       
    56     def get_response(self, request):
       
    57         "Returns an HttpResponse object for the given HttpRequest"
       
    58         from django.core import exceptions, urlresolvers
       
    59         from django.core.mail import mail_admins
       
    60         from django.conf import settings
       
    61 
       
    62         # Apply request middleware
       
    63         for middleware_method in self._request_middleware:
       
    64             response = middleware_method(request)
       
    65             if response:
       
    66                 return response
       
    67 
       
    68         # Get urlconf from request object, if available.  Otherwise use default.
       
    69         urlconf = getattr(request, "urlconf", settings.ROOT_URLCONF)
       
    70 
       
    71         resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
       
    72         try:
       
    73             callback, callback_args, callback_kwargs = resolver.resolve(request.path)
       
    74 
       
    75             # Apply view middleware
       
    76             for middleware_method in self._view_middleware:
       
    77                 response = middleware_method(request, callback, callback_args, callback_kwargs)
       
    78                 if response:
       
    79                     return response
       
    80 
       
    81             try:
       
    82                 response = callback(request, *callback_args, **callback_kwargs)
       
    83             except Exception, e:
       
    84                 # If the view raised an exception, run it through exception
       
    85                 # middleware, and if the exception middleware returns a
       
    86                 # response, use that. Otherwise, reraise the exception.
       
    87                 for middleware_method in self._exception_middleware:
       
    88                     response = middleware_method(request, e)
       
    89                     if response:
       
    90                         return response
       
    91                 raise
       
    92 
       
    93             # Complain if the view returned None (a common error).
       
    94             if response is None:
       
    95                 try:
       
    96                     view_name = callback.func_name # If it's a function
       
    97                 except AttributeError:
       
    98                     view_name = callback.__class__.__name__ + '.__call__' # If it's a class
       
    99                 raise ValueError, "The view %s.%s didn't return an HttpResponse object." % (callback.__module__, view_name)
       
   100 
       
   101             return response
       
   102         except http.Http404, e:
       
   103             if settings.DEBUG:
       
   104                 from django.views import debug
       
   105                 return debug.technical_404_response(request, e)
       
   106             else:
       
   107                 callback, param_dict = resolver.resolve404()
       
   108                 return callback(request, **param_dict)
       
   109         except exceptions.PermissionDenied:
       
   110             return http.HttpResponseForbidden('<h1>Permission denied</h1>')
       
   111         except SystemExit:
       
   112             # Allow sys.exit() to actually exit. See tickets #1023 and #4701
       
   113             raise
       
   114         except: # Handle everything else, including SuspiciousOperation, etc.
       
   115             # Get the exception info now, in case another exception is thrown later.
       
   116             exc_info = sys.exc_info()
       
   117             receivers = dispatcher.send(signal=signals.got_request_exception, request=request)
       
   118 
       
   119             if settings.DEBUG_PROPAGATE_EXCEPTIONS:
       
   120                 raise
       
   121             elif settings.DEBUG:
       
   122                 from django.views import debug
       
   123                 return debug.technical_500_response(request, *exc_info)
       
   124             else:
       
   125                 # When DEBUG is False, send an error message to the admins.
       
   126                 subject = 'Error (%s IP): %s' % ((request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS and 'internal' or 'EXTERNAL'), request.path)
       
   127                 try:
       
   128                     request_repr = repr(request)
       
   129                 except:
       
   130                     request_repr = "Request repr() unavailable"
       
   131                 message = "%s\n\n%s" % (self._get_traceback(exc_info), request_repr)
       
   132                 mail_admins(subject, message, fail_silently=True)
       
   133                 # Return an HttpResponse that displays a friendly error message.
       
   134                 callback, param_dict = resolver.resolve500()
       
   135                 return callback(request, **param_dict)
       
   136 
       
   137     def _get_traceback(self, exc_info=None):
       
   138         "Helper function to return the traceback as a string"
       
   139         import traceback
       
   140         return '\n'.join(traceback.format_exception(*(exc_info or sys.exc_info())))
       
   141 
       
   142     def apply_response_fixes(self, request, response):
       
   143         """
       
   144         Applies each of the functions in self.response_fixes to the request and
       
   145         response, modifying the response in the process. Returns the new
       
   146         response.
       
   147         """
       
   148         for func in self.response_fixes:
       
   149             response = func(request, response)
       
   150         return response
       
   151