diff --git a/swh/web/browse/tests/views/test_content.py b/swh/web/browse/tests/views/test_content.py --- a/swh/web/browse/tests/views/test_content.py +++ b/swh/web/browse/tests/views/test_content.py @@ -261,10 +261,8 @@ content_data = archive_data.content_get_data(content_text["sha1"])["data"] assert resp["Content-Type"] == "text/plain" - assert resp["Content-disposition"] == ( - "filename=%s_%s" % ("sha1", content_text["sha1"]) - ) - assert resp.content == content_data + assert resp["Content-disposition"] == (f'filename="sha1_{content_text["sha1"]}"') + assert b"".join(resp.streaming_content) == content_data filename = content_text["path"].split("/")[-1] @@ -279,8 +277,8 @@ ) assert resp["Content-Type"] == "text/plain" - assert resp["Content-disposition"] == "filename=%s" % filename - assert resp.content == content_data + assert resp["Content-disposition"] == f'filename="{filename}"' + assert b"".join(resp.streaming_content) == content_data def test_content_raw_no_utf8_text(client, content_text_non_utf8): @@ -291,7 +289,9 @@ resp = check_http_get_response( client, url, status_code=200, content_type="text/plain" ) - _, encoding = get_mimetype_and_encoding_for_content(resp.content) + _, encoding = get_mimetype_and_encoding_for_content( + b"".join(resp.streaming_content) + ) assert encoding == content_text_non_utf8["encoding"] @@ -308,11 +308,11 @@ content_data = archive_data.content_get_data(content_image_type["sha1"])["data"] assert resp["Content-Type"] == "application/octet-stream" - assert resp["Content-disposition"] == "attachment; filename=%s_%s" % ( - "sha1", - content_image_type["sha1"], + assert ( + resp["Content-disposition"] + == f'attachment; filename="sha1_{content_image_type["sha1"]}"' ) - assert resp.content == content_data + assert b"".join(resp.streaming_content) == content_data url = reverse( "browse-content-raw", @@ -325,8 +325,8 @@ ) assert resp["Content-Type"] == "application/octet-stream" - assert resp["Content-disposition"] == "attachment; filename=%s" % filename - assert resp.content == content_data + assert resp["Content-disposition"] == f'attachment; filename="{filename}"' + assert b"".join(resp.streaming_content) == content_data @pytest.mark.django_db diff --git a/swh/web/browse/views/content.py b/swh/web/browse/views/content.py --- a/swh/web/browse/views/content.py +++ b/swh/web/browse/views/content.py @@ -5,9 +5,10 @@ import difflib from distutils.util import strtobool +import io from typing import Any, Dict, Optional -from django.http import HttpRequest, HttpResponse, JsonResponse +from django.http import FileResponse, HttpRequest, HttpResponse, JsonResponse from django.shortcuts import redirect, render from swh.model.hashutil import hash_to_hex @@ -43,7 +44,7 @@ view_name="browse-content-raw", checksum_args=["query_string"], ) -def content_raw(request: HttpRequest, query_string: str) -> HttpResponse: +def content_raw(request: HttpRequest, query_string: str) -> FileResponse: """Django view that produces a raw display of a content identified by its hash value. @@ -63,13 +64,27 @@ content_data["mimetype"].startswith("text/") or content_data["mimetype"] == "inode/x-empty" ): - response = HttpResponse(content_data["raw_data"], content_type="text/plain") - response["Content-disposition"] = "filename=%s" % filename + content_type = "text/plain" + as_attachment = False else: - response = HttpResponse( - content_data["raw_data"], content_type="application/octet-stream" + content_type = "application/octet-stream" + as_attachment = True + + response = FileResponse( + io.BytesIO(content_data["raw_data"]), # not copied, as this is never modified + filename=filename, + content_type=content_type, + as_attachment=True, + ) + + if not as_attachment: + # django 2.2.24 used in production does not set Content-Disposition header + # if as_attachment is False so we use that workaround to preserve old behavior + # TODO: remove that block once we use upstream django in production + response["Content-Disposition"] = response["Content-Disposition"].replace( + "attachment; ", "" ) - response["Content-disposition"] = "attachment; filename=%s" % filename + return response