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

Handle missing Content-Type header when accessing remote media #11200

Merged
merged 8 commits into from
Nov 1, 2021
1 change: 1 addition & 0 deletions changelog.d/11200.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixes a long-standing bug wherein a missing Content-Type header when downloading remote media causes Synapse to throw an error.
H-Shay marked this conversation as resolved.
Show resolved Hide resolved
7 changes: 5 additions & 2 deletions synapse/rest/media/v1/media_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ async def get_local_media(

self.mark_recently_accessed(None, media_id)

media_type = media_info["media_type"]
media_type = media_info.get("media_type", "application/octet-stream")
squahtx marked this conversation as resolved.
Show resolved Hide resolved
media_length = media_info["media_length"]
upload_name = name if name else media_info["upload_name"]
url_cache = media_info["url_cache"]
Expand Down Expand Up @@ -445,7 +445,10 @@ async def _download_remote_file(

await finish()

media_type = headers[b"Content-Type"][0].decode("ascii")
if b"Content-Type" in headers:
media_type = headers[b"Content-Type"][0].decode("ascii")
else:
media_type = "application/octet-stream"
upload_name = get_filename_from_headers(headers)
time_now_ms = self.clock.time_msec()

Expand Down
2 changes: 1 addition & 1 deletion synapse/rest/media/v1/upload_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ async def _async_render_POST(self, request: SynapseRequest) -> None:
assert content_type_headers # for mypy
media_type = content_type_headers[0].decode("ascii")
else:
raise SynapseError(msg="Upload request missing 'Content-Type'", code=400)
media_type = "application/octet-stream"

# if headers.hasHeader(b"Content-Disposition"):
# disposition = headers.getRawHeaders(b"Content-Disposition")[0]
Expand Down
45 changes: 45 additions & 0 deletions tests/rest/media/v1/test_media_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,51 @@ def _req(self, content_disposition):

return channel

def test_handle_missing_content_type(self):
def _req_missing_headers(content_disposition):
channel = make_request(
self.reactor,
FakeSite(self.download_resource, self.reactor),
"GET",
self.media_id,
shorthand=False,
await_result=False,
)
self.pump()

# We've made one fetch, to example.com, using the media URL, and asking
# the other server not to do a remote fetch
self.assertEqual(len(self.fetches), 1)
self.assertEqual(self.fetches[0][1], "example.com")
self.assertEqual(
self.fetches[0][2], "/_matrix/media/r0/download/" + self.media_id
)
self.assertEqual(self.fetches[0][3], {"allow_remote": "false"})

headers = {
b"Content-Length": [b"%d" % (len(self.test_image.data))],
}
if content_disposition:
headers[b"Content-Disposition"] = [content_disposition]

self.fetches[0][0].callback(
(self.test_image.data, (len(self.test_image.data), headers))
)

self.pump()
self.assertEqual(channel.code, 200)

return channel
squahtx marked this conversation as resolved.
Show resolved Hide resolved

channel = _req_missing_headers(
b"inline; filename=out" + self.test_image.extension
)
headers = channel.headers
self.assertEqual(channel.code, 200)
self.assertEqual(
headers.getRawHeaders(b"Content-Type"), [b"application/octet-stream"]
)

def test_disposition_filename_ascii(self):
"""
If the filename is filename=<ascii> then Synapse will decode it as an
Expand Down