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
from contextlib import contextmanager
from io import BytesIO
from io import IOBase
import itertools
import logging
from six import binary_type
......@@ -97,10 +98,24 @@ if 1: # upstream moved WSGIResponse to HTTPResponse.py
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
# using HTTP/1.1 "hop-by-hop" features or headers. This patch prevents Zope
# from sending 'Connection' and 'Transfer-Encoding' headers.
def finalize(self):
def _finalize(self):
headers = self.headers
body = self.body
......@@ -137,6 +152,13 @@ if 1: # upstream moved WSGIResponse to HTTPResponse.py
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
......@@ -456,13 +478,16 @@ def publish_module(environ, start_response,
status, headers = response.finalize()
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:
# If somebody used response.write, that data will be in the
# response.stdout BytesIO, so we put that before the body.
result = (response.stdout.getvalue(), response.body)
result = (result, response.stdout.getvalue())
for func in response.after_list:
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