Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Handle content types with parameters. #16440

Merged
merged 4 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/16440.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Properly return inline media when content types have parameters.
4 changes: 3 additions & 1 deletion synapse/media/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,9 @@ def _quote(x: str) -> str:

# A strict subset of content types is allowed to be inlined so that they may
# be viewed directly in a browser. Other file types are forced to be downloads.
if media_type.lower() in INLINE_CONTENT_TYPES:
#
# Only the type & subtype are important, parameters can be ignored.
if media_type.lower().split(";", 1)[0] in INLINE_CONTENT_TYPES:
disposition = "inline"
else:
disposition = "attachment"
Expand Down
19 changes: 18 additions & 1 deletion tests/media/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,35 @@ def tests(self) -> None:

class AddFileHeadersTests(unittest.TestCase):
TEST_CASES = {
# Safe values use inline.
"text/plain": b"inline; filename=file.name",
"text/csv": b"inline; filename=file.name",
"image/png": b"inline; filename=file.name",
# Unlisted values are set to attachment.
"text/html": b"attachment; filename=file.name",
"any/thing": b"attachment; filename=file.name",
# Parameters get ignored.
"text/plain; charset=utf-8": b"inline; filename=file.name",
"text/markdown; charset=utf-8; variant=CommonMark": b"attachment; filename=file.name",
# Parsed as lowercase.
"Text/Plain": b"inline; filename=file.name",
# Bad values don't choke.
"": b"attachment; filename=file.name",
";": b"attachment; filename=file.name",
}

def test_content_disposition(self) -> None:
for media_type, expected in self.TEST_CASES.items():
request = Mock()
add_file_headers(request, media_type, 0, "file.name")
request.setHeader.assert_any_call(b"Content-Disposition", expected)
# There should be a single call to set Content-Disposition.
for call in request.setHeader.call_args_list:
args, _ = call
if args[0] == b"Content-Disposition":
break
else:
self.fail(f"No Content-Disposition header found for {media_type}")
self.assertEqual(args[1], expected, media_type)

def test_no_filename(self) -> None:
request = Mock()
Expand Down
Loading