Range requests get wrong data when using file_stream()
Describe the bug when stream_large_files=True, app.static() responses with more data than expected when doing some range-requests that the range size is not aligned to the chunk size. It's due to file_steam() and a fix is shown as below.
Code snippet with
from sanic import Sanic
app = Sanic("try")
app.static("/view", "srv", use_content_range=True, stream_large_files=True)
app.run(host="0.0.0.0", port=8000)curl -r 0-5000 localhost:8000/view/big.file | wc -cshows 8192 as the final count.
Expected behavior A count of 5001 is expected instead.
Reasoning and fix It's due to the _streaming_fn() in file_stream() in response.py.
As the following diff shows, the buggy code is reading min((_range.size, chunk_size)) bytes, which is fixed, in the streaming loop. For a full read, it's okey to get an empty string at the end; while in range-requests, it may read and return more across the end boundary.
By changing _range.size to to_send the bug is fixed.
--- response.a.py 2022-07-28 19:03:48.575385670 +0800
+++ response.b.py 2022-07-28 19:05:24.756010839 +0800
@@ -488,7 +488,7 @@
await f.seek(_range.start)
to_send = _range.size
while to_send > 0:
- content = await f.read(min((_range.size, chunk_size)))
+ content = await f.read(min((to_send, chunk_size)))
if len(content) < 1:
break
to_send -= len(content)Environment (please complete the following information):
- OS: Linux
- Version: 22.3.2
Source: sanic-org/sanic