PageRenderTime 50ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/django/branches/soc2009/http-wsgi-improvements/django/core/handlers/base.py

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