quart icon indicating copy to clipboard operation
quart copied to clipboard

Support Accept-Range header in send_file?

Open EternityForest opened this issue 1 year ago • 1 comments

It would be nice to have an accept_range flag on the semd_file, that would set the accept header, and check for range requests in the context.

It seems easy enough to implement so I can write the feature and do a PR if this is in-scope for the project.

In very simple one off apps, it would be nice to be able to serve seekable media without needing to add an extra ASGi server to handle the static file serving.

Right now this doesn't seem to work in browsers without range requests enabled.

Also, non-resumable downloads are generally annoying.

EternityForest avatar Jun 18 '24 19:06 EternityForest

My workaround at the moment is just to define my own function, this code seems to be working

async def send_file_range(file_path: str):
    try:

        @quart.ctx.copy_current_request_context
        def f():
            range_header = quart.request.headers.get("Range", "").replace(
                "bytes=", ""
            )
            if "-" in range_header:
                r = range_header.split("-")
                start = int(r[0])
                fs = os.path.getsize(file_path)
                if len(r) > 1 and r[1]:
                    end = int(r[1])
                else:
                    end = fs - 1

                end = min(end, fs - 1)
            else:
                start = 0
                end = os.path.getsize(file_path) - 1

            with open(file_path, "rb") as file:
                file.seek(start)
                data = file.read(end - start + 1)

            response = quart.Response(
                data, mimetype=mimetypes.guess_type(file_path)[0]
            )
            response.headers["Content-Range"] = (
                f"bytes {start}-{end}/{os.path.getsize(file_path)}"
            )
            response.headers["Content-Length"] = str(end - start + 1)
            response.status_code = 206
            return response

        return await f()

    except FileNotFoundError:
        return "File not found", 404

EternityForest avatar Jan 10 '25 00:01 EternityForest