web/lib/django/core/handlers/base.py
changeset 38 77b6da96e6f1
equal deleted inserted replaced
37:8d941af65caf 38:77b6da96e6f1
       
     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         try:
       
    72             try:
       
    73                 # Setup default url resolver for this thread.
       
    74                 urlconf = settings.ROOT_URLCONF
       
    75                 urlresolvers.set_urlconf(urlconf)
       
    76                 resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
       
    77 
       
    78                 # Apply request middleware
       
    79                 for middleware_method in self._request_middleware:
       
    80                     response = middleware_method(request)
       
    81                     if response:
       
    82                         return response
       
    83 
       
    84                 if hasattr(request, "urlconf"):
       
    85                     # Reset url resolver with a custom urlconf.
       
    86                     urlconf = request.urlconf
       
    87                     urlresolvers.set_urlconf(urlconf)
       
    88                     resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
       
    89 
       
    90                 callback, callback_args, callback_kwargs = resolver.resolve(
       
    91                         request.path_info)
       
    92 
       
    93                 # Apply view middleware
       
    94                 for middleware_method in self._view_middleware:
       
    95                     response = middleware_method(request, callback, callback_args, callback_kwargs)
       
    96                     if response:
       
    97                         return response
       
    98 
       
    99                 try:
       
   100                     response = callback(request, *callback_args, **callback_kwargs)
       
   101                 except Exception, e:
       
   102                     # If the view raised an exception, run it through exception
       
   103                     # middleware, and if the exception middleware returns a
       
   104                     # response, use that. Otherwise, reraise the exception.
       
   105                     for middleware_method in self._exception_middleware:
       
   106                         response = middleware_method(request, e)
       
   107                         if response:
       
   108                             return response
       
   109                     raise
       
   110 
       
   111                 # Complain if the view returned None (a common error).
       
   112                 if response is None:
       
   113                     try:
       
   114                         view_name = callback.func_name # If it's a function
       
   115                     except AttributeError:
       
   116                         view_name = callback.__class__.__name__ + '.__call__' # If it's a class
       
   117                     raise ValueError("The view %s.%s didn't return an HttpResponse object." % (callback.__module__, view_name))
       
   118 
       
   119                 return response
       
   120             except http.Http404, e:
       
   121                 if settings.DEBUG:
       
   122                     from django.views import debug
       
   123                     return debug.technical_404_response(request, e)
       
   124                 else:
       
   125                     try:
       
   126                         callback, param_dict = resolver.resolve404()
       
   127                         return callback(request, **param_dict)
       
   128                     except:
       
   129                         try:
       
   130                             return self.handle_uncaught_exception(request, resolver, sys.exc_info())
       
   131                         finally:
       
   132                             receivers = signals.got_request_exception.send(sender=self.__class__, request=request)
       
   133             except exceptions.PermissionDenied:
       
   134                 return http.HttpResponseForbidden('<h1>Permission denied</h1>')
       
   135             except SystemExit:
       
   136                 # Allow sys.exit() to actually exit. See tickets #1023 and #4701
       
   137                 raise
       
   138             except: # Handle everything else, including SuspiciousOperation, etc.
       
   139                 # Get the exception info now, in case another exception is thrown later.
       
   140                 exc_info = sys.exc_info()
       
   141                 receivers = signals.got_request_exception.send(sender=self.__class__, request=request)
       
   142                 return self.handle_uncaught_exception(request, resolver, exc_info)
       
   143         finally:
       
   144             # Reset URLconf for this thread on the way out for complete
       
   145             # isolation of request.urlconf
       
   146             urlresolvers.set_urlconf(None)
       
   147 
       
   148     def handle_uncaught_exception(self, request, resolver, exc_info):
       
   149         """
       
   150         Processing for any otherwise uncaught exceptions (those that will
       
   151         generate HTTP 500 responses). Can be overridden by subclasses who want
       
   152         customised 500 handling.
       
   153 
       
   154         Be *very* careful when overriding this because the error could be
       
   155         caused by anything, so assuming something like the database is always
       
   156         available would be an error.
       
   157         """
       
   158         from django.conf import settings
       
   159         from django.core.mail import mail_admins
       
   160 
       
   161         if settings.DEBUG_PROPAGATE_EXCEPTIONS:
       
   162             raise
       
   163 
       
   164         if settings.DEBUG:
       
   165             from django.views import debug
       
   166             return debug.technical_500_response(request, *exc_info)
       
   167 
       
   168         # When DEBUG is False, send an error message to the admins.
       
   169         subject = 'Error (%s IP): %s' % ((request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS and 'internal' or 'EXTERNAL'), request.path)
       
   170         try:
       
   171             request_repr = repr(request)
       
   172         except:
       
   173             request_repr = "Request repr() unavailable"
       
   174         message = "%s\n\n%s" % (self._get_traceback(exc_info), request_repr)
       
   175         mail_admins(subject, message, fail_silently=True)
       
   176         # If Http500 handler is not installed, re-raise last exception
       
   177         if resolver.urlconf_module is None:
       
   178             raise exc_info[1], None, exc_info[2]
       
   179         # Return an HttpResponse that displays a friendly error message.
       
   180         callback, param_dict = resolver.resolve500()
       
   181         return callback(request, **param_dict)
       
   182 
       
   183     def _get_traceback(self, exc_info=None):
       
   184         "Helper function to return the traceback as a string"
       
   185         import traceback
       
   186         return '\n'.join(traceback.format_exception(*(exc_info or sys.exc_info())))
       
   187 
       
   188     def apply_response_fixes(self, request, response):
       
   189         """
       
   190         Applies each of the functions in self.response_fixes to the request and
       
   191         response, modifying the response in the process. Returns the new
       
   192         response.
       
   193         """
       
   194         for func in self.response_fixes:
       
   195             response = func(request, response)
       
   196         return response
       
   197 
       
   198 def get_script_name(environ):
       
   199     """
       
   200     Returns the equivalent of the HTTP request's SCRIPT_NAME environment
       
   201     variable. If Apache mod_rewrite has been used, returns what would have been
       
   202     the script name prior to any rewriting (so it's the script name as seen
       
   203     from the client's perspective), unless DJANGO_USE_POST_REWRITE is set (to
       
   204     anything).
       
   205     """
       
   206     from django.conf import settings
       
   207     if settings.FORCE_SCRIPT_NAME is not None:
       
   208         return force_unicode(settings.FORCE_SCRIPT_NAME)
       
   209 
       
   210     # If Apache's mod_rewrite had a whack at the URL, Apache set either
       
   211     # SCRIPT_URL or REDIRECT_URL to the full resource URL before applying any
       
   212     # rewrites. Unfortunately not every webserver (lighttpd!) passes this
       
   213     # information through all the time, so FORCE_SCRIPT_NAME, above, is still
       
   214     # needed.
       
   215     script_url = environ.get('SCRIPT_URL', u'')
       
   216     if not script_url:
       
   217         script_url = environ.get('REDIRECT_URL', u'')
       
   218     if script_url:
       
   219         return force_unicode(script_url[:-len(environ.get('PATH_INFO', ''))])
       
   220     return force_unicode(environ.get('SCRIPT_NAME', u''))
       
   221