Commit 68527217 authored by Vincent Pelletier's avatar Vincent Pelletier

ERP5Type/patches/WSGIPublisher: Emulate HTTPResponse.write better.

Once a response has been written to, the status and headers are supposed
to have been sent over the network. So any future change to them is moot.
Likewise, setBody does nothing: only write can continue appending to the
existing body.
As in the case of WSGI the response does not actually get sent just yet:
- lock the body
- store finalize() result
Also, make the order in which body and stdout are returned consistent with
HTTPResponse: body is returned first (as part of HTTPResponse.write's call
to self.outputBody, which calls self.__str__, which emits body), and then
stdout content.
Also, add support for cases whre the existing body is a file or an
IUnboundStreamIterator.
parent 7a6e04c1
...@@ -19,6 +19,7 @@ from contextlib import closing ...@@ -19,6 +19,7 @@ from contextlib import closing
from contextlib import contextmanager from contextlib import contextmanager
from io import BytesIO from io import BytesIO
from io import IOBase from io import IOBase
import itertools
import logging import logging
from six import binary_type from six import binary_type
...@@ -97,10 +98,24 @@ if 1: # upstream moved WSGIResponse to HTTPResponse.py ...@@ -97,10 +98,24 @@ if 1: # upstream moved WSGIResponse to HTTPResponse.py
WSGIResponse.setBody = setBody WSGIResponse.setBody = setBody
def write(self, data):
if not self._streaming:
notify(pubevents.PubBeforeStreaming(self))
self._streaming = 1
self._locked_body = 1
self.finalize()
self.stdout.flush()
self.stdout.write(data)
WSGIResponse.write = write
# According to PEP 333, WSGI applications and middleware are forbidden from # According to PEP 333, WSGI applications and middleware are forbidden from
# using HTTP/1.1 "hop-by-hop" features or headers. This patch prevents Zope # using HTTP/1.1 "hop-by-hop" features or headers. This patch prevents Zope
# from sending 'Connection' and 'Transfer-Encoding' headers. # from sending 'Connection' and 'Transfer-Encoding' headers.
def finalize(self): def _finalize(self):
headers = self.headers headers = self.headers
body = self.body body = self.body
...@@ -137,6 +152,13 @@ if 1: # upstream moved WSGIResponse to HTTPResponse.py ...@@ -137,6 +152,13 @@ if 1: # upstream moved WSGIResponse to HTTPResponse.py
return '%s %s' % (self.status, self.errmsg), self.listHeaders() return '%s %s' % (self.status, self.errmsg), self.listHeaders()
WSGIResponse._finalized = None
def finalize(self):
if not self._finalized:
self._finalized = _finalize(self)
return self._finalized
WSGIResponse.finalize = finalize WSGIResponse.finalize = finalize
...@@ -456,13 +478,16 @@ def publish_module(environ, start_response, ...@@ -456,13 +478,16 @@ def publish_module(environ, start_response,
status, headers = response.finalize() status, headers = response.finalize()
start_response(status, headers) start_response(status, headers)
if isinstance(response.body, _FILE_TYPES) or \
IUnboundStreamIterator.providedBy(response.body):
result = response.body result = response.body
if isinstance(result, _FILE_TYPES):
if response.stdout.getvalue():
raise ValueError(
'Cannot both return a file type and write to response.',
)
elif IUnboundStreamIterator.providedBy(result):
result = itertools.chain(result, (response.stdout.getvalue(), ))
else: else:
# If somebody used response.write, that data will be in the result = (result, response.stdout.getvalue())
# response.stdout BytesIO, so we put that before the body.
result = (response.stdout.getvalue(), response.body)
for func in response.after_list: for func in response.after_list:
func() func()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment