Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
39 changes: 39 additions & 0 deletions tests/federation/test_federation_media.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,45 @@ def test_file_download(self) -> None:
found_file = any(SMALL_PNG in field for field in stripped_bytes)
self.assertTrue(found_file)

def test_federation_etag(self) -> None:
"""Test that federation ETags work"""

content = io.BytesIO(b"file_to_stream")
content_uri = self.get_success(
self.media_repo.create_content(
"text/plain",
"test_upload",
content,
46,
UserID.from_string("@user_id:whatever.org"),
)
)

channel = self.make_signed_federation_request(
"GET",
f"/_matrix/federation/v1/media/download/{content_uri.media_id}",
)
self.pump()
self.assertEqual(200, channel.code)

# We expect exactly one ETag header.
etags = channel.headers.getRawHeaders("ETag")
self.assertIsNotNone(etags)
assert etags is not None # For mypy
self.assertEqual(len(etags), 1)
etag = etags[0]

# Refetching with the etag should result in 304 and empty body.
channel = self.make_signed_federation_request(
"GET",
f"/_matrix/federation/v1/media/download/{content_uri.media_id}",
custom_headers=[("If-None-Match", etag)],
)
self.pump()
self.assertEqual(channel.code, 304)
self.assertEqual(channel.is_finished(), True)
self.assertNotIn("body", channel.result)


class FederationThumbnailTest(unittest.FederatingHomeserverTestCase):
def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
Expand Down
110 changes: 110 additions & 0 deletions tests/rest/client/test_media.py
Original file line number Diff line number Diff line change
Expand Up @@ -2676,3 +2676,113 @@ def test_authenticated_media(self) -> None:
access_token=self.tok,
)
self.assertEqual(channel10.code, 200)

def test_authenticated_media_etag(self) -> None:
"""Test that ETag work correctly with authenticated media over client
Comment thread
erikjohnston marked this conversation as resolved.
Outdated
APIs"""

# upload some local media with authentication on
channel = self.make_request(
"POST",
"_matrix/media/v3/upload?filename=test_png_upload",
SMALL_PNG,
self.tok,
shorthand=False,
content_type=b"image/png",
custom_headers=[("Content-Length", str(67))],
)
self.assertEqual(channel.code, 200)
res = channel.json_body.get("content_uri")
assert res is not None
uri = res.split("mxc://")[1]

# Check standard media endpoint
self._check_caching(f"/download/{uri}")

# check thumbnails as well
params = "?width=32&height=32&method=crop"
self._check_caching(f"/thumbnail/{uri}{params}")

# Inject a piece of remote media.
file_id = "abcdefg12345"
file_info = FileInfo(server_name="lonelyIsland", file_id=file_id)

media_storage = self.hs.get_media_repository().media_storage

ctx = media_storage.store_into_file(file_info)
(f, fname) = self.get_success(ctx.__aenter__())
f.write(SMALL_PNG)
self.get_success(ctx.__aexit__(None, None, None))

# we write the authenticated status when storing media, so this should pick up
# config and authenticate the media
self.get_success(
self.store.store_cached_remote_media(
origin="lonelyIsland",
media_id="52",
media_type="image/png",
media_length=1,
time_now_ms=self.clock.time_msec(),
upload_name="remote_test.png",
filesystem_id=file_id,
)
)

# ensure we have thumbnails for the non-dynamic code path
if self.extra_config == {"dynamic_thumbnails": False}:
self.get_success(
self.repo._generate_thumbnails(
"lonelyIsland", "52", file_id, "image/png"
)
)

self._check_caching("/download/lonelyIsland/52")

params = "?width=32&height=32&method=crop"
self._check_caching(f"/thumbnail/lonelyIsland/52{params}")

def _check_caching(self, path: str) -> None:
"""
Checks that:
1. fetching the path returns an ETag header
2. refetching with the ETag returns a 304 without a body
3. refetching with the ETag but through unauthenticated endpoint
returns 404
"""

# Request media over authenticated endpoint, should be found
channel1 = self.make_request(
"GET",
f"/_matrix/client/v1/media{path}",
access_token=self.tok,
shorthand=False,
)
self.assertEqual(channel1.code, 200)

# Should have a single ETag field
etags = channel1.headers.getRawHeaders("ETag")
self.assertIsNotNone(etags)
assert etags is not None # For mypy
self.assertEqual(len(etags), 1)
etag = etags[0]

# Refetching with the etag should result in 304 and empty body.
channel2 = self.make_request(
"GET",
f"/_matrix/client/v1/media{path}",
access_token=self.tok,
shorthand=False,
custom_headers=[("If-None-Match", etag)],
)
self.assertEqual(channel2.code, 304)
self.assertEqual(channel2.is_finished(), True)
self.assertNotIn("body", channel2.result)

# Refetching with the etag but no access token should result in 404.
channel3 = self.make_request(
"GET",
f"/_matrix/media/r0{path}",
shorthand=False,
custom_headers=[("If-None-Match", etag)],
)
self.assertEqual(channel3.code, 404)