Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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 authored September 14, 2007
17  django/core/handlers/base.py
@@ -50,6 +50,10 @@ def load_middleware(self):
50 50
 
51 51
     def get_response(self, request):
52 52
         "Returns an HttpResponse object for the given HttpRequest"
  53
+        response = self._real_get_response(request)
  54
+        return fix_location_header(request, response)
  55
+
  56
+    def _real_get_response(self, request):
53 57
         from django.core import exceptions, urlresolvers
54 58
         from django.core.mail import mail_admins
55 59
         from django.conf import settings
@@ -129,3 +133,16 @@ def _get_traceback(self, exc_info=None):
129 133
         "Helper function to return the traceback as a string"
130 134
         import traceback
131 135
         return '\n'.join(traceback.format_exception(*(exc_info or sys.exc_info())))
  136
+
  137
+def fix_location_header(request, response):
  138
+    """
  139
+    Ensure that we always use an absolute URI in any location header in the
  140
+    response. This is required by RFC 2616, section 14.30.
  141
+
  142
+    Code constructing response objects is free to insert relative paths and
  143
+    this function converts them to absolute paths.
  144
+    """
  145
+    if 'Location' in response.headers and http.get_host(request):
  146
+        response['Location'] = request.build_absolute_uri(response['Location'])
  147
+    return response
  148
+
17  django/http/__init__.py
@@ -2,6 +2,7 @@
2 2
 from Cookie import SimpleCookie
3 3
 from pprint import pformat
4 4
 from urllib import urlencode
  5
+from urlparse import urljoin
5 6
 from django.utils.datastructures import MultiValueDict, FileDict
6 7
 from django.utils.encoding import smart_str, iri_to_uri, force_unicode
7 8
 
@@ -42,10 +43,24 @@ def has_key(self, key):
42 43
         return key in self.GET or key in self.POST
43 44
 
44 45
     __contains__ = has_key
45  
-        
  46
+
46 47
     def get_full_path(self):
47 48
         return ''
48 49
 
  50
+    def build_absolute_uri(self, location=None):
  51
+        """
  52
+        Builds an absolute URI from the location and the variables available in
  53
+        this request. If no location is specified, the absolute URI is built on
  54
+        ``request.get_full_path()``.
  55
+        """
  56
+        if not location:
  57
+            location = request.get_full_path()
  58
+        if not ':' in location:
  59
+            current_uri = '%s://%s%s' % (self.is_secure() and 'https' or 'http',
  60
+                                         get_host(self), self.path)
  61
+            location = urljoin(current_uri, location)
  62
+        return location
  63
+
49 64
     def is_secure(self):
50 65
         return os.environ.get("HTTPS") == "on"
51 66
 
8  django/test/testcases.py
@@ -84,12 +84,8 @@ def assertRedirects(self, response, expected_url, status_code=302,
84 84
         self.assertEqual(response.status_code, status_code,
85 85
             ("Response didn't redirect as expected: Response code was %d"
86 86
              " (expected %d)" % (response.status_code, status_code)))
87  
-        scheme, netloc, path, query, fragment = urlsplit(response['Location'])
88  
-        url = path
89  
-        if query:
90  
-            url += '?' + query
91  
-        if fragment:
92  
-            url += '#' + fragment
  87
+        url = response['Location']
  88
+        scheme, netloc, path, query, fragment = urlsplit(url)
93 89
         self.assertEqual(url, expected_url,
94 90
             "Response redirected to '%s', expected '%s'" % (url, expected_url))
95 91
 
10  docs/request_response.txt
@@ -161,6 +161,16 @@ Methods
161 161
 
162 162
    Example: ``"/music/bands/the_beatles/?print=true"``
163 163
 
  164
+``build_absolute_uri(location)``
  165
+   Returns the absolute URI form of ``location``. If no location is provided,
  166
+   the location will be set to ``request.get_full_path()``.
  167
+
  168
+   If the location is already an absolute URI, it will not be altered.
  169
+   Otherwise the absolute URI is built using the server variables available in
  170
+   this request.
  171
+
  172
+   Example: ``"http://example.com/music/bands/the_beatles/?print=true"``
  173
+
164 174
 ``is_secure()``
165 175
    Returns ``True`` if the request is secure; that is, if it was made with
166 176
    HTTPS.
12  tests/modeltests/test_client/models.py
@@ -83,9 +83,13 @@ def test_raw_post(self):
83 83
     def test_redirect(self):
84 84
         "GET a URL that redirects elsewhere"
85 85
         response = self.client.get('/test_client/redirect_view/')
86  
-        
87 86
         # Check that the response was a 302 (redirect)
88 87
         self.assertRedirects(response, '/test_client/get_view/')
  88
+        
  89
+        client_providing_host = Client(HTTP_HOST='django.testserver')
  90
+        response = client_providing_host.get('/test_client/redirect_view/')
  91
+        # Check that the response was a 302 (redirect) with absolute URI
  92
+        self.assertRedirects(response, 'http://django.testserver/test_client/get_view/')
89 93
     
90 94
     def test_redirect_with_query(self):
91 95
         "GET a URL that redirects with given GET parameters"
@@ -97,10 +101,14 @@ def test_redirect_with_query(self):
97 101
     def test_permanent_redirect(self):
98 102
         "GET a URL that redirects permanently elsewhere"
99 103
         response = self.client.get('/test_client/permanent_redirect_view/')
100  
-        
101 104
         # Check that the response was a 301 (permanent redirect)
102 105
         self.assertRedirects(response, '/test_client/get_view/', status_code=301)
103 106
 
  107
+        client_providing_host = Client(HTTP_HOST='django.testserver')
  108
+        response = client_providing_host.get('/test_client/permanent_redirect_view/')
  109
+        # Check that the response was a 301 (permanent redirect) with absolute URI
  110
+        self.assertRedirects(response, 'http://django.testserver/test_client/get_view/', status_code=301)
  111
+
104 112
     def test_redirect_to_strange_location(self):
105 113
         "GET a URL that redirects to a non-200 page"
106 114
         response = self.client.get('/test_client/double_redirect_view/')

0 notes on commit e70d7e6

Please sign in to comment.
Something went wrong with that request. Please try again.