import sys from django import http from django.core import signals from django.utils.encoding import force_unicode from django.utils.importlib import import_module from django.utils.log import getLogger logger = getLogger('django.request') class BaseHandler(object): # Changes that are always applied to a response (in this order). response_fixes = [ http.fix_location_header, http.conditional_content_removal, http.fix_IE_for_attach, http.fix_IE_for_vary, ] def __init__(self): self._request_middleware = self._view_middleware = self._response_middleware = self._exception_middleware = None def load_middleware(self): """ Populate middleware lists from settings.MIDDLEWARE_CLASSES. Must be called after the environment is fixed (see __call__). """ from django.conf import settings from django.core import exceptions self._view_middleware = [] self._template_response_middleware = [] self._response_middleware = [] self._exception_middleware = [] request_middleware = [] for middleware_path in settings.MIDDLEWARE_CLASSES: try: mw_module, mw_classname = middleware_path.rsplit('.', 1) except ValueError: raise exceptions.ImproperlyConfigured('%s isn\'t a middleware module' % middleware_path) try: mod = import_module(mw_module) except ImportError, e: raise exceptions.ImproperlyConfigured('Error importing middleware %s: "%s"' % (mw_module, e)) try: mw_class = getattr(mod, mw_classname) except AttributeError: raise exceptions.ImproperlyConfigured('Middleware module "%s" does not define a "%s" class' % (mw_module, mw_classname)) try: mw_instance = mw_class() except exceptions.MiddlewareNotUsed: continue if hasattr(mw_instance, 'process_request'): request_middleware.append(mw_instance.process_request) if hasattr(mw_instance, 'process_view'): self._view_middleware.append(mw_instance.process_view) if hasattr(mw_instance, 'process_template_response'): self._template_response_middleware.insert(0, mw_instance.process_template_response) if hasattr(mw_instance, 'process_response'): self._response_middleware.insert(0, mw_instance.process_response) if hasattr(mw_instance, 'process_exception'): self._exception_middleware.insert(0, mw_instance.process_exception) # We only assign to this when initialization is complete as it is used # as a flag for initialization being complete. self._request_middleware = request_middleware def get_response(self, request): "Returns an HttpResponse object for the given HttpRequest" from django.core import exceptions, urlresolvers from django.conf import settings try: # Setup default url resolver for this thread, this code is outside # the try/except so we don't get a spurious "unbound local # variable" exception in the event an exception is raised before # resolver is set urlconf = settings.ROOT_URLCONF urlresolvers.set_urlconf(urlconf) resolver = urlresolvers.RegexURLResolver(r'^/', urlconf) try: response = None # Apply request middleware for middleware_method in self._request_middleware: response = middleware_method(request) if response: break if response is None: if hasattr(request, "urlconf"): # Reset url resolver with a custom urlconf. urlconf = request.urlconf urlresolvers.set_urlconf(urlconf) resolver = urlresolvers.RegexURLResolver(r'^/', urlconf) callback, callback_args, callback_kwargs = resolver.resolve( request.path_info) # Apply view middleware for middleware_method in self._view_middleware: response = middleware_method(request, callback, callback_args, callback_kwargs) if response: break if response is None: try: response = callback(request, *callback_args, **callback_kwargs) except Exception, e: # If the view raised an exception, run it through exception # middleware, and if the exception middleware returns a # response, use that. Otherwise, reraise the exception. for middleware_method in self._exception_middleware: response = middleware_method(request, e) if response: break if response is None: raise # Complain if the view returned None (a common error). if response is None: try: view_name = callback.func_name # If it's a function except AttributeError: view_name = callback.__class__.__name__ + '.__call__' # If it's a class raise ValueError("The view %s.%s didn't return an HttpResponse object." % (callback.__module__, view_name)) # If the response supports deferred rendering, apply template # response middleware and the render the response if hasattr(response, 'render') and callable(response.render): for middleware_method in self._template_response_middleware: response = middleware_method(request, response) response.render() except http.Http404, e: logger.warning('Not Found: %s' % request.path, extra={ 'status_code': 404, 'request': request }) if settings.DEBUG: from django.views import debug response = debug.technical_404_response(request, e) else: try: callback, param_dict = resolver.resolve404() response = callback(request, **param_dict) except: try: response = self.handle_uncaught_exception(request, resolver, sys.exc_info()) finally: receivers = signals.got_request_exception.send(sender=self.__class__, request=request) except exceptions.PermissionDenied: logger.warning('Forbidden (Permission denied): %s' % request.path, extra={ 'status_code': 403, 'request': request }) response = http.HttpResponseForbidden('