Skip to content
Open
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
5 changes: 2 additions & 3 deletions Lib/asyncio/base_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -969,7 +969,7 @@ async def _sock_sendfile_native(self, sock, file, offset, count):
f"and file {file!r} combination")

async def _sock_sendfile_fallback(self, sock, file, offset, count):
if offset:
if hasattr(file, 'seek'):
file.seek(offset)
blocksize = (
min(count, constants.SENDFILE_FALLBACK_READBUFFER_SIZE)
Expand Down Expand Up @@ -1286,7 +1286,6 @@ async def sendfile(self, transport, file, offset=0, count=None,
raise RuntimeError(
f"fallback is disabled and native sendfile is not "
f"supported for transport {transport!r}")

return await self._sendfile_fallback(transport, file,
offset, count)

Expand All @@ -1295,7 +1294,7 @@ async def _sendfile_native(self, transp, file, offset, count):
"sendfile syscall is not supported")

async def _sendfile_fallback(self, transp, file, offset, count):
if offset:
if hasattr(file, 'seek'):
file.seek(offset)
blocksize = min(count, 16384) if count else 16384
buf = bytearray(blocksize)
Expand Down
3 changes: 3 additions & 0 deletions Lib/asyncio/windows_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,9 @@ def sendfile(self, sock, file, offset, count):
ov = _overlapped.Overlapped(NULL)
offset_low = offset & 0xffff_ffff
offset_high = (offset >> 32) & 0xffff_ffff
# TransmitFile ignores OVERLAPPED.Offset for handles not opened with
# FILE_FLAG_OVERLAPPED, so seek the CRT file pointer to match.
file.seek(offset)
ov.TransmitFile(sock.fileno(),
msvcrt.get_osfhandle(file.fileno()),
offset_low, offset_high,
Expand Down
26 changes: 26 additions & 0 deletions Lib/test/test_asyncio/test_sendfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,32 @@ def test_sock_sendfile_zero_size(self):
self.assertEqual(ret, 0)
self.assertEqual(self.file.tell(), 0)

def check_sock_sendfile_offset(self, data, offset, force_fallback=False):
sock, proto = self.prepare_socksendfile()
with tempfile.TemporaryFile() as f:
f.write(data)
f.flush()
self.assertEqual(f.tell(), len(data))

if force_fallback:
async def _sock_sendfile_fail(sock, file, offset, count):
raise asyncio.exceptions.SendfileNotAvailableError()
with support.swap_attr(self.loop, '_sock_sendfile_native', _sock_sendfile_fail):
ret = self.run_loop(self.loop.sock_sendfile(sock, f, offset, None))
else:
ret = self.run_loop(self.loop.sock_sendfile(sock, f, offset, None))
self.assertEqual(f.tell(), len(data))
sock.close()
self.run_loop(proto.wait_closed())
self.assertEqual(ret, len(data) - offset)

def test_sock_sendfile_offset(self):
data = b'abcdef'
for offset in (0, len(data) // 2, len(data)):
for force_fallback in (False, True):
with self.subTest(offset=offset, force_fallback=force_fallback):
self.check_sock_sendfile_offset(data, offset, force_fallback)

def test_sock_sendfile_mix_with_regular_send(self):
buf = b"mix_regular_send" * (4 * 1024) # 64 KiB
sock, proto = self.prepare_socksendfile()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:mod:`asyncio`: ``sendfile()`` and ``sock_sendfile()`` event loop methods
now call ``file.seek(offset)`` if *file* has a ``seek()`` method,
even if *offset* is ``0`` (default value).
Loading