FileResponse failed to prepare proper headers for Range requests #2844
Description
Long story short
Please describe your problem and why the fix is important.
Users may pause their downloads of large static resources.
Many download managers including those browser-builtin ones check for Content-Range headers. Missing this header would cause downloads to fail.
I checked the source code and found out static resources are handled by FileResponse in web_fileresponse.py. But {0}.format(title)
Expected behaviour
What is the behaviour you expect?
Assume you have a BIG file big_file
big_file.size() == 10000 (9.77kb)
A user downloaded 500 bytes (0-499) and connection lost.
And then the user resumes download with request: "Range:bytes=500-"
Expected header: "Content-Range:bytes 500-9999/10000" <- this one is missing
Actual behaviour
What's actually happening?
The downloads just failed immediately after clicking resume button.
Actually aiohttp handles Range requests very well. HTTP 206 and Content-Length are both correctly returned to users.
Steps to reproduce
Please describe steps to reproduce the issue.
If you have a script that does that please include it here within
markdown code markup
Check the web_fileresponse.py source code, or try a download like this
from aiohttp import web
import asyncio
loop = asyncio.get_event_loop()
app = web.Application(loop = loop)
app.add_static('/', folder_containing_large_file, show_index = True)
web.run_app(app, host = '0.0.0.0', port = 4321)
goto http://your_addr:4321/
click the big_file
Your environment
Describe the environment you have that lead to your issue.
This includes aiohttp version, OS, proxy server and other bits that
are related to your case.
IMPORTANT: aiohttp is both server framework and client library.
For getting rid of confusing please put 'server', 'client' or 'both'
word here.
Server
Python/3.6.4
aiohttp/3.0.9
Temporary workaround
in file web_fileresponse.py:
line 228 == "if count:"
in line 227 I added:
self.headers[hdrs.ACCEPT_RANGES] = 'bytes'
(Accept-Ranges header, which is to indicate that the server supports Range requests, is also missing. But I found out that usually web clients just ignore it. They still send Range requests even though this is missing. Maybe an Accept-Ranges:none header is needed to prevent Range requests?)
in line 229 I added:
if start is not None: self.headers[hdrs.CONTENT_RANGE] = f'bytes {start}-{start+count-1}/{file_size}'
(After this line is added, download managers work like a charm)
These two lines could be a temporary workaround. It has problems left listed as below
Other things to check
Some download managers use this header:
If-Range:xxxxxx
Range:bytes=yyyy-zzzz
And some use this (including Chrome browser):
If-Unmodified-Since:xxxxxx
Range:bytes=yyyy-zzzz
Both are not properly handled by FileResponse. Nothing is checked and HTTP 206 is returned with requested partial content
As far as I know, what is expected:
if condition:
return HTTP 206, Content-Length=len(requested_part), Content-Range=start-end/full_len
else:
return HTTP 200, Content-Length=full_len
Besides, multipart/byterange is not supported
A request with Range:bytes=0-10,20-30 will cause HTTP 416
(EOF. It's my first time using github, please tell me if anything wrong. English is not my first language, please point out if any mistake. Sorry about that)
Edit:
Only If-Range works in that way, but If-Unmodified-Since is like this:
if condition:
return HTTP 206, Content-Length=len(requested_part), Content-Range=start-end/full_len
else:
return HTTP 412 Precondition Failed,