Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed #987 -- Convert relative URI portions into absolute URIs in HTT…

…P Location headers. Based on a patch from SmileyChris.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@6164 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit e70d7e60640e280f8d410d41c1f9cb6195483c4e 1 parent dc78510
Malcolm Tredinnick malcolmt authored
17 django/core/handlers/base.py
View
@@ -50,6 +50,10 @@ def load_middleware(self):
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 @@ def _get_traceback(self, exc_info=None):
"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
+
17 django/http/__init__.py
View
@@ -2,6 +2,7 @@
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
@@ -42,10 +43,24 @@ def has_key(self, key):
return key in self.GET or key in self.POST
__contains__ = has_key
-
+
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"
8 django/test/testcases.py
View
@@ -84,12 +84,8 @@ def assertRedirects(self, response, expected_url, status_code=302,
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))
10 docs/request_response.txt
View
@@ -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.
12 tests/modeltests/test_client/models.py
View
@@ -83,9 +83,13 @@ def test_raw_post(self):
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"
@@ -97,10 +101,14 @@ def test_redirect_with_query(self):
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/')
Please sign in to comment.
Something went wrong with that request. Please try again.