diff --git a/src/zope/server/http/tests/test_wsgiserver.py b/src/zope/server/http/tests/test_wsgiserver.py index 2ac60ec..ec60e52 100644 --- a/src/zope/server/http/tests/test_wsgiserver.py +++ b/src/zope/server/http/tests/test_wsgiserver.py @@ -348,7 +348,10 @@ class FakeTask: status = None reason = None response = [] - accumulated_headers = [] + accumulated_headers = None + def __init__(self): + self.accumulated_headers = [] + self.response_headers = {} getCGIEnvironment = lambda _: {} class request_data: getBodyStream = lambda _: StringIO.StringIO() @@ -374,6 +377,7 @@ def test_start_response_with_no_headers_sent(self): orig_app = self.server.application self.server.application, task = self._getFakeAppAndTask() task.accumulated_headers = ['header1', 'header2'] + task.accumulated_headers = {'key1': 'value1', 'key2': 'value2'} self.server.executeRequest(task) @@ -382,6 +386,9 @@ def test_start_response_with_no_headers_sent(self): # any headers written before are cleared and # only the most recent one is added. self.assertEqual(task.accumulated_headers, ['Content-type: text/plain']) + # response headers are cleared. They'll be rebuilt from + # accumulated_headers in the prepareResponseHeaders method + self.assertEqual(task.response_headers, {}) self.server.application = orig_app diff --git a/src/zope/server/http/wsgihttpserver.py b/src/zope/server/http/wsgihttpserver.py index 76e0ec2..bad67bf 100644 --- a/src/zope/server/http/wsgihttpserver.py +++ b/src/zope/server/http/wsgihttpserver.py @@ -26,6 +26,31 @@ def fakeWrite(body): "Zope 3's HTTP Server does not support the WSGI write() function.") +def curriedStartResponse(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: + # As per WSGI spec existing headers must be cleared + task.accumulated_headers = None + task.response_headers = {} + finally: + exc_info = None + # Prepare the headers for output + status, reason = re.match('([0-9]*) (.*)', status).groups() + task.setResponseStatus(status, reason) + task.appendResponseHeaders(['%s: %s' % i for i in headers]) + + # Return the write method used to write the response data. + return fakeWrite + return start_response + + class WSGIHTTPServer(HTTPServer): """Zope Publisher-specific WSGI-compliant HTTP Server""" @@ -76,33 +101,8 @@ def executeRequest(self, task): """Overrides HTTPServer.executeRequest().""" 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(): - # higher levels will catch and handle raised exception: - # 1. "service" method in httptask.py - # 2. "service" method in severchannelbase.py - # 3. "handlerThread" method in taskthreads.py - raise exc_info[0], exc_info[1], exc_info[2] - else: - # As per WSGI spec existing headers must be cleared - task.accumulated_headers = None - finally: - exc_info = None - # Prepare the headers for output - status, reason = re.match('([0-9]*) (.*)', status).groups() - task.setResponseStatus(status, reason) - task.appendResponseHeaders(['%s: %s' % i for i in headers]) - - # Return the write method used to write the response data. - return fakeWrite - # Call the application to handle the request and write a response - result = self.application(env, start_response) + result = self.application(env, curriedStartResponse(task)) # By iterating manually at this point, we execute task.write() # multiple times, allowing partial data to be sent. @@ -118,30 +118,9 @@ def executeRequest(self, task): env = self._constructWSGIEnvironment(task) 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: - # As per WSGI spec existing headers must be cleared - task.accumulated_headers = None - finally: - exc_info = None - # Prepare the headers for output - status, reason = re.match('([0-9]*) (.*)', status).groups() - task.setResponseStatus(status, reason) - task.appendResponseHeaders(['%s: %s' % i for i in headers]) - - # Return the write method used to write the response data. - return fakeWrite - # Call the application to handle the request and write a response try: - result = self.application(env, start_response) + result = self.application(env, curriedStartResponse(task)) # By iterating manually at this point, we execute task.write() # multiple times, allowing partial data to be sent. for value in result: