upload: Preserve content-type from upload for local-file storage.

Now that we store the content-type in the database, use that value
(if we have it, since we did not backfill) when serving content back
to the client.  This means the file backend has parity with the S3
backend.
This commit is contained in:
Alex Vandiver 2024-09-04 18:19:25 +00:00 committed by Tim Abbott
parent d7ebe7296d
commit 56ca594abf
2 changed files with 30 additions and 3 deletions

View File

@ -174,6 +174,19 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
self.assertEqual(result.status_code, 200)
self.assertEqual(result["Content-Type"], "text/plain")
def test_preserve_provided_content_type(self) -> None:
uploaded_file = SimpleUploadedFile("somefile.txt", b"zulip!", content_type="image/png")
result = self.api_post(
self.example_user("hamlet"), "/api/v1/user_uploads", {"file": uploaded_file}
)
self.login("hamlet")
response_dict = self.assert_json_success(result)
url = response_dict["url"]
result = self.client_get(url)
self.assertEqual(result.status_code, 200)
self.assertEqual(result["Content-Type"], "image/png")
# This test will go through the code path for uploading files onto LOCAL storage
# when Zulip is in DEVELOPMENT mode.
def test_file_upload_authed(self) -> None:

View File

@ -115,6 +115,7 @@ def serve_local(
path_id: str,
filename: str,
force_download: bool = False,
mimetype: str | None = None,
) -> HttpResponseBase:
assert settings.LOCAL_FILES_DIR is not None
local_path = os.path.join(settings.LOCAL_FILES_DIR, path_id)
@ -122,7 +123,8 @@ def serve_local(
if not os.path.isfile(local_path):
return HttpResponseNotFound("<p>File not found</p>")
mimetype, encoding = guess_type(filename)
if mimetype is None:
mimetype = guess_type(filename)[0]
download = force_download or mimetype not in INLINE_MIME_TYPES
if settings.DEVELOPMENT:
@ -133,6 +135,7 @@ def serve_local(
open(local_path, "rb"), # noqa: SIM115
as_attachment=download,
filename=filename,
content_type=mimetype,
)
patch_cache_control(response, private=True, immutable=True)
return response
@ -339,12 +342,18 @@ def serve_file(
# Update the path that we are fetching to be the thumbnail
path_id = get_image_thumbnail_path(image_attachment, requested_format)
served_filename = str(requested_format)
mimetype: str | None = None # Guess from filename
else:
served_filename = attachment.file_name
mimetype = attachment.content_type
if settings.LOCAL_UPLOADS_DIR is not None:
return serve_local(
request, path_id, filename=served_filename, force_download=force_download
request,
path_id,
filename=served_filename,
force_download=force_download,
mimetype=mimetype,
)
else:
return serve_s3(request, path_id, force_download=force_download)
@ -388,7 +397,12 @@ def serve_file_unauthed_from_token(
raise JsonableError(_("Invalid token"))
if settings.LOCAL_UPLOADS_DIR is not None:
return serve_local(request, path_id, filename=attachment.file_name)
return serve_local(
request,
path_id,
filename=attachment.file_name,
mimetype=attachment.content_type,
)
else:
return serve_s3(request, path_id)