Author: mtredinnick
Date: 2007-09-14 00:28:00 -0500 (Fri, 14 Sep 2007)
New Revision: 6164
Modified:
django/trunk/django/core/handlers/base.py
django/trunk/django/http/__init__.py
django/trunk/django/test/testcases.py
django/trunk/docs/request_response.txt
django/trunk/tests/modeltests/test_client/models.py
Log:
Fixed #987 -- Convert relative URI portions into absolute URIs in HTTP Location
headers. Based on a patch from SmileyChris.
Modified: django/trunk/django/core/handlers/base.py
===================================================================
--- django/trunk/django/core/handlers/base.py 2007-09-14 04:55:09 UTC (rev
6163)
+++ django/trunk/django/core/handlers/base.py 2007-09-14 05:28:00 UTC (rev
6164)
@@ -50,6 +50,10 @@
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 @@
"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
+
Modified: django/trunk/django/http/__init__.py
===================================================================
--- django/trunk/django/http/__init__.py 2007-09-14 04:55:09 UTC (rev
6163)
+++ django/trunk/django/http/__init__.py 2007-09-14 05:28:00 UTC (rev
6164)
@@ -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 @@
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"
Modified: django/trunk/django/test/testcases.py
===================================================================
--- django/trunk/django/test/testcases.py 2007-09-14 04:55:09 UTC (rev
6163)
+++ django/trunk/django/test/testcases.py 2007-09-14 05:28:00 UTC (rev
6164)
@@ -84,12 +84,8 @@
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))
Modified: django/trunk/docs/request_response.txt
===================================================================
--- django/trunk/docs/request_response.txt 2007-09-14 04:55:09 UTC (rev
6163)
+++ django/trunk/docs/request_response.txt 2007-09-14 05:28:00 UTC (rev
6164)
@@ -161,6 +161,16 @@
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.
Modified: django/trunk/tests/modeltests/test_client/models.py
===================================================================
--- django/trunk/tests/modeltests/test_client/models.py 2007-09-14 04:55:09 UTC
(rev 6163)
+++ django/trunk/tests/modeltests/test_client/models.py 2007-09-14 05:28:00 UTC
(rev 6164)
@@ -83,9 +83,13 @@
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_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/')
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/django-updates?hl=en
-~----------~----~----~----~------~----~------~--~---