Skip to content

FileResponse failed to prepare proper headers for Range requests #2844

Closed
@spcharc

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,

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions