Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
a8f0c9c
bugfix(150107): adding isinstance check on offset to include if avail…
grantlouisherman May 20, 2026
7e7cba2
Merge branch 'main' into bugfix-150107-asyncio-ignore-0-offset
grantlouisherman May 20, 2026
4a05d1a
Merge branch 'main' into bugfix-150107-asyncio-ignore-0-offset
grantlouisherman May 20, 2026
6b5e93c
Merge branch 'main' into bugfix-150107-asyncio-ignore-0-offset
grantlouisherman May 21, 2026
d2a9ce0
📜🤖 Added by blurb_it.
blurb-it[bot] May 21, 2026
a11d3b3
Merge branch 'main' into bugfix-150107-asyncio-ignore-0-offset
grantlouisherman May 21, 2026
4587db4
Merge branch 'main' into bugfix-150107-asyncio-ignore-0-offset
grantlouisherman May 21, 2026
b525cb2
addressing PR comments
grantlouisherman May 21, 2026
f247be0
addressing PR comments
grantlouisherman May 21, 2026
84cdc6c
fixing lints
grantlouisherman May 21, 2026
25ab08e
Merge branch 'main' into bugfix-150107-asyncio-ignore-0-offset
grantlouisherman May 21, 2026
801932f
adding unit test
grantlouisherman May 21, 2026
0679bcb
Merge branch 'main' into bugfix-150107-asyncio-ignore-0-offset
grantlouisherman May 21, 2026
800a2d5
fixing test failures and lint errors
grantlouisherman May 21, 2026
2af3015
fixing windows tests
grantlouisherman May 21, 2026
027dec5
Merge branch 'main' into bugfix-150107-asyncio-ignore-0-offset
grantlouisherman May 21, 2026
79857ff
Merge branch 'main' into bugfix-150107-asyncio-ignore-0-offset
grantlouisherman May 21, 2026
ded4a36
Merge branch 'main' into bugfix-150107-asyncio-ignore-0-offset
grantlouisherman May 22, 2026
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)
Comment thread
grantlouisherman marked this conversation as resolved.
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)
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vstinner this was an AI debugged and verified by me after the windows unit tests were crashing. Apparently the issue is that this function was essentially ignoring the offset being passed because we were not passing in OVERLAPPED.Offset. So test_sock_sendfile_offset was crashing because essentially we write 6 bytes and point to EOF. Then pass in the offset of 0 the rewind however because TransmitFile was ignoring the overlap the tests failed with an EOF error. There was a similar error reported but never got merged #112337

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):
Comment thread
grantlouisherman marked this conversation as resolved.
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)
Comment thread
grantlouisherman marked this conversation as resolved.

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