Fixed #987 -- Convert relative URI portions into absolute URIs in HTTP Location headers. Based on a patch from SmileyChris.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@6164 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
dc785104b8
commit
e70d7e6064
|
@ -50,6 +50,10 @@ class BaseHandler(object):
|
|||
|
||||
def get_response(self, request):
|
||||
"Returns an HttpResponse object for the given HttpRequest"
|
||||
response = self._real_get_response(request)
|
||||
return fix_location_header(request, response)
|
||||
|
||||
def _real_get_response(self, request):
|
||||
from django.core import exceptions, urlresolvers
|
||||
from django.core.mail import mail_admins
|
||||
from django.conf import settings
|
||||
|
@ -129,3 +133,16 @@ class BaseHandler(object):
|
|||
"Helper function to return the traceback as a string"
|
||||
import traceback
|
||||
return '\n'.join(traceback.format_exception(*(exc_info or sys.exc_info())))
|
||||
|
||||
def fix_location_header(request, response):
|
||||
"""
|
||||
Ensure that we always use an absolute URI in any location header in the
|
||||
response. This is required by RFC 2616, section 14.30.
|
||||
|
||||
Code constructing response objects is free to insert relative paths and
|
||||
this function converts them to absolute paths.
|
||||
"""
|
||||
if 'Location' in response.headers and http.get_host(request):
|
||||
response['Location'] = request.build_absolute_uri(response['Location'])
|
||||
return response
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import os
|
|||
from Cookie import SimpleCookie
|
||||
from pprint import pformat
|
||||
from urllib import urlencode
|
||||
from urlparse import urljoin
|
||||
from django.utils.datastructures import MultiValueDict, FileDict
|
||||
from django.utils.encoding import smart_str, iri_to_uri, force_unicode
|
||||
|
||||
|
@ -46,6 +47,20 @@ class HttpRequest(object):
|
|||
def get_full_path(self):
|
||||
return ''
|
||||
|
||||
def build_absolute_uri(self, location=None):
|
||||
"""
|
||||
Builds an absolute URI from the location and the variables available in
|
||||
this request. If no location is specified, the absolute URI is built on
|
||||
``request.get_full_path()``.
|
||||
"""
|
||||
if not location:
|
||||
location = request.get_full_path()
|
||||
if not ':' in location:
|
||||
current_uri = '%s://%s%s' % (self.is_secure() and 'https' or 'http',
|
||||
get_host(self), self.path)
|
||||
location = urljoin(current_uri, location)
|
||||
return location
|
||||
|
||||
def is_secure(self):
|
||||
return os.environ.get("HTTPS") == "on"
|
||||
|
||||
|
|
|
@ -84,12 +84,8 @@ class TestCase(unittest.TestCase):
|
|||
self.assertEqual(response.status_code, status_code,
|
||||
("Response didn't redirect as expected: Response code was %d"
|
||||
" (expected %d)" % (response.status_code, status_code)))
|
||||
scheme, netloc, path, query, fragment = urlsplit(response['Location'])
|
||||
url = path
|
||||
if query:
|
||||
url += '?' + query
|
||||
if fragment:
|
||||
url += '#' + fragment
|
||||
url = response['Location']
|
||||
scheme, netloc, path, query, fragment = urlsplit(url)
|
||||
self.assertEqual(url, expected_url,
|
||||
"Response redirected to '%s', expected '%s'" % (url, expected_url))
|
||||
|
||||
|
|
|
@ -161,6 +161,16 @@ Methods
|
|||
|
||||
Example: ``"/music/bands/the_beatles/?print=true"``
|
||||
|
||||
``build_absolute_uri(location)``
|
||||
Returns the absolute URI form of ``location``. If no location is provided,
|
||||
the location will be set to ``request.get_full_path()``.
|
||||
|
||||
If the location is already an absolute URI, it will not be altered.
|
||||
Otherwise the absolute URI is built using the server variables available in
|
||||
this request.
|
||||
|
||||
Example: ``"http://example.com/music/bands/the_beatles/?print=true"``
|
||||
|
||||
``is_secure()``
|
||||
Returns ``True`` if the request is secure; that is, if it was made with
|
||||
HTTPS.
|
||||
|
|
|
@ -83,10 +83,14 @@ class ClientTest(TestCase):
|
|||
def test_redirect(self):
|
||||
"GET a URL that redirects elsewhere"
|
||||
response = self.client.get('/test_client/redirect_view/')
|
||||
|
||||
# Check that the response was a 302 (redirect)
|
||||
self.assertRedirects(response, '/test_client/get_view/')
|
||||
|
||||
client_providing_host = Client(HTTP_HOST='django.testserver')
|
||||
response = client_providing_host.get('/test_client/redirect_view/')
|
||||
# Check that the response was a 302 (redirect) with absolute URI
|
||||
self.assertRedirects(response, 'http://django.testserver/test_client/get_view/')
|
||||
|
||||
def test_redirect_with_query(self):
|
||||
"GET a URL that redirects with given GET parameters"
|
||||
response = self.client.get('/test_client/redirect_view/', {'var': 'value'})
|
||||
|
@ -97,10 +101,14 @@ class ClientTest(TestCase):
|
|||
def test_permanent_redirect(self):
|
||||
"GET a URL that redirects permanently elsewhere"
|
||||
response = self.client.get('/test_client/permanent_redirect_view/')
|
||||
|
||||
# Check that the response was a 301 (permanent redirect)
|
||||
self.assertRedirects(response, '/test_client/get_view/', status_code=301)
|
||||
|
||||
client_providing_host = Client(HTTP_HOST='django.testserver')
|
||||
response = client_providing_host.get('/test_client/permanent_redirect_view/')
|
||||
# Check that the response was a 301 (permanent redirect) with absolute URI
|
||||
self.assertRedirects(response, 'http://django.testserver/test_client/get_view/', status_code=301)
|
||||
|
||||
def test_redirect_to_strange_location(self):
|
||||
"GET a URL that redirects to a non-200 page"
|
||||
response = self.client.get('/test_client/double_redirect_view/')
|
||||
|
|
Loading…
Reference in New Issue