Skip to content

Commit

Permalink
Merge pull request #363 from Pylons/bugfix/wsgi-file-wrapper
Browse files Browse the repository at this point in the history
Bugfix: wsgi.file_wrapper should pass-through seek/tell attrs
  • Loading branch information
mmerickel authored Jan 17, 2022
2 parents 88d5e7b + 5627a4c commit e828cd5
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 0 deletions.
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

0 comments on commit e828cd5

Please sign in to comment.