Skip to content

Commit

Permalink
Merge e1c95a5 into 24ae27b
Browse files Browse the repository at this point in the history
  • Loading branch information
mamico committed Oct 27, 2019
2 parents 24ae27b + e1c95a5 commit 55a64bb
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 1 deletion.
5 changes: 5 additions & 0 deletions CHANGES.rst
Expand Up @@ -21,9 +21,14 @@ https://github.com/zopefoundation/Zope/blob/4.x/CHANGES.rst
- Fix ``OFS.Image.File.__str__`` for ``Pdata`` contents
(`#711 <https://github.com/zopefoundation/Zope/issues/711>`_)

- Add ``wsgi.file_wrapper`` implementation
https://www.python.org/dev/peps/pep-0333/#optional-platform-specific-file-handling
(`#719 <https://github.com/zopefoundation/Zope/pull/719>`_)

- Set ``REMOTE_USER`` in wsgi environ using Zope user authentication
(`#713 <https://github.com/zopefoundation/Zope/pull/713>`_)


- Improve documentation for Zope's error logging services.

Backwards incompatible changes
Expand Down
5 changes: 4 additions & 1 deletion src/ZPublisher/WSGIPublisher.py
Expand Up @@ -351,7 +351,10 @@ def publish_module(environ, start_response,

if isinstance(response.body, _FILE_TYPES) or \
IUnboundStreamIterator.providedBy(response.body):
result = response.body
if 'wsgi.file_wrapper' in environ:
result = environ['wsgi.file_wrapper'](response.body)
else:
result = response.body
else:
# If somebody used response.write, that data will be in the
# response.stdout BytesIO, so we put that before the body.
Expand Down
67 changes: 67 additions & 0 deletions src/ZPublisher/tests/test_WSGIPublisher.py
Expand Up @@ -445,6 +445,73 @@ def __next__(self):
app_iter = self._callFUT(environ, start_response, _publish)
self.assertTrue(app_iter is body)

def test_stream_file_wrapper(self):
from ZPublisher.Iterators import IStreamIterator
from zope.interface import implementer
from ZPublisher.HTTPResponse import WSGIResponse

@implementer(IStreamIterator)
class TestStreamIterator(object):
data = "hello" * 20

def __len__(self):
return len(self.data)

class Wrapper(object):
def __init__(self, file):
self.file = file

_response = WSGIResponse()
_response.setHeader('Content-Type', 'text/plain')
body = _response.body = TestStreamIterator()
environ = self._makeEnviron(**{'wsgi.file_wrapper': Wrapper})
start_response = DummyCallable()
_publish = DummyCallable()
_publish._result = _response
app_iter = self._callFUT(environ, start_response, _publish)
self.assertTrue(app_iter.file is body)
self.assertTrue(isinstance(app_iter, Wrapper))
self.assertEqual(
int(_response.headers['content-length']), len(body))
self.assertTrue(
_response.headers['content-type'].startswith('text/plain'))
self.assertEqual(_response.status, 200)

def test_unboundstream_file_wrapper(self):
from ZPublisher.Iterators import IUnboundStreamIterator
from zope.interface import implementer
from ZPublisher.HTTPResponse import WSGIResponse

@implementer(IUnboundStreamIterator)
class TestUnboundStreamIterator(object):
data = "hello"

def __len__(self):
return len(self.data)

class Wrapper(object):
def __init__(self, file):
self.file = file

_response = WSGIResponse()
_response.setStatus(200)
# UnboundStream needs Content-Length header
_response.setHeader('Content-Length', '5')
_response.setHeader('Content-Type', 'text/plain')
body = _response.body = TestUnboundStreamIterator()
environ = self._makeEnviron(**{'wsgi.file_wrapper': Wrapper})
start_response = DummyCallable()
_publish = DummyCallable()
_publish._result = _response
app_iter = self._callFUT(environ, start_response, _publish)
self.assertTrue(app_iter.file is body)
self.assertTrue(isinstance(app_iter, Wrapper))
self.assertEqual(
int(_response.headers['content-length']), len(body))
self.assertTrue(
_response.headers['content-type'].startswith('text/plain'))
self.assertEqual(_response.status, 200)

def test_request_closed(self):
environ = self._makeEnviron()
start_response = DummyCallable()
Expand Down

0 comments on commit 55a64bb

Please sign in to comment.