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

Commit 0842114

Browse files
committed
Follow redirects when fetching from /download.
1 parent 600ddc4 commit 0842114

File tree

3 files changed

+40
-4
lines changed

3 files changed

+40
-4
lines changed

synapse/federation/transport/client.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -850,7 +850,11 @@ async def download_media_v3(
850850
# end up with a routing loop.
851851
"allow_remote": "false",
852852
"timeout_ms": str(max_timeout_ms),
853+
# Matix 1.7 allows for this to redirect to another URL, this should
854+
# just be ignored for an old homeserver, so always provide it.
855+
"allow_redirect": "true",
853856
},
857+
follow_redirects=True,
854858
)
855859

856860

synapse/http/matrixfederationclient.py

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,8 @@ def _create_txn_id(self) -> str:
164164
_next_id = (_next_id + 1) % (MAXINT - 1)
165165
return txn_id
166166

167-
uri: bytes = attr.ib(init=False)
168-
"""The URI of this request, generated from the above information.
167+
uri: bytes = attr.ib()
168+
"""The URI of this request, usually generated from the above information.
169169
"""
170170

171171
@uri.default
@@ -515,6 +515,7 @@ async def _send_request(
515515
ignore_backoff: bool = False,
516516
backoff_on_404: bool = False,
517517
backoff_on_all_error_codes: bool = False,
518+
follow_redirects: bool = False,
518519
) -> IResponse:
519520
"""
520521
Sends a request to the given server.
@@ -557,6 +558,9 @@ async def _send_request(
557558
backoff_on_404: Back off if we get a 404
558559
backoff_on_all_error_codes: Back off if we get any error response
559560
561+
follow_redirects: True to follow the Location header of 307/308 redirect
562+
responses. This does not recurse.
563+
560564
Returns:
561565
Resolves with the HTTP response object on success.
562566
@@ -716,6 +720,26 @@ async def _send_request(
716720
response.code,
717721
response_phrase,
718722
)
723+
elif (
724+
response.code in (307, 308)
725+
and follow_redirects
726+
and response.headers.hasHeader("Location")
727+
):
728+
# The Location header *might* be relative so resolve it.
729+
location = response.headers.getRawHeaders(b"Location")[0]
730+
new_uri = urllib.parse.urljoin(request.uri, location)
731+
732+
return await self._send_request(
733+
attr.evolve(request, uri=new_uri),
734+
retry_on_dns_fail,
735+
timeout,
736+
long_retries,
737+
ignore_backoff,
738+
backoff_on_404,
739+
backoff_on_all_error_codes,
740+
# Do not continue following redirects.
741+
follow_redirects=False,
742+
)
719743
else:
720744
logger.info(
721745
"{%s} [%s] Got response headers: %d %s",
@@ -1385,6 +1409,7 @@ async def get_file(
13851409
retry_on_dns_fail: bool = True,
13861410
max_size: Optional[int] = None,
13871411
ignore_backoff: bool = False,
1412+
follow_redirects: bool = False,
13881413
) -> Tuple[int, Dict[bytes, List[bytes]]]:
13891414
"""GETs a file from a given homeserver
13901415
Args:
@@ -1394,6 +1419,8 @@ async def get_file(
13941419
args: Optional dictionary used to create the query string.
13951420
ignore_backoff: true to ignore the historical backoff data
13961421
and try the request anyway.
1422+
follow_redirects: True to follow the Location header of 307/308 redirect
1423+
responses. This does not recurse.
13971424
13981425
Returns:
13991426
Resolves with an (int,dict) tuple of
@@ -1414,7 +1441,10 @@ async def get_file(
14141441
)
14151442

14161443
response = await self._send_request(
1417-
request, retry_on_dns_fail=retry_on_dns_fail, ignore_backoff=ignore_backoff
1444+
request,
1445+
retry_on_dns_fail=retry_on_dns_fail,
1446+
ignore_backoff=ignore_backoff,
1447+
follow_redirects=follow_redirects,
14181448
)
14191449

14201450
headers = dict(response.headers.getAllRawHeaders())

tests/media/test_media_storage.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ def get_file(
248248
retry_on_dns_fail: bool = True,
249249
max_size: Optional[int] = None,
250250
ignore_backoff: bool = False,
251+
follow_redirects: bool = False,
251252
) -> "Deferred[Tuple[int, Dict[bytes, List[bytes]]]]":
252253
"""A mock for MatrixFederationHttpClient.get_file."""
253254

@@ -325,7 +326,8 @@ def _req(
325326
self.fetches[0][2], "/_matrix/media/v3/download/" + self.media_id
326327
)
327328
self.assertEqual(
328-
self.fetches[0][3], {"allow_remote": "false", "timeout_ms": "20000"}
329+
self.fetches[0][3],
330+
{"allow_remote": "false", "timeout_ms": "20000", "allow_redirect": "true"},
329331
)
330332

331333
headers = {

0 commit comments

Comments
 (0)