diff --git a/synapse/media/thumbnailer.py b/synapse/media/thumbnailer.py
index f8a9560784..413a720e40 100644
--- a/synapse/media/thumbnailer.py
+++ b/synapse/media/thumbnailer.py
@@ -36,9 +36,11 @@ from synapse.media._base import (
ThumbnailInfo,
respond_404,
respond_with_file,
+ respond_with_multipart_responder,
respond_with_responder,
)
-from synapse.media.media_storage import MediaStorage
+from synapse.media.media_storage import FileResponder, MediaStorage
+from synapse.storage.databases.main.media_repository import LocalMedia
if TYPE_CHECKING:
from synapse.media.media_repository import MediaRepository
@@ -271,6 +273,7 @@ class ThumbnailProvider:
method: str,
m_type: str,
max_timeout_ms: int,
+ for_federation: bool,
) -> None:
media_info = await self.media_repo.get_local_media_info(
request, media_id, max_timeout_ms
@@ -290,6 +293,8 @@ class ThumbnailProvider:
media_id,
url_cache=bool(media_info.url_cache),
server_name=None,
+ for_federation=for_federation,
+ media_info=media_info,
)
async def select_or_generate_local_thumbnail(
@@ -301,6 +306,7 @@ class ThumbnailProvider:
desired_method: str,
desired_type: str,
max_timeout_ms: int,
+ for_federation: bool,
) -> None:
media_info = await self.media_repo.get_local_media_info(
request, media_id, max_timeout_ms
@@ -326,10 +332,16 @@ class ThumbnailProvider:
responder = await self.media_storage.fetch_media(file_info)
if responder:
- await respond_with_responder(
- request, responder, info.type, info.length
- )
- return
+ if for_federation:
+ await respond_with_multipart_responder(
+ self.hs.get_clock(), request, responder, media_info
+ )
+ return
+ else:
+ await respond_with_responder(
+ request, responder, info.type, info.length
+ )
+ return
logger.debug("We don't have a thumbnail of that size. Generating")
@@ -344,7 +356,15 @@ class ThumbnailProvider:
)
if file_path:
- await respond_with_file(request, desired_type, file_path)
+ if for_federation:
+ await respond_with_multipart_responder(
+ self.hs.get_clock(),
+ request,
+ FileResponder(open(file_path, "rb")),
+ media_info,
+ )
+ else:
+ await respond_with_file(request, desired_type, file_path)
else:
logger.warning("Failed to generate thumbnail")
raise SynapseError(400, "Failed to generate thumbnail.")
@@ -360,9 +380,10 @@ class ThumbnailProvider:
desired_type: str,
max_timeout_ms: int,
ip_address: str,
+ use_federation: bool,
) -> None:
media_info = await self.media_repo.get_remote_media_info(
- server_name, media_id, max_timeout_ms, ip_address
+ server_name, media_id, max_timeout_ms, ip_address, use_federation
)
if not media_info:
respond_404(request)
@@ -424,12 +445,13 @@ class ThumbnailProvider:
m_type: str,
max_timeout_ms: int,
ip_address: str,
+ use_federation: bool,
) -> None:
# TODO: Don't download the whole remote file
# We should proxy the thumbnail from the remote server instead of
# downloading the remote file and generating our own thumbnails.
media_info = await self.media_repo.get_remote_media_info(
- server_name, media_id, max_timeout_ms, ip_address
+ server_name, media_id, max_timeout_ms, ip_address, use_federation
)
if not media_info:
return
@@ -448,6 +470,7 @@ class ThumbnailProvider:
media_info.filesystem_id,
url_cache=False,
server_name=server_name,
+ for_federation=False,
)
async def _select_and_respond_with_thumbnail(
@@ -461,7 +484,9 @@ class ThumbnailProvider:
media_id: str,
file_id: str,
url_cache: bool,
+ for_federation: bool,
server_name: Optional[str] = None,
+ media_info: Optional[LocalMedia] = None,
) -> None:
"""
Respond to a request with an appropriate thumbnail from the previously generated thumbnails.
@@ -476,6 +501,8 @@ class ThumbnailProvider:
file_id: The ID of the media that a thumbnail is being requested for.
url_cache: True if this is from a URL cache.
server_name: The server name, if this is a remote thumbnail.
+ for_federation: whether the request is from the federation /thumbnail request
+ media_info: metadata about the media being requested.
"""
logger.debug(
"_select_and_respond_with_thumbnail: media_id=%s desired=%sx%s (%s) thumbnail_infos=%s",
@@ -511,13 +538,20 @@ class ThumbnailProvider:
responder = await self.media_storage.fetch_media(file_info)
if responder:
- await respond_with_responder(
- request,
- responder,
- file_info.thumbnail.type,
- file_info.thumbnail.length,
- )
- return
+ if for_federation:
+ assert media_info is not None
+ await respond_with_multipart_responder(
+ self.hs.get_clock(), request, responder, media_info
+ )
+ return
+ else:
+ await respond_with_responder(
+ request,
+ responder,
+ file_info.thumbnail.type,
+ file_info.thumbnail.length,
+ )
+ return
# If we can't find the thumbnail we regenerate it. This can happen
# if e.g. we've deleted the thumbnails but still have the original
@@ -558,12 +592,18 @@ class ThumbnailProvider:
)
responder = await self.media_storage.fetch_media(file_info)
- await respond_with_responder(
- request,
- responder,
- file_info.thumbnail.type,
- file_info.thumbnail.length,
- )
+ if for_federation:
+ assert media_info is not None
+ await respond_with_multipart_responder(
+ self.hs.get_clock(), request, responder, media_info
+ )
+ else:
+ await respond_with_responder(
+ request,
+ responder,
+ file_info.thumbnail.type,
+ file_info.thumbnail.length,
+ )
else:
# This might be because:
# 1. We can't create thumbnails for the given media (corrupted or
|