Skip to content

Commit

Permalink
1. Reset "response_headers" in addition to "accumulated_headers".
Browse files Browse the repository at this point in the history
2. Make code comply with DRY.
  • Loading branch information
satchit committed May 17, 2011
1 parent 33ed2f3 commit b231541
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 49 deletions.
9 changes: 8 additions & 1 deletion src/zope/server/http/tests/test_wsgiserver.py
Expand Up @@ -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()
Expand All @@ -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)

Expand All @@ -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

Expand Down
75 changes: 27 additions & 48 deletions src/zope/server/http/wsgihttpserver.py
Expand Up @@ -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"""

Expand Down Expand Up @@ -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.
Expand All @@ -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:
Expand Down

0 comments on commit b231541

Please sign in to comment.