[Checkins] SVN: zope.server/trunk/ - When the result of a WSGI application was received, ``task.write()`` was

Stephan Richter srichter at gmail.com
Tue Aug 24 15:12:50 EDT 2010


Log message for revision 115921:
  - When the result of a WSGI application was received, ``task.write()`` was
    only called once to transmit the data. This prohibited the transmission of
    partial results. Now the WSGI server iterates through the result itself
    making multiple ``task.write()`` calls, which will cause partial data to be
    transmitted.
  
  - Created a second test case instance for the post-mortem WSGI server, so it
    is tested as well.
  
  - Get ready for release.
  
  

Changed:
  U   zope.server/trunk/CHANGES.txt
  U   zope.server/trunk/setup.py
  U   zope.server/trunk/src/zope/server/dualmodechannel.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-24 15:30:57 UTC (rev 115920)
+++ zope.server/trunk/CHANGES.txt	2010-08-24 19:12:50 UTC (rev 115921)
@@ -3,9 +3,18 @@
 =======
 
 
-3.8.1 (unreleased)
+3.8.1 (2010-08-24)
 ------------------
 
+- When the result of a WSGI application was received, ``task.write()`` was
+  only called once to transmit the data. This prohibited the transmission of
+  partial results. Now the WSGI server iterates through the result itself
+  making multiple ``task.write()`` calls, which will cause partial data to be
+  transmitted.
+
+- Created a second test case instance for the post-mortem WSGI server, so it
+  is tested as well.
+
 - Using python's ``doctest`` module instead of deprecated
   ``zope.testing.doctest``.
 

Modified: zope.server/trunk/setup.py
===================================================================
--- zope.server/trunk/setup.py	2010-08-24 15:30:57 UTC (rev 115920)
+++ zope.server/trunk/setup.py	2010-08-24 19:12:50 UTC (rev 115921)
@@ -26,7 +26,7 @@
 
 setup(
     name='zope.server',
-    version = '3.8.1dev',
+    version = '3.8.1',
     author='Zope Foundation and Contributors',
     author_email='zope-dev at zope.org',
     description='Zope Server (Web and FTP)',

Modified: zope.server/trunk/src/zope/server/dualmodechannel.py
===================================================================
--- zope.server/trunk/src/zope/server/dualmodechannel.py	2010-08-24 15:30:57 UTC (rev 115920)
+++ zope.server/trunk/src/zope/server/dualmodechannel.py	2010-08-24 19:12:50 UTC (rev 115921)
@@ -154,7 +154,7 @@
         if isinstance(data, str):
             if data:
                 self.outbuf.append(data)
-                wrote = len(data) 
+                wrote = len(data)
         else:
             for v in data:
                 if v:

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-24 15:30:57 UTC (rev 115920)
+++ zope.server/trunk/src/zope/server/http/tests/test_wsgiserver.py	2010-08-24 19:12:50 UTC (rev 115921)
@@ -131,10 +131,13 @@
 
 class Tests(PlacelessSetup, unittest.TestCase):
 
-    def setUp(self):
+    def _getServerClass(self):
         # import only now to prevent the testrunner from importing it too early
         # Otherwise dualmodechannel.the_trigger is closed by the ZEO tests
         from zope.server.http.wsgihttpserver import WSGIHTTPServer
+        return WSGIHTTPServer
+
+    def setUp(self):
         super(Tests, self).setUp()
         zope.component.provideAdapter(HTTPCharsets, [IHTTPRequest],
                                       IUserPreferredCharsets, '')
@@ -156,8 +159,9 @@
 
         td.setThreadCount(4)
         # Bind to any port on localhost.
-        self.server = WSGIHTTPServer(application, 'Browser',
-                                     LOCALHOST, 0, task_dispatcher=td)
+        ServerClass = self._getServerClass()
+        self.server = ServerClass(application, 'Browser',
+                                  LOCALHOST, 0, task_dispatcher=td)
 
         self.port = self.server.socket.getsockname()[1]
         self.run_loop = 1
@@ -290,10 +294,17 @@
             '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
+    def test_ensure_multiple_task_write_calls(self):
+        # In order to get data out as fast as possible, the WSGI server needs
+        # to call task.write() multiple times.
+        orig_app = self.server.application
+        def app(eviron, start_response):
+            start_response('200 Ok', [])
+            return ['This', 'is', 'my', 'response.']
+        self.server.application = app
+
         class FakeTask:
+            counter = 0
             getCGIEnvironment = lambda _: {}
             class request_data:
                 getBodyStream = lambda _: StringIO.StringIO()
@@ -301,14 +312,39 @@
             setResponseStatus = appendResponseHeaders = lambda *_: None
 
             def write(self, v):
-                if isinstance(v, str):
-                    raise TypeError("Should only write iterables")
-                list(v)
-        self.server.executeRequest(FakeTask())
+                self.counter += 1
 
+        task = FakeTask()
+        self.server.executeRequest(task)
+        self.assertEqual(task.counter, 4)
 
+        self.server.application = orig_app
+
+
+class PMDBTests(Tests):
+
+    def _getServerClass(self):
+        # import only now to prevent the testrunner from importing it too early
+        # Otherwise dualmodechannel.the_trigger is closed by the ZEO tests
+        from zope.server.http.wsgihttpserver import PMDBWSGIHTTPServer
+        return PMDBWSGIHTTPServer
+
+    def testWSGIVariables(self):
+        # Assert that the environment contains all required WSGI variables
+        status, response_body = self.invokeRequest('/wsgi')
+        wsgi_variables = set(response_body.split())
+        self.assertEqual(wsgi_variables,
+                         set(['wsgi.version', 'wsgi.url_scheme', 'wsgi.input',
+                              'wsgi.errors', 'wsgi.multithread',
+                              'wsgi.multiprocess', 'wsgi.handleErrors',
+                              'wsgi.run_once']))
+
+
 def test_suite():
-    return unittest.TestSuite(unittest.makeSuite(Tests))
+    return unittest.TestSuite((
+        unittest.makeSuite(Tests),
+        unittest.makeSuite(PMDBTests),
+        ))
 
 if __name__ == '__main__':
     unittest.main(defaultTest='test_suite')

Modified: zope.server/trunk/src/zope/server/http/wsgihttpserver.py
===================================================================
--- zope.server/trunk/src/zope/server/http/wsgihttpserver.py	2010-08-24 15:30:57 UTC (rev 115920)
+++ zope.server/trunk/src/zope/server/http/wsgihttpserver.py	2010-08-24 19:12:50 UTC (rev 115921)
@@ -86,7 +86,11 @@
             return fakeWrite
 
         # Call the application to handle the request and write a response
-        task.write(self.application(env, start_response))
+        result = self.application(env, start_response)
+        # By iterating manually at this point, we execute task.write()
+        # multiple times, allowing partial data to be sent.
+        for value in result:
+            task.write(value)
 
 
 class PMDBWSGIHTTPServer(WSGIHTTPServer):
@@ -108,7 +112,11 @@
 
         # Call the application to handle the request and write a response
         try:
-            task.write(self.application(env, start_response))
+            result = self.application(env, start_response)
+            # By iterating manually at this point, we execute task.write()
+            # multiple times, allowing partial data to be sent.
+            for value in result:
+                task.write(value)
         except:
             import sys, pdb
             print "%s:" % sys.exc_info()[0]



More information about the checkins mailing list