[Checkins] SVN: zope.server/branches/achapman-exc-info/src/zope/server/http/ further compliance with WSGI PEP.

Satchidanand Haridas satchit at zope.com
Tue May 17 10:14:21 EDT 2011


Log message for revision 121687:
  further compliance with WSGI PEP.
  
  and tests.
  
  

Changed:
  U   zope.server/branches/achapman-exc-info/src/zope/server/http/tests/test_wsgiserver.py
  U   zope.server/branches/achapman-exc-info/src/zope/server/http/wsgihttpserver.py

-=-
Modified: zope.server/branches/achapman-exc-info/src/zope/server/http/tests/test_wsgiserver.py
===================================================================
--- zope.server/branches/achapman-exc-info/src/zope/server/http/tests/test_wsgiserver.py	2011-05-17 12:41:54 UTC (rev 121686)
+++ zope.server/branches/achapman-exc-info/src/zope/server/http/tests/test_wsgiserver.py	2011-05-17 14:14:20 UTC (rev 121687)
@@ -312,13 +312,15 @@
         self.server.application = app
 
         class FakeTask:
+            wrote_header = 0
             counter = 0
             getCGIEnvironment = lambda _: {}
             class request_data:
                 getBodyStream = lambda _: StringIO.StringIO()
             request_data = request_data()
             setResponseStatus = appendResponseHeaders = lambda *_: None
-
+            def wroteResponseHeader(self):
+                return self.wrote_header
             def write(self, v):
                 self.counter += 1
 
@@ -334,7 +336,10 @@
             try:
                 raise DummyException()
             except DummyException as e:
-                start_response('500 Internal Error', [], sys.exc_info())
+                start_response(
+                    '500 Internal Error',
+                    [('Content-type', 'text/plain')],
+                    sys.exc_info())
                 return ERROR_RESPONSE.split()
             return RESPONSE.split()
 
@@ -343,11 +348,16 @@
             status = None
             reason = None
             response = []
+            accumulated_headers = []
             getCGIEnvironment = lambda _: {}
             class request_data:
                 getBodyStream = lambda _: StringIO.StringIO()
             request_data = request_data()
-            appendResponseHeaders = lambda *_: None
+            def appendResponseHeaders(self, lst):
+                accum = self.accumulated_headers
+                if accum is None:
+                    self.accumulated_headers = accum = []
+                accum.extend(lst)
             def setResponseStatus(self, status, reason):
                 self.status = status
                 self.reason = reason
@@ -363,13 +373,27 @@
         # start_response exc_info if no headers have been sent
         orig_app = self.server.application
         self.server.application, task = self._getFakeAppAndTask()
+        task.accumulated_headers = ['header1', 'header2']
 
         self.server.executeRequest(task)
 
         self.assertEqual(task.status, "500")
         self.assertEqual(task.response, ERROR_RESPONSE.split())
+        # any headers written before are cleared and
+        # only the most recent one is added.
+        self.assertEqual(task.accumulated_headers, ['Content-type: text/plain'])
 
+        self.server.application = orig_app
 
+
+    def test_multiple_start_response_calls(self):
+        # if start_response is called more than once with no exc_info
+        ignore, task = self._getFakeAppAndTask()
+        task.wrote_header = 1
+
+        self.assertRaises(AssertionError, self.server.executeRequest, task)
+
+
     def test_start_response_with_headers_sent(self):
         # If headers have been sent it raises the exception
         orig_app = self.server.application
@@ -399,6 +423,26 @@
                               'wsgi.multiprocess', 'wsgi.handleErrors',
                               'wsgi.run_once']))
 
+    def test_multiple_start_response_calls(self):
+        # if start_response is called more than once with no exc_info
+        ignore, task = self._getFakeAppAndTask()
+        task.wrote_header = 1
+
+        # monkey-patch pdb.post_mortem so we don't go into pdb session.
+        pm_traceback = []
+        def fake_post_mortem(tb):
+            import traceback
+            pm_traceback.extend(traceback.format_tb(tb))
+
+        import pdb
+        orig_post_mortem = pdb.post_mortem
+        pdb.post_mortem = fake_post_mortem
+
+        self.assertRaises(AssertionError, self.server.executeRequest, task)
+        expected_msg = "start_response called a second time"
+        self.assertTrue(expected_msg in pm_traceback[-1])
+        pdb.post_mortem = orig_post_mortem
+
     def test_start_response_with_headers_sent(self):
         # If headers have been sent it raises the exception, which will
         # be caught by the server and invoke pdb.post_mortem.
@@ -418,6 +462,7 @@
 
         self.assertRaises(DummyException, self.server.executeRequest, task)
         self.assertTrue("raise DummyException" in pm_traceback[-1])
+
         self.server.application = orig_app
         pdb.post_mortem = orig_post_mortem
 

Modified: zope.server/branches/achapman-exc-info/src/zope/server/http/wsgihttpserver.py
===================================================================
--- zope.server/branches/achapman-exc-info/src/zope/server/http/wsgihttpserver.py	2011-05-17 12:41:54 UTC (rev 121686)
+++ zope.server/branches/achapman-exc-info/src/zope/server/http/wsgihttpserver.py	2011-05-17 14:14:20 UTC (rev 121687)
@@ -77,12 +77,16 @@
         env = self._constructWSGIEnvironment(task)
 
         def start_response(status, headers, exc_info=None):
+            if task.wroteResponseHeader() and not exc_info:
+                raise AssertionError("start_response called a second time "
+                                     "without providing exc_info.")
             if exc_info:
                 try:
                     if task.wroteResponseHeader():
                         raise exc_info[0], exc_info[1], exc_info[2]
                     else:
-                        pass
+                        # As per WSGI spec existing headers must be cleared
+                        task.accumulated_headers = None
                 finally:
                     exc_info = None
             # Prepare the headers for output
@@ -110,12 +114,16 @@
         env['wsgi.handleErrors'] = False
 
         def start_response(status, headers, exc_info=None):
+            if task.wroteResponseHeader() and not exc_info:
+                raise AssertionError("start_response called a second time "
+                                     "without providing exc_info.")
             if exc_info:
                 try:
                     if task.wroteResponseHeader():
                         raise exc_info[0], exc_info[1], exc_info[2]
                     else:
-                        pass
+                        # As per WSGI spec existing headers must be cleared
+                        task.accumulated_headers = None
                 finally:
                     exc_info = None
             # Prepare the headers for output



More information about the checkins mailing list