Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ Python Version Support
Bugfix
~~~~~~

- ``wsgi.file_wrapper`` now sets the ``seekable``, ``seek``, and ``tell`` attributes from
the underlying file if the underlying file is seekable. This allows WSGI
middleware to implement things like range requests for example

See https://github.com/Pylons/waitress/issues/359 and
https://github.com/Pylons/waitress/pull/363

- In Python 3 ``OSError`` is no longer subscriptable, this caused failures on
Windows attempting to loop to find an socket that would work for use in the
trigger.
Expand Down
10 changes: 10 additions & 0 deletions src/waitress/buffers.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,16 @@ def __init__(self, file, block_size=32768):
self.file = file
self.block_size = block_size # for __iter__

# This is for the benefit of anyone that is attempting to wrap this
# wsgi.file_wrapper in a WSGI middleware and wants to seek, this is
# useful for instance for support Range requests
if _is_seekable(self.file):
if hasattr(self.file, "seekable"):
self.seekable = self.file.seekable

self.seek = self.file.seek
self.tell = self.file.tell

def prepare(self, size=None):
if _is_seekable(self.file):
start_pos = self.file.tell()
Expand Down
4 changes: 4 additions & 0 deletions tests/test_buffers.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ def tearDown(self):
def test_prepare_not_seekable(self):
f = KindaFilelike(b"abc")
inst = self._makeOne(f)
self.assertFalse(hasattr(inst, "seek"))
self.assertFalse(hasattr(inst, "tell"))
result = inst.prepare()
self.assertEqual(result, False)
self.assertEqual(inst.remain, 0)
Expand All @@ -200,6 +202,8 @@ def test_prepare_not_seekable_closeable(self):
def test_prepare_seekable_closeable(self):
f = Filelike(b"abc", close=1, tellresults=[0, 10])
inst = self._makeOne(f)
self.assertEqual(inst.seek, f.seek)
self.assertEqual(inst.tell, f.tell)
result = inst.prepare()
self.assertEqual(result, 10)
self.assertEqual(inst.remain, 10)
Expand Down