diff --git a/django/core/handlers/base.py b/django/core/handlers/base.py index f63b28dc66..b1de2831b3 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: @@ -170,3 +172,20 @@ 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). + + Note: this isn't used by the mod_python handler, since the equivalent of + SCRIPT_NAME isn't available there. + """ + # If mod_rewrite had a whack at the URL, Apache set SCRIPT_URL to + # SCRIPT_NAME before applying any rewrites. + script_url = force_unicode(environ.get('SCRIPT_URL', '')) + if script_url: + return script_url + return force_unicode(environ.get('SCRIPT_NAME', '')) + diff --git a/django/core/handlers/modpython.py b/django/core/handlers/modpython.py index 332df6f54c..a2d9db8ba4 100644 --- a/django/core/handlers/modpython.py +++ b/django/core/handlers/modpython.py @@ -16,6 +16,15 @@ class ModPythonRequest(http.HttpRequest): def __init__(self, req): self._req = req 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 def __repr__(self): # Since this is called as part of error handling, we need to be very @@ -100,7 +109,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 +117,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, diff --git a/django/core/handlers/wsgi.py b/django/core/handlers/wsgi.py index 795f139042..15708c9a91 100644 --- a/django/core/handlers/wsgi.py +++ b/django/core/handlers/wsgi.py @@ -7,7 +7,7 @@ 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.dispatch import dispatcher from django.utils import datastructures from django.utils.encoding import force_unicode @@ -74,9 +74,14 @@ def safe_copyfileobj(fsrc, fdst, length=16*1024, size=0): class WSGIRequest(http.HttpRequest): def __init__(self, environ): + script_name = base.get_script_name() + path_info = force_unicode(environ.get('PATH_INFO', '/')) 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 +183,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 diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py index ff0bcbcfea..c25e99fdd2 100644 --- a/django/core/urlresolvers.py +++ b/django/core/urlresolvers.py @@ -291,10 +291,11 @@ class RegexURLResolver(object): def resolve(path, urlconf=None): return get_resolver(urlconf).resolve(path) -def reverse(viewname, urlconf=None, args=None, kwargs=None): +def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=u'/'): args = args or [] kwargs = kwargs or {} - return iri_to_uri(u'/' + get_resolver(urlconf).reverse(viewname, *args, **kwargs)) + return iri_to_uri(prefix + + get_resolver(urlconf).reverse(viewname, *args, **kwargs)) def clear_url_caches(): global _resolver_cache diff --git a/django/http/__init__.py b/django/http/__init__.py index ef15479983..fe0b93edcf 100644 --- a/django/http/__init__.py +++ b/django/http/__init__.py @@ -31,6 +31,7 @@ class HttpRequest(object): def __init__(self): self.GET, self.POST, self.COOKIES, self.META, self.FILES = {}, {}, {}, {}, {} self.path = '' + self.path_info = '' self.method = None def __repr__(self): @@ -442,3 +443,4 @@ def str_to_unicode(s, encoding): return unicode(s, encoding, 'replace') else: return s + diff --git a/django/test/client.py b/django/test/client.py index 47c12a4ca1..7d621449ea 100644 --- a/django/test/client.py +++ b/django/test/client.py @@ -190,7 +190,7 @@ class Client: 'PATH_INFO': '/', 'QUERY_STRING': '', 'REQUEST_METHOD': 'GET', - 'SCRIPT_NAME': None, + 'SCRIPT_NAME': '', 'SERVER_NAME': 'testserver', 'SERVER_PORT': 80, 'SERVER_PROTOCOL': 'HTTP/1.1',