[Checkins] SVN: zope.publisher/trunk/ Fixed the check for untrusted redirects introduced in 3.9.0 so it works with virtual hosting.

Thomas Lotze tl at gocept.com
Thu Oct 8 05:37:22 EDT 2009


Log message for revision 104912:
  Fixed the check for untrusted redirects introduced in 3.9.0 so it works with virtual hosting.

Changed:
  U   zope.publisher/trunk/CHANGES.txt
  U   zope.publisher/trunk/src/zope/publisher/http.py
  U   zope.publisher/trunk/src/zope/publisher/tests/test_http.py

-=-
Modified: zope.publisher/trunk/CHANGES.txt
===================================================================
--- zope.publisher/trunk/CHANGES.txt	2009-10-08 09:25:43 UTC (rev 104911)
+++ zope.publisher/trunk/CHANGES.txt	2009-10-08 09:37:22 UTC (rev 104912)
@@ -4,9 +4,9 @@
 3.9.3 (unreleased)
 ------------------
 
-- Nothing changed yet.
+- Fixed the check for untrusted redirects introduced in 3.9.0 so it works with
+  virtual hosting.
 
-
 3.9.2 (2009-10-07)
 ------------------
 

Modified: zope.publisher/trunk/src/zope/publisher/http.py
===================================================================
--- zope.publisher/trunk/src/zope/publisher/http.py	2009-10-08 09:25:43 UTC (rev 104911)
+++ zope.publisher/trunk/src/zope/publisher/http.py	2009-10-08 09:37:22 UTC (rev 104912)
@@ -874,17 +874,19 @@
 
     def redirect(self, location, status=None, trusted=False):
         """Causes a redirection without raising an error"""
-        
+
         # convert to a string, as the location could be non-string
         # convertable to string, for example, an URLGetter instance
         location = str(location)
-        
+
         if not trusted:
-            scheme, target_host, path, query, fragment = (
-                urlparse.urlsplit(location))
-            if target_host and target_host != self._request.get('HTTP_HOST'):
-                raise ValueError(
-                    "Untrusted redirect to host %r not allowed." % target_host)
+            target_host = extract_host(location)
+            if target_host:
+                app_host = extract_host(self._request.getApplicationURL())
+                if target_host != app_host:
+                    raise ValueError(
+                        "Untrusted redirect to host %r not allowed."
+                        % target_host)
 
         if status is None:
             # parse the HTTP version and set default accordingly
@@ -938,6 +940,15 @@
     return cmp(y, x)
 
 
+def extract_host(url):
+    scheme, host, path, query, fragment = urlparse.urlsplit(url)
+    if ':' not in host:
+        port = DEFAULT_PORTS.get(scheme)
+        if port:
+            host = '%s:%s' % (host, port)
+    return host
+
+
 class HTTPCharsets(object):
     zope.component.adapts(IHTTPRequest)
     zope.interface.implements(IUserPreferredCharsets)

Modified: zope.publisher/trunk/src/zope/publisher/tests/test_http.py
===================================================================
--- zope.publisher/trunk/src/zope/publisher/tests/test_http.py	2009-10-08 09:25:43 UTC (rev 104911)
+++ zope.publisher/trunk/src/zope/publisher/tests/test_http.py	2009-10-08 09:37:22 UTC (rev 104912)
@@ -308,6 +308,34 @@
             'http://my-friends.com', trusted=True)
         self.assertEquals('http://my-friends.com', location)
 
+        # We can redirect to our own full server URL, with or without a port
+        # being specified. Let's explicitly set a host name to test this is
+        # this is how virtual hosting works:
+        request.setApplicationServer('example.com')
+        location = request.response.redirect('http://example.com')
+        self.assertEquals('http://example.com', location)
+
+        request.setApplicationServer('example.com', port=8080)
+        location = request.response.redirect('http://example.com:8080')
+        self.assertEquals('http://example.com:8080', location)
+
+        # The default port for HTTP and HTTPS may be omitted:
+        request.setApplicationServer('example.com')
+        location = request.response.redirect('http://example.com:80')
+        self.assertEquals('http://example.com:80', location)
+
+        request.setApplicationServer('example.com', port=80)
+        location = request.response.redirect('http://example.com')
+        self.assertEquals('http://example.com', location)
+
+        request.setApplicationServer('example.com', 'https')
+        location = request.response.redirect('https://example.com:443')
+        self.assertEquals('https://example.com:443', location)
+
+        request.setApplicationServer('example.com', 'https', 443)
+        location = request.response.redirect('https://example.com')
+        self.assertEquals('https://example.com', location)
+
     def testUnregisteredStatus(self):
         # verify we can set the status to an unregistered int value
         request = self._createRequest({}, '')



More information about the checkins mailing list