-
-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FileResponse failed to prepare proper headers for Range requests #2844
Comments
Thank you for report. |
What is a pull request? I've seen it a couple of times on github though. |
Pull Request is a way to making a patch for merging. |
Thank you for your explanation. I'm trying to figure out how to use git command now. |
If-Unmodified-Since should be processed together with If-Modified-Since, It is not required to be used together with range requests. If-Range could be processed together too, if not matched, remove the range header. I don't have time for this now. If no one is working on it, I can do It later. |
If ETag is generated, client will use If-Match instead. There is an implementation I created years ago: https://github.com/hubo1016/vlcp/blob/master/vlcp/service/web/static.py#L65 It did not process If-Match header, But works for normal range requests. Only ETag is supported, Last-Modified is not returned. |
Thanks for reply. aiohttp does provide Last-Modified header and it doesn't have Etag support yet. So If-Match and If-None-Match handler isn't necessary as clients won't make requests with them. (They won't get any ETag beforehand)
Usually we don't change static resources a lot. And generating strong ETags requires some caching and hashing work. It's not cheap. Especially when dealing with large files. |
@spcharc It is not that different. In fact, usually we generate a ETag based on: modification time, inode, file size. They all come from fstat(). HMAC (sha256, md5) are NOT used. At least Apache and nginx uses this kind of ETag. |
I see. Thank you! |
Fixed by #2847 |
Today I thought about why ETag is better than date check again. |
@spcharc Currently I don't have enough time, but you can look at an implementation I wrote and tested before: I've also modified it to a suitable version (removing Python 2.x compatibility) def safehex(v):
h = hex(v)[2:]
return h
def _createetag(stat_info):
etag = 'aiohttp-' + safehex(stat_info.st_ino) + '-' + safehex(int(stat_info.st_mtime)) + '-' + safehex(int(stat_info.st_size))
# return etag.encode('ascii') # if bytes are wanted
return etag Call Whether to support ETag or not, and how to implement it is a decision of design. It should be discussed in a separated issue. And adding ETag should be a feature request rather than a bug fix which is not very urgent. |
@hubo1016 Thank you for your detailed explanation and suggestion. I will open another issue to discuss it. |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a [new issue] for related bugs. |
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
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.
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:
And some use this (including Chrome browser):
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:
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:
The text was updated successfully, but these errors were encountered: