diff options
-rw-r--r-- | changelog.d/4840.feature | 1 | ||||
-rw-r--r-- | synapse/federation/transport/client.py | 24 | ||||
-rw-r--r-- | synapse/http/matrixfederationclient.py | 45 |
3 files changed, 59 insertions, 11 deletions
diff --git a/changelog.d/4840.feature b/changelog.d/4840.feature new file mode 100644 index 0000000000..9d1fd59053 --- /dev/null +++ b/changelog.d/4840.feature @@ -0,0 +1 @@ +Remove trailing slashes from certain outbound federation requests. Retry if receiving a 404. Context: #3622. \ No newline at end of file diff --git a/synapse/federation/transport/client.py b/synapse/federation/transport/client.py index 4e8919d657..68808e9203 100644 --- a/synapse/federation/transport/client.py +++ b/synapse/federation/transport/client.py @@ -51,8 +51,8 @@ class TransportLayerClient(object): logger.debug("get_room_state dest=%s, room=%s", destination, room_id) - path = _create_v1_path("/state/%s/", room_id) - return self.client.get_json( + path = _create_v1_path("/state/%s", room_id) + return self.client.get_json_with_trailing_slashes_on_404( destination, path=path, args={"event_id": event_id}, ) @@ -73,8 +73,8 @@ class TransportLayerClient(object): logger.debug("get_room_state_ids dest=%s, room=%s", destination, room_id) - path = _create_v1_path("/state_ids/%s/", room_id) - return self.client.get_json( + path = _create_v1_path("/state_ids/%s", room_id) + return self.client.get_json_with_trailing_slashes_on_404( destination, path=path, args={"event_id": event_id}, ) @@ -95,8 +95,10 @@ class TransportLayerClient(object): logger.debug("get_pdu dest=%s, event_id=%s", destination, event_id) - path = _create_v1_path("/event/%s/", event_id) - return self.client.get_json(destination, path=path, timeout=timeout) + path = _create_v1_path("/event/%s", event_id) + return self.client.get_json_with_trailing_slashes_on_404( + destination, path=path, timeout=timeout, + ) @log_function def backfill(self, destination, room_id, event_tuples, limit): @@ -121,14 +123,14 @@ class TransportLayerClient(object): # TODO: raise? return - path = _create_v1_path("/backfill/%s/", room_id) + path = _create_v1_path("/backfill/%s", room_id) args = { "v": event_tuples, "limit": [str(limit)], } - return self.client.get_json( + return self.client.get_json_with_trailing_slashes_on_404( destination, path=path, args=args, @@ -169,7 +171,7 @@ class TransportLayerClient(object): path = _create_v1_path("/send/%s", transaction.transaction_id) - response = yield self.client.put_json( + response = yield self.client.put_json_with_trailing_slashes_on_404( transaction.destination, path=path, data=json_data, @@ -959,7 +961,7 @@ def _create_v1_path(path, *args): Example: - _create_v1_path("/event/%s/", event_id) + _create_v1_path("/event/%s", event_id) Args: path (str): String template for the path @@ -980,7 +982,7 @@ def _create_v2_path(path, *args): Example: - _create_v2_path("/event/%s/", event_id) + _create_v2_path("/event/%s", event_id) Args: path (str): String template for the path diff --git a/synapse/http/matrixfederationclient.py b/synapse/http/matrixfederationclient.py index 1682c9af13..8776639d6a 100644 --- a/synapse/http/matrixfederationclient.py +++ b/synapse/http/matrixfederationclient.py @@ -644,6 +644,51 @@ class MatrixFederationHttpClient(object): defer.returnValue(body) @defer.inlineCallbacks + def get_json_with_trailing_slashes_on_404(self, args={}): + """Runs client.get_json under the hood, but if receiving a 404, tries + the request again with a trailing slash. This is a result of removing + trailing slashes from some federation endpoints and in an effort to + remain backwards compatible with older versions of Synapse, we try + again if a server requires a trailing slash. + + Args: + args (dict): A dictionary of arguments matching those provided by put_json. + Returns: + Deferred[dict|list]: Succeeds when we get a 2xx HTTP response. The + result will be the decoded JSON body. + """ + response = yield self.get_json(**args) + + # Retry with a trailing slash if we received a 404 + if response.code == 404: + args["path"] += "/" + response = yield self.get_json(**args) + + defer.returnValue(response) + + @defer.inlineCallbacks + def put_json_with_trailing_slashes_on_404(self, args={}): + """Runs client.put_json under the hood, but if receiving a 404, tries + the request again with a trailing slash. + + See get_json_with_trailing_slashes_on_404 for more details. + + Args: + args (dict): A dictionary of arguments matching those provided by put_json. + Returns: + Deferred[dict|list]: Succeeds when we get a 2xx HTTP response. The + result will be the decoded JSON body. + """ + response = yield self.put_json(**args) + + # Retry with a trailing slash if we received a 404 + if response.code == 404: + args["path"] += "/" + response = yield self.put_json(**args) + + defer.returnValue(response) + + @defer.inlineCallbacks def delete_json(self, destination, path, long_retries=False, timeout=None, ignore_backoff=False, args={}): """Send a DELETE request to the remote expecting some json response |