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
-~----------~----~----~----~------~----~------~--~---

Reply via email to