diff options
Diffstat (limited to 'django/core/handlers')
-rw-r--r-- | django/core/handlers/base.py | 41 | ||||
-rw-r--r-- | django/core/handlers/modpython.py | 25 | ||||
-rw-r--r-- | django/core/handlers/wsgi.py | 19 |
3 files changed, 74 insertions, 11 deletions
diff --git a/django/core/handlers/base.py b/django/core/handlers/base.py index 29835d7ce5..214032e318 100644 --- a/django/core/handlers/base.py +++ b/django/core/handlers/base.py @@ -3,6 +3,7 @@ import sys from django import http from django.core import signals from django.dispatch import dispatcher +from django.utils.encoding import force_unicode class BaseHandler(object): # Changes that are always applied to a response (in this order). @@ -73,7 +74,8 @@ class BaseHandler(object): resolver = urlresolvers.RegexURLResolver(r'^/', urlconf) try: - callback, callback_args, callback_kwargs = resolver.resolve(request.path) + callback, callback_args, callback_kwargs = resolver.resolve( + request.path_info) # Apply view middleware for middleware_method in self._view_middleware: @@ -107,8 +109,11 @@ class BaseHandler(object): from django.views import debug return debug.technical_404_response(request, e) else: - callback, param_dict = resolver.resolve404() - return callback(request, **param_dict) + try: + callback, param_dict = resolver.resolve404() + return callback(request, **param_dict) + except: + return self.handle_uncaught_exception(request, resolver, sys.exc_info()) except exceptions.PermissionDenied: return http.HttpResponseForbidden('<h1>Permission denied</h1>') except SystemExit: @@ -118,9 +123,6 @@ class BaseHandler(object): # Get the exception info now, in case another exception is thrown later. exc_info = sys.exc_info() receivers = dispatcher.send(signal=signals.got_request_exception, request=request) - - if settings.DEBUG_PROPAGATE_EXCEPTIONS: - raise return self.handle_uncaught_exception(request, resolver, exc_info) def handle_uncaught_exception(self, request, resolver, exc_info): @@ -136,6 +138,9 @@ class BaseHandler(object): from django.conf import settings from django.core.mail import mail_admins + if settings.DEBUG_PROPAGATE_EXCEPTIONS: + raise + if settings.DEBUG: from django.views import debug return debug.technical_500_response(request, *exc_info) @@ -167,3 +172,27 @@ class BaseHandler(object): response = func(request, response) return response +def get_script_name(environ): + """ + Returns the equivalent of the HTTP request's SCRIPT_NAME environment + variable. If Apache mod_rewrite has been used, returns what would have been + the script name prior to any rewriting (so it's the script name as seen + from the client's perspective), unless DJANGO_USE_POST_REWRITE is set (to + anything). + """ + from django.conf import settings + if settings.FORCE_SCRIPT_NAME is not None: + return force_unicode(settings.FORCE_SCRIPT_NAME) + + # If Apache's mod_rewrite had a whack at the URL, Apache set either + # SCRIPT_URL or REDIRECT_URL to the full resource URL before applying any + # rewrites. Unfortunately not every webserver (lighttpd!) passes this + # information through all the time, so FORCE_SCRIPT_NAME, above, is still + # needed. + script_url = environ.get('SCRIPT_URL', u'') + if not script_url: + script_url = environ.get('REDIRECT_URL', u'') + if script_url: + return force_unicode(script_url[:-len(environ.get('PATH_INFO', ''))]) + return force_unicode(environ.get('SCRIPT_NAME', u'')) + diff --git a/django/core/handlers/modpython.py b/django/core/handlers/modpython.py index 332df6f54c..58699816fd 100644 --- a/django/core/handlers/modpython.py +++ b/django/core/handlers/modpython.py @@ -4,6 +4,7 @@ from pprint import pformat from django import http from django.core import signals from django.core.handlers.base import BaseHandler +from django.core.urlresolvers import set_script_prefix from django.dispatch import dispatcher from django.utils import datastructures from django.utils.encoding import force_unicode, smart_str @@ -15,7 +16,26 @@ from django.utils.encoding import force_unicode, smart_str class ModPythonRequest(http.HttpRequest): def __init__(self, req): self._req = req + # FIXME: This isn't ideal. The request URI may be encoded (it's + # non-normalized) slightly differently to the "real" SCRIPT_NAME + # and PATH_INFO values. This causes problems when we compute path_info, + # below. For now, don't use script names that will be subject to + # encoding/decoding. self.path = force_unicode(req.uri) + root = req.get_options().get('django.root', '') + self.django_root = root + # req.path_info isn't necessarily computed correctly in all + # circumstances (it's out of mod_python's control a bit), so we use + # req.uri and some string manipulations to get the right value. + if root and req.uri.startswith(root): + self.path_info = force_unicode(req.uri[len(root):]) + else: + self.path_info = self.path + if not self.path_info: + # Django prefers empty paths to be '/', rather than '', to give us + # a common start character for URL patterns. So this is a little + # naughty, but also pretty harmless. + self.path_info = u'/' def __repr__(self): # Since this is called as part of error handling, we need to be very @@ -100,7 +120,7 @@ class ModPythonRequest(http.HttpRequest): 'CONTENT_LENGTH': self._req.clength, # This may be wrong 'CONTENT_TYPE': self._req.content_type, # This may be wrong 'GATEWAY_INTERFACE': 'CGI/1.1', - 'PATH_INFO': self._req.path_info, + 'PATH_INFO': self.path_info, 'PATH_TRANSLATED': None, # Not supported 'QUERY_STRING': self._req.args, 'REMOTE_ADDR': self._req.connection.remote_ip, @@ -108,7 +128,7 @@ class ModPythonRequest(http.HttpRequest): 'REMOTE_IDENT': self._req.connection.remote_logname, 'REMOTE_USER': self._req.user, 'REQUEST_METHOD': self._req.method, - 'SCRIPT_NAME': None, # Not supported + 'SCRIPT_NAME': self.django_root, 'SERVER_NAME': self._req.server.server_hostname, 'SERVER_PORT': self._req.server.port, 'SERVER_PROTOCOL': self._req.protocol, @@ -153,6 +173,7 @@ class ModPythonHandler(BaseHandler): if self._request_middleware is None: self.load_middleware() + set_script_prefix(req.get_options().get('django.root', '')) dispatcher.send(signal=signals.request_started) try: try: diff --git a/django/core/handlers/wsgi.py b/django/core/handlers/wsgi.py index 795f139042..a1324936cd 100644 --- a/django/core/handlers/wsgi.py +++ b/django/core/handlers/wsgi.py @@ -7,7 +7,8 @@ except ImportError: from django import http from django.core import signals -from django.core.handlers.base import BaseHandler +from django.core.handlers import base +from django.core.urlresolvers import set_script_prefix from django.dispatch import dispatcher from django.utils import datastructures from django.utils.encoding import force_unicode @@ -74,9 +75,20 @@ def safe_copyfileobj(fsrc, fdst, length=16*1024, size=0): class WSGIRequest(http.HttpRequest): def __init__(self, environ): + script_name = base.get_script_name(environ) + path_info = force_unicode(environ.get('PATH_INFO', u'/')) + if not path_info: + # Sometimes PATH_INFO exists, but is empty (e.g. accessing + # the SCRIPT_NAME URL without a trailing slash). We really need to + # operate as if they'd requested '/'. Not amazingly nice to force + # the path like this, but should be harmless. + path_info = u'/' self.environ = environ - self.path = force_unicode(environ['PATH_INFO']) + self.path_info = path_info + self.path = '%s%s' % (script_name, path_info) self.META = environ + self.META['PATH_INFO'] = path_info + self.META['SCRIPT_NAME'] = script_name self.method = environ['REQUEST_METHOD'].upper() def __repr__(self): @@ -178,7 +190,7 @@ class WSGIRequest(http.HttpRequest): REQUEST = property(_get_request) raw_post_data = property(_get_raw_post_data) -class WSGIHandler(BaseHandler): +class WSGIHandler(base.BaseHandler): initLock = Lock() request_class = WSGIRequest @@ -194,6 +206,7 @@ class WSGIHandler(BaseHandler): self.load_middleware() self.initLock.release() + set_script_prefix(base.get_script_name(environ)) dispatcher.send(signal=signals.request_started) try: try: |