Code

Ticket #18314: TICKET-18314.diff

File TICKET-18314.diff, 5.5 KB (added by yoyoma, 2 years ago)

Patch to fix bug, updated to remove basestring.format() usage

Line 
1diff --git a/django/http/__init__.py b/django/http/__init__.py
2index bf848de..79e5043 100644
3--- a/django/http/__init__.py
4+++ b/django/http/__init__.py
5@@ -205,16 +205,32 @@ class HttpRequest(object):
6 
7     def build_absolute_uri(self, location=None):
8         """
9-        Builds an absolute URI from the location and the variables available in
10-        this request. If no location is specified, the absolute URI is built on
11-        ``request.get_full_path()``.
12+        Builds an absolute URI, using location and/or variables available in
13+        the request, and returns it. If ``location`` is provided and is
14+        absolute, it is simply converted to an RFC 3987 compliant URI and
15+        returned. If ``location`` is provided but is relative or is
16+        scheme-relative (i.e., //example.com/), it is urljoined to a base URL
17+        constructed from the request variables.
18         """
19-        if not location:
20-            location = self.get_full_path()
21-        if not absolute_http_url_re.match(location):
22-            current_uri = '%s://%s%s' % (self.is_secure() and 'https' or 'http',
23-                                         self.get_host(), self.path)
24-            location = urljoin(current_uri, location)
25+        if location is None:
26+            # Build the URI using ``self.get_full_path()``
27+            location = '%(scheme)s//%(host)s%(path)s' % {
28+                'scheme': 'https:' if self.is_secure() else 'http:',
29+                'host': self.get_host(),
30+                'path': self.get_full_path()
31+            }
32+        elif not absolute_http_url_re.match(location):
33+            # The location was explicitly provided, but isn't absolute
34+            base_url = '%(scheme)s//%(host)s%(path)s' % {
35+                'scheme': 'https:' if self.is_secure() else 'http:',
36+                'host': self.get_host(),
37+                'path': self.path
38+            }
39+            # Join the constructed URL with the provided location, which will
40+            # allow the provided ``location`` to apply query strings to the
41+            # base path as well as override the host, if it begins with //
42+            location = urljoin(base_url, location)
43+
44         return iri_to_uri(location)
45 
46     def _is_secure(self):
47@@ -750,4 +766,3 @@ def str_to_unicode(s, encoding):
48         return unicode(s, encoding, 'replace')
49     else:
50         return s
51-
52diff --git a/tests/regressiontests/http/__init__.py b/tests/regressiontests/http/__init__.py
53new file mode 100644
54index 0000000..8b13789
55--- /dev/null
56+++ b/tests/regressiontests/http/__init__.py
57@@ -0,0 +1 @@
58+
59diff --git a/tests/regressiontests/http/models.py b/tests/regressiontests/http/models.py
60new file mode 100644
61index 0000000..8b13789
62--- /dev/null
63+++ b/tests/regressiontests/http/models.py
64@@ -0,0 +1 @@
65+
66diff --git a/tests/regressiontests/http/tests.py b/tests/regressiontests/http/tests.py
67new file mode 100644
68index 0000000..2c62458
69--- /dev/null
70+++ b/tests/regressiontests/http/tests.py
71@@ -0,0 +1,65 @@
72+from django.utils import unittest
73+from django.test.client import RequestFactory
74+
75+
76+class HttpRequestTestCase(unittest.TestCase):
77+    """
78+    Regression tests for ticket # 18314.
79+    """
80+    def setUp(self):
81+        """
82+        Attaches a request factory.
83+        """
84+        self.factory = RequestFactory()
85+
86+    def test_build_absolute_uri_no_location(self):
87+        """
88+        Ensures that ``request.build_absolute_uri()`` returns the proper value
89+        when the ``location`` argument is not provided, and ``request.path``
90+        begins with //.
91+        """
92+        # //// is needed to create a request with a path beginning with //
93+        request = self.factory.get('////django-ate-my-baby')
94+        self.assertEqual(
95+            request.build_absolute_uri(),
96+            'http://testserver//django-ate-my-baby'
97+        )
98+
99+    def test_build_absolute_uri_absolute_location(self):
100+        """
101+        Ensures that ``request.build_absolute_uri()`` returns the proper value
102+        when an absolute URL ``location`` argument is provided, and
103+        ``request.path`` begins with //.
104+        """
105+        # //// is needed to create a request with a path beginning with //
106+        request = self.factory.get('////django-ate-my-baby')
107+        self.assertEqual(
108+            request.build_absolute_uri(location='http://example.com/?foo=bar'),
109+            'http://example.com/?foo=bar'
110+        )
111+
112+    def test_build_absolute_uri_schema_relateive_location(self):
113+        """
114+        Ensures that ``request.build_absolute_uri()`` returns the proper value
115+        when a schema-relative URL ``location`` argument is provided, and
116+        ``request.path`` begins with //.
117+        """
118+        # //// is needed to create a request with a path beginning with //
119+        request = self.factory.get('////django-ate-my-baby')
120+        self.assertEqual(
121+            request.build_absolute_uri(location='//example.com/?foo=bar'),
122+            'http://example.com/?foo=bar'
123+        )
124+
125+    def test_build_absolute_uri_relative_location(self):
126+        """
127+        Ensures that ``request.build_absolute_uri()`` returns the proper value
128+        when a relative URL ``location`` argument is provided, and
129+        ``request.path`` begins with //.
130+        """
131+        # //// is needed to create a request with a path beginning with //
132+        request = self.factory.get('////django-ate-my-baby')
133+        self.assertEqual(
134+            request.build_absolute_uri(location='/foo/bar/'),
135+            'http://testserver/foo/bar/'
136+        )