[Checkins] SVN: zope.server/trunk/ - Implemented proxy support. Proxy requests contain a full URIs and the

Stephan Richter srichter at gmail.com
Sun Aug 1 21:42:41 EDT 2010


Log message for revision 115365:
  - Implemented proxy support. Proxy requests contain a full URIs and the
    request parser used to throw that information away. Using
    ``urlparse.urlsplit()``, all pieces of the URL are recorded.
  
  - The proxy acheme and netloc/hostname are exposed in the WSGI 
    environment as ``zserver.proxy.scheme`` and ``zserver.proxy.host``.
  
  - Made tests runnable via buildout again
  
  - Get ready for release.
  

Changed:
  U   zope.server/trunk/CHANGES.txt
  U   zope.server/trunk/buildout.cfg
  U   zope.server/trunk/setup.py
  U   zope.server/trunk/src/zope/server/http/httprequestparser.py
  U   zope.server/trunk/src/zope/server/http/tests/test_httprequestparser.py
  U   zope.server/trunk/src/zope/server/http/tests/test_wsgiserver.py
  U   zope.server/trunk/src/zope/server/http/wsgihttpserver.py

-=-
Modified: zope.server/trunk/CHANGES.txt
===================================================================
--- zope.server/trunk/CHANGES.txt	2010-08-01 23:19:40 UTC (rev 115364)
+++ zope.server/trunk/CHANGES.txt	2010-08-02 01:42:41 UTC (rev 115365)
@@ -3,12 +3,18 @@
 =======
 
 
-3.6.3 (unreleased)
+3.7.0 (2010-08-01)
 ------------------
 
-- Nothing changed yet.
+- Implemented proxy support. Proxy requests contain a full URIs and the
+  request parser used to throw that information away. Using
+  ``urlparse.urlsplit()``, all pieces of the URL are recorded.
 
+- The proxy acheme and netloc/hostname are exposed in the WSGI environment as
+  ``zserver.proxy.scheme`` and ``zserver.proxy.host``.
 
+- Made tests runnable via buildout again.
+
 3.6.2 (2010-06-11)
 ------------------
 

Modified: zope.server/trunk/buildout.cfg
===================================================================
--- zope.server/trunk/buildout.cfg	2010-08-01 23:19:40 UTC (rev 115364)
+++ zope.server/trunk/buildout.cfg	2010-08-02 01:42:41 UTC (rev 115365)
@@ -10,4 +10,4 @@
 
 [test]
 recipe = zc.recipe.testrunner
-eggs = zope.server
+eggs = zope.server [test]

Modified: zope.server/trunk/setup.py
===================================================================
--- zope.server/trunk/setup.py	2010-08-01 23:19:40 UTC (rev 115364)
+++ zope.server/trunk/setup.py	2010-08-02 01:42:41 UTC (rev 115365)
@@ -26,7 +26,7 @@
 
 setup(
     name='zope.server',
-    version = '3.6.3dev',
+    version = '3.7.0',
     author='Zope Foundation and Contributors',
     author_email='zope-dev at zope.org',
     description='Zope Server (Web and FTP)',
@@ -59,6 +59,11 @@
                         'zope.publisher',
                         'zope.security',
                         ],
+    extras_require = dict([
+        ('test', ['zope.testing',
+                 'zope.i18n',
+                 'zope.component']),
+        ]),
     include_package_data = True,
     zip_safe = False,
     entry_points = """

Modified: zope.server/trunk/src/zope/server/http/httprequestparser.py
===================================================================
--- zope.server/trunk/src/zope/server/http/httprequestparser.py	2010-08-01 23:19:40 UTC (rev 115364)
+++ zope.server/trunk/src/zope/server/http/httprequestparser.py	2010-08-02 01:42:41 UTC (rev 115365)
@@ -18,6 +18,7 @@
 """
 import re
 from urllib import unquote
+import urlparse
 
 from zope.server.fixedstreamreceiver import FixedStreamReceiver
 from zope.server.buffers import OverflowableBuffer
@@ -172,7 +173,7 @@
         return r
 
     first_line_re = re.compile (
-        '([^ ]+) (?:[^ :?#]+://[^ ?#/]*)?([^ ]+)(( HTTP/([0-9.]+))$|$)')
+        '([^ ]+) ((?:[^ :?#]+://[^ ?#/]*(?:[0-9]{1,5})?)?[^ ]+)(( HTTP/([0-9.]+))$|$)')
 
     def crack_first_line(self):
         r = self.first_line
@@ -186,23 +187,14 @@
         else:
             return None, None, None
 
-    path_regex = re.compile (
-    #     path    query     fragment
-        r'([^?#]*)(\?[^#]*)?(#.*)?'
-        )
-
     def split_uri(self):
-        m = self.path_regex.match (self.uri)
-        if m.end() != len(self.uri):
-            raise ValueError("Broken URI")
-        else:
-            path, query, self.fragment = m.groups()
-            if path and '%' in path:
-                path = unquote(path)
-            self.path = path
-            if query:
-                query = query[1:]
-            self.query = query
+        (self.proxy_scheme, self.proxy_netloc, path, self.query, self.fragment) = \
+            urlparse.urlsplit(self.uri)
+        if path and '%' in path:
+            path = unquote(path)
+        self.path = path
+        if self.query == '':
+            self.query = None
 
     def getBodyStream(self):
         body_rcv = self.body_rcv

Modified: zope.server/trunk/src/zope/server/http/tests/test_httprequestparser.py
===================================================================
--- zope.server/trunk/src/zope/server/http/tests/test_httprequestparser.py	2010-08-01 23:19:40 UTC (rev 115364)
+++ zope.server/trunk/src/zope/server/http/tests/test_httprequestparser.py	2010-08-02 01:42:41 UTC (rev 115365)
@@ -56,6 +56,8 @@
         self.assertEqual(parser.path, '/foobar')
         self.assertEqual(parser.command, 'GET')
         self.assertEqual(parser.query, None)
+        self.assertEqual(parser.proxy_scheme, '')
+        self.assertEqual(parser.proxy_netloc, '')
         self.assertEqual(parser.getBodyStream().getvalue(), 'Hello.\n')
 
     def testComplexGET(self):
@@ -83,6 +85,29 @@
                          'd=b+%2B%2F%3D%26b%3Aint&c+%2B%2F%3D%26c%3Aint=6')
         self.assertEqual(parser.getBodyStream().getvalue(), 'Hello mick')
 
+    def testProxyGET(self):
+        data = """\
+GET https://example.com:8080/foobar HTTP/8.4
+content-length: 7
+
+Hello.
+"""
+        parser = self.parser
+        self.feed(data)
+        self.failUnless(parser.completed)
+        self.assertEqual(parser.version, '8.4')
+        self.failIf(parser.empty)
+        self.assertEqual(parser.headers,
+                         {'CONTENT_LENGTH': '7',
+                          })
+        self.assertEqual(parser.path, '/foobar')
+        self.assertEqual(parser.command, 'GET')
+        self.assertEqual(parser.proxy_scheme, 'https')
+        self.assertEqual(parser.proxy_netloc, 'example.com:8080')
+        self.assertEqual(parser.command, 'GET')
+        self.assertEqual(parser.query, None)
+        self.assertEqual(parser.getBodyStream().getvalue(), 'Hello.\n')
+
     def testDuplicateHeaders(self):
         # Ensure that headers with the same key get concatenated as per
         # RFC2616.

Modified: zope.server/trunk/src/zope/server/http/tests/test_wsgiserver.py
===================================================================
--- zope.server/trunk/src/zope/server/http/tests/test_wsgiserver.py	2010-08-01 23:19:40 UTC (rev 115364)
+++ zope.server/trunk/src/zope/server/http/tests/test_wsgiserver.py	2010-08-02 01:42:41 UTC (rev 115365)
@@ -116,6 +116,14 @@
         """Return whether WSGI app is invoked only once or not"""
         return str(bool(REQUEST['wsgi.run_once']))
 
+    def proxy_scheme(self, REQUEST):
+        """Return the proxy scheme."""
+        return REQUEST['zserver.proxy.scheme']
+
+    def proxy_host(self, REQUEST):
+        """Return the proxy host."""
+        return REQUEST['zserver.proxy.host']
+
 class Tests(PlacelessSetup, unittest.TestCase):
 
     def setUp(self):
@@ -252,6 +260,14 @@
         status, response_body = self.invokeRequest('/wsgi/run_once')
         self.assertEqual('False', response_body)
 
+    def testWSGIProxy(self):
+        status, response_body = self.invokeRequest(
+            'https://zope.org:8080/wsgi/proxy_scheme')
+        self.assertEqual('https', response_body)
+        status, response_body = self.invokeRequest(
+            'https://zope.org:8080/wsgi/proxy_host')
+        self.assertEqual('zope.org:8080', response_body)
+
     def test_server_uses_iterable(self):
         # Make sure that the task write method isn't called with a
         # str or non iterable

Modified: zope.server/trunk/src/zope/server/http/wsgihttpserver.py
===================================================================
--- zope.server/trunk/src/zope/server/http/wsgihttpserver.py	2010-08-01 23:19:40 UTC (rev 115364)
+++ zope.server/trunk/src/zope/server/http/wsgihttpserver.py	2010-08-02 01:42:41 UTC (rev 115365)
@@ -61,6 +61,15 @@
         env['wsgi.multiprocess'] = True
         env['wsgi.run_once'] = False
         env['wsgi.input'] = task.request_data.getBodyStream()
+
+        # Add some proprietary proxy information.
+        # Note: Derived request parsers might not have these new attributes,
+        # so fail gracefully.
+        try:
+            env['zserver.proxy.scheme'] = task.request_data.proxy_scheme
+            env['zserver.proxy.host'] = task.request_data.proxy_netloc
+        except AttributeError:
+            pass
         return env
 
     def executeRequest(self, task):



More information about the checkins mailing list