Merge pull request #22924 from jmchilton/jbrowse_bug

[26.1] Fix HTTP Range requests on dataset files (non-nginx deployments)
This commit is contained in:
Marius van den Beek
2026-06-16 09:28:27 +02:00
committed by GitHub
2 changed files with 36 additions and 4 deletions
+2 -2
View File
@@ -569,8 +569,8 @@ def send_file(start_response, trans, body):
body = b""
if trans.request.range:
start = int(trans.request.range.start)
file_size = int(trans.response.headers["content-length"])
end = int(file_size if end is None else trans.request.range.end)
file_size = os.path.getsize(body.name)
end = file_size if trans.request.range.end is None else min(int(trans.request.range.end), file_size)
trans.response.headers["content-length"] = str(end - start)
trans.response.headers["content-range"] = f"bytes {start}-{end - 1}/{file_size}"
trans.response.status = 206
+34 -2
View File
@@ -15,7 +15,7 @@ from galaxy.web.framework.base import (
CONTENT = "content"
def setup_fastAPI(fh, nginx_x_accel_redirect_base=None, apache_xsendfile=None):
def setup_fastAPI(fh, nginx_x_accel_redirect_base=None, apache_xsendfile=None, set_content_length=True):
def wsgi_application(env, start_response):
trans = Bunch(
response=Response(),
@@ -24,7 +24,8 @@ def setup_fastAPI(fh, nginx_x_accel_redirect_base=None, apache_xsendfile=None):
config=Bunch(nginx_x_accel_redirect_base=nginx_x_accel_redirect_base, apache_xsendfile=apache_xsendfile)
),
)
trans.response.headers["content-length"] = len(CONTENT)
if set_content_length:
trans.response.headers["content-length"] = len(CONTENT)
trans.response.set_content_type("application/octet-stream")
return send_file(start_response, trans, fh)
@@ -72,3 +73,34 @@ def test_sendfile_in_process(test_file_handle):
assert "x-accel-redirect" not in response.headers
assert response.headers["content-length"] == str(len(CONTENT))
assert response.content.decode() == "content"
def test_sendfile_range(test_file_handle):
app = setup_fastAPI(test_file_handle)
client = TestClient(app)
response = client.get("/test/send_file", headers={"Range": "bytes=0-3"})
assert response.status_code == 206
assert response.headers["content-range"] == f"bytes 0-3/{len(CONTENT)}"
assert response.headers["content-length"] == "4"
assert response.content.decode() == "cont"
def test_sendfile_range_open_ended(test_file_handle):
app = setup_fastAPI(test_file_handle)
client = TestClient(app)
response = client.get("/test/send_file", headers={"Range": "bytes=2-"})
assert response.status_code == 206
assert response.headers["content-range"] == f"bytes 2-{len(CONTENT) - 1}/{len(CONTENT)}"
assert response.headers["content-length"] == str(len(CONTENT) - 2)
assert response.content.decode() == "ntent"
def test_sendfile_range_without_content_length(test_file_handle):
# Files served out of a dataset's extra_files_path (e.g. JBrowse track data) don't set
# a content-length header; a Range request on a non-nginx deployment must still succeed.
app = setup_fastAPI(test_file_handle, set_content_length=False)
client = TestClient(app)
response = client.get("/test/send_file", headers={"Range": "bytes=0-3"})
assert response.status_code == 206
assert response.headers["content-range"] == f"bytes 0-3/{len(CONTENT)}"
assert response.content.decode() == "cont"