summaryrefslogtreecommitdiff
path: root/django/core/handler.py
diff options
context:
space:
mode:
authorAdrian Holovaty <adrian@holovaty.com>2005-07-13 01:25:57 +0000
committerAdrian Holovaty <adrian@holovaty.com>2005-07-13 01:25:57 +0000
commited114e15106192b22ebb78ef5bf5bce72b419d13 (patch)
treef7c27f035cca8d50bd69e2ecbd7497fccec4a35a /django/core/handler.py
parent07ffc7d605cc96557db28a9e35da69bc0719611b (diff)
Imported Django from private SVN repository (created from r. 8825)
git-svn-id: http://code.djangoproject.com/svn/django/trunk@3 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/core/handler.py')
-rw-r--r--django/core/handler.py157
1 files changed, 157 insertions, 0 deletions
diff --git a/django/core/handler.py b/django/core/handler.py
new file mode 100644
index 0000000000..1412ee6838
--- /dev/null
+++ b/django/core/handler.py
@@ -0,0 +1,157 @@
+import os
+from django.utils import httpwrappers
+
+# NOTE: do *not* import settings (or any module which eventually imports
+# settings) until after CoreHandler has been called; otherwise os.environ
+# won't be set up correctly (with respect to settings).
+
+class ImproperlyConfigured(Exception):
+ pass
+
+class CoreHandler:
+
+ def __init__(self):
+ self._request_middleware = self._view_middleware = self._response_middleware = None
+
+ def __call__(self, req):
+ # mod_python fakes the environ, and thus doesn't process SetEnv. This fixes that
+ os.environ.update(req.subprocess_env)
+
+ # now that the environ works we can see the correct settings, so imports
+ # that use settings now can work
+ from django.conf import settings
+ from django.core import db
+
+ # if we need to set up middleware, now that settings works we can do it now.
+ if self._request_middleware is None:
+ self.load_middleware()
+
+ try:
+ request = self.get_request(req)
+ response = self.get_response(req.uri, request)
+ finally:
+ db.db.close()
+
+ # Apply response middleware
+ for middleware_method in self._response_middleware:
+ response = middleware_method(request, response)
+
+ # Convert our custom HttpResponse object back into the mod_python req.
+ httpwrappers.populate_apache_request(response, req)
+ return 0 # mod_python.apache.OK
+
+ 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._request_middleware = []
+ self._view_middleware = []
+ self._response_middleware = []
+ for middleware_path in settings.MIDDLEWARE_CLASSES:
+ dot = middleware_path.rindex('.')
+ mw_module, mw_classname = middleware_path[:dot], middleware_path[dot+1:]
+ try:
+ mod = __import__(mw_module, '', '', [''])
+ except ImportError, e:
+ raise ImproperlyConfigured, 'Error importing middleware %s: "%s"' % (mw_module, e)
+ try:
+ mw_class = getattr(mod, mw_classname)
+ except AttributeError:
+ raise 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'):
+ self._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_response'):
+ self._response_middleware.insert(0, mw_instance.process_response)
+
+ def get_request(self, req):
+ "Returns an HttpRequest object for the given mod_python req object"
+ from django.core.extensions import CMSRequest
+ return CMSRequest(req)
+
+ def get_response(self, path, request):
+ "Returns an HttpResponse object for the given HttpRequest"
+ from django.core import db, exceptions, urlresolvers
+ from django.core.mail import mail_admins
+ from django.conf.settings import DEBUG, INTERNAL_IPS, ROOT_URLCONF
+
+ # Apply request middleware
+ for middleware_method in self._request_middleware:
+ response = middleware_method(request)
+ if response:
+ return response
+
+ conf_module = __import__(ROOT_URLCONF, '', '', [''])
+ resolver = urlresolvers.RegexURLResolver(conf_module.urlpatterns)
+ try:
+ callback, param_dict = resolver.resolve(path)
+ # Apply view middleware
+ for middleware_method in self._view_middleware:
+ response = middleware_method(request, callback, param_dict)
+ if response:
+ return response
+ return callback(request, **param_dict)
+ except exceptions.Http404:
+ if DEBUG:
+ return self.get_technical_error_response(is404=True)
+ else:
+ resolver = urlresolvers.Error404Resolver(conf_module.handler404)
+ callback, param_dict = resolver.resolve()
+ return callback(request, **param_dict)
+ except db.DatabaseError:
+ db.db.rollback()
+ if DEBUG:
+ return self.get_technical_error_response()
+ else:
+ subject = 'Database error (%s IP)' % (request.META['REMOTE_ADDR'] in INTERNAL_IPS and 'internal' or 'EXTERNAL')
+ message = "%s\n\n%s" % (self._get_traceback(), request)
+ mail_admins(subject, message, fail_silently=True)
+ return self.get_friendly_error_response(request, conf_module)
+ except exceptions.PermissionDenied:
+ return httpwrappers.HttpResponseForbidden('<h1>Permission denied</h1>')
+ except: # Handle everything else, including SuspiciousOperation, etc.
+ if DEBUG:
+ return self.get_technical_error_response()
+ else:
+ subject = 'Coding error (%s IP)' % (request.META['REMOTE_ADDR'] in INTERNAL_IPS and 'internal' or 'EXTERNAL')
+ message = "%s\n\n%s" % (self._get_traceback(), request)
+ mail_admins(subject, message, fail_silently=True)
+ return self.get_friendly_error_response(request, conf_module)
+
+ def get_friendly_error_response(self, request, conf_module):
+ """
+ Returns an HttpResponse that displays a PUBLIC error message for a
+ fundamental database or coding error.
+ """
+ from django.core import urlresolvers
+ resolver = urlresolvers.Error404Resolver(conf_module.handler500)
+ callback, param_dict = resolver.resolve()
+ return callback(request, **param_dict)
+
+ def get_technical_error_response(self, is404=False):
+ """
+ Returns an HttpResponse that displays a TECHNICAL error message for a
+ fundamental database or coding error.
+ """
+ error_string = "<pre>There's been an error:\n\n%s</pre>" % self._get_traceback()
+ responseClass = is404 and httpwrappers.HttpResponseNotFound or httpwrappers.HttpResponseServerError
+ return responseClass(error_string)
+
+ def _get_traceback(self):
+ "Helper function to return the traceback as a string"
+ import sys, traceback
+ return '\n'.join(traceback.format_exception(*sys.exc_info()))
+
+def handler(req):
+ return CoreHandler()(req)