[Checkins] SVN: zope.server/branches/achapman-exc-info/src/zope/server/http/ Changed implementation to close the gap with the WSGI PEP.
Satchidanand Haridas
satchit at zope.com
Fri May 13 11:22:15 EDT 2011
Log message for revision 121663:
Changed implementation to close the gap with the WSGI PEP.
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-13 00:52:51 UTC (rev 121662)
+++ zope.server/branches/achapman-exc-info/src/zope/server/http/tests/test_wsgiserver.py 2011-05-13 15:22:14 UTC (rev 121663)
@@ -12,6 +12,7 @@
"""Test Puvlisher-based HTTP Server
"""
import StringIO
+import sys
import unittest
from asyncore import socket_map, poll
from threading import Thread
@@ -45,7 +46,14 @@
Pseudo ZODB conflict error.
"""
+ERROR_RESPONSE = "error occurred"
+RESPONSE = "normal response"
+class DummyException(Exception):
+ value = "Dummy Exception to test start_response"
+ def __str__(self):
+ return repr(self.value)
+
class PublicationWithConflict(DefaultPublication):
def handleException(self, object, request, exc_info, retry_allowed=1):
@@ -320,41 +328,57 @@
self.server.application = orig_app
- def test_exception_handling(self):
- # some applications/middleware (like repoze.retry) might pass the
- # exc_info to start_response.
+ def _getFakeAppAndTask(self):
- orig_app = self.server.application
-
- class DummyException(Exception):
- value = "Dummy Exception to test start_response"
- def __str__(self):
- return repr(self.value)
-
def app(environ, start_response):
try:
- start_response(
- "500 Error",
- [],
- (DummyException, DummyException.value, None))
+ raise DummyException()
except DummyException as e:
- return e.value.split()
+ start_response('500 Internal Error', [], sys.exc_info())
+ return ERROR_RESPONSE.split()
+ return RESPONSE.split()
class FakeTask:
+ wrote_header = 0
+ status = None
+ reason = None
response = []
getCGIEnvironment = lambda _: {}
class request_data:
getBodyStream = lambda _: StringIO.StringIO()
request_data = request_data()
- setResponseStatus = appendResponseHeaders = lambda *_: None
+ appendResponseHeaders = lambda *_: None
+ def setResponseStatus(self, status, reason):
+ self.status = status
+ self.reason = reason
+ def wroteResponseHeader(self):
+ return self.wrote_header
def write(self, v):
self.response.append(v)
- self.server.application = app
- task = FakeTask()
+ return app, FakeTask()
+
+
+ def test_start_response_with_no_headers_sent(self):
+ # start_response exc_info if no headers have been sent
+ orig_app = self.server.application
+ self.server.application, task = self._getFakeAppAndTask()
+
self.server.executeRequest(task)
- self.assertEqual(task.response, DummyException.value.split())
+ self.assertEqual(task.status, "500")
+ self.assertEqual(task.response, ERROR_RESPONSE.split())
+
+
+ def test_start_response_with_headers_sent(self):
+ # If headers have been sent it raises the exception
+ orig_app = self.server.application
+ self.server.application, task = self._getFakeAppAndTask()
+
+ # If headers have already been written an exception is raised
+ task.wrote_header = 1
+ self.assertRaises(DummyException, self.server.executeRequest, task)
+
self.server.application = orig_app
class PMDBTests(Tests):
@@ -375,7 +399,29 @@
'wsgi.multiprocess', 'wsgi.handleErrors',
'wsgi.run_once']))
+ 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.
+ orig_app = self.server.application
+ self.server.application, 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(DummyException, self.server.executeRequest, task)
+ self.assertTrue("raise DummyException" in pm_traceback[-1])
+ self.server.application = orig_app
+ pdb.post_mortem = orig_post_mortem
+
+
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(Tests),
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-13 00:52:51 UTC (rev 121662)
+++ zope.server/branches/achapman-exc-info/src/zope/server/http/wsgihttpserver.py 2011-05-13 15:22:14 UTC (rev 121663)
@@ -79,7 +79,10 @@
def start_response(status, headers, exc_info=None):
if exc_info:
try:
- raise exc_info[0], exc_info[1], exc_info[2]
+ if task.wroteResponseHeader():
+ raise exc_info[0], exc_info[1], exc_info[2]
+ else:
+ pass
finally:
exc_info = None
# Prepare the headers for output
@@ -109,7 +112,10 @@
def start_response(status, headers, exc_info=None):
if exc_info:
try:
- raise exc_info[0], exc_info[1], exc_info[2]
+ if task.wroteResponseHeader():
+ raise exc_info[0], exc_info[1], exc_info[2]
+ else:
+ pass
finally:
exc_info = None
# Prepare the headers for output
More information about the checkins
mailing list