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

Remove trailing slashes from outbound federation requests #4840

Merged
merged 42 commits into from
Mar 21, 2019
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
525dd02
Remove trailing slashes from outbound federation requests
anoadragon453 Mar 8, 2019
64ff110
Retry certain federation requests on 404
anoadragon453 Mar 8, 2019
f8740d5
Add changelog
anoadragon453 Mar 8, 2019
a5dd335
lint
anoadragon453 Mar 8, 2019
a8a028d
Merge branch 'develop' into anoa/trailing_slashes_client
anoadragon453 Mar 11, 2019
f18dca2
Merge branch 'develop' into anoa/trailing_slashes_client
anoadragon453 Mar 11, 2019
66f205e
We're calling different functions now
anoadragon453 Mar 11, 2019
802cb5d
Fix syntax error
anoadragon453 Mar 11, 2019
4868b12
and again
anoadragon453 Mar 11, 2019
0ea8582
Cleaner way of implementing trailing slashes
anoadragon453 Mar 12, 2019
97653ef
Correct argument name
anoadragon453 Mar 12, 2019
cf301e3
Add workaround note
anoadragon453 Mar 13, 2019
7e75d96
Fix paranthesis indent
anoadragon453 Mar 13, 2019
7d053cf
Retry on 400:M_UNRECOGNIZED
anoadragon453 Mar 13, 2019
09626bf
Switch to wrapper function around _send_request
anoadragon453 Mar 13, 2019
5526b05
Fix syntax issues
anoadragon453 Mar 13, 2019
660b77f
Add missing docstring detail
anoadragon453 Mar 13, 2019
220607a
Remove testing code
anoadragon453 Mar 13, 2019
9dd0e34
Syntax test
anoadragon453 Mar 13, 2019
ee8ba39
Are you happy now
anoadragon453 Mar 13, 2019
c2d848b
Destructure again
anoadragon453 Mar 13, 2019
c991e7a
Syntax checker is bork
anoadragon453 Mar 13, 2019
bec3138
go home python, you're drunk
anoadragon453 Mar 13, 2019
66cdb84
Or perhaps I was the one who was drunk
anoadragon453 Mar 13, 2019
7c0295f
no kwargs today
anoadragon453 Mar 13, 2019
5ca857a
as above
anoadragon453 Mar 13, 2019
26f8e2d
there comes a time when you should give up. but you dont
anoadragon453 Mar 13, 2019
8d16ffa
i should have given up
anoadragon453 Mar 13, 2019
45524f2
i should have given up x2
anoadragon453 Mar 13, 2019
86c60bd
i should have given up x3
anoadragon453 Mar 13, 2019
9a2e22f
is this what purgatory feels like
anoadragon453 Mar 13, 2019
b2df0e8
receiving a 400 caused an exception. handle it
anoadragon453 Mar 13, 2019
ecea5af
Correct var name
anoadragon453 Mar 13, 2019
621e7f3
Better exception handling
anoadragon453 Mar 18, 2019
a8ad39e
lint
anoadragon453 Mar 18, 2019
94cb793
Federation test fixed!
anoadragon453 Mar 20, 2019
551ea11
Just return if not doing any trailing slash shennanigans
anoadragon453 Mar 20, 2019
c69df5d
Fix comments. v0.99.2 -> v0.99.3
anoadragon453 Mar 20, 2019
cd36a12
New test, fix issues
anoadragon453 Mar 20, 2019
bb52a2e
lint
anoadragon453 Mar 20, 2019
2150151
kwargs doesn't like commas on calling funcs either. TIL
anoadragon453 Mar 20, 2019
b41c2ea
Clean up backoff_on_404 and metehod calls
anoadragon453 Mar 21, 2019
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
1 change: 1 addition & 0 deletions changelog.d/4840.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Remove trailing slashes from certain outbound federation requests. Retry if receiving a 404. Context: #3622.
21 changes: 14 additions & 7 deletions synapse/federation/transport/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,10 @@ def get_room_state(self, destination, room_id, event_id):
logger.debug("get_room_state dest=%s, room=%s",
destination, room_id)

path = _create_v1_path("/state/%s/", room_id)
path = _create_v1_path("/state/%s", room_id)
return self.client.get_json(
destination, path=path, args={"event_id": event_id},
try_trailing_slash_on_404=True,
)

@log_function
Expand All @@ -73,9 +74,10 @@ def get_room_state_ids(self, destination, room_id, event_id):
logger.debug("get_room_state_ids dest=%s, room=%s",
destination, room_id)

path = _create_v1_path("/state_ids/%s/", room_id)
path = _create_v1_path("/state_ids/%s", room_id)
return self.client.get_json(
destination, path=path, args={"event_id": event_id},
try_trailing_slash_on_404=True,
)

@log_function
Expand All @@ -95,8 +97,11 @@ def get_event(self, destination, event_id, timeout=None):
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(
destination, path=path, timeout=timeout,
try_trailing_slash_on_404=True,
)

@log_function
def backfill(self, destination, room_id, event_tuples, limit):
Expand All @@ -121,7 +126,7 @@ def backfill(self, destination, room_id, event_tuples, limit):
# TODO: raise?
return

path = _create_v1_path("/backfill/%s/", room_id)
path = _create_v1_path("/backfill/%s", room_id)

args = {
"v": event_tuples,
Expand All @@ -132,6 +137,7 @@ def backfill(self, destination, room_id, event_tuples, limit):
destination,
path=path,
args=args,
try_trailing_slash_on_404=True,
)

@defer.inlineCallbacks
Expand Down Expand Up @@ -176,6 +182,7 @@ def send_transaction(self, transaction, json_data_callback=None):
json_data_callback=json_data_callback,
long_retries=True,
backoff_on_404=True, # If we get a 404 the other side has gone
try_trailing_slash_on_404=True,
)

defer.returnValue(response)
Expand Down Expand Up @@ -959,7 +966,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
Expand All @@ -980,7 +987,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
Expand Down
70 changes: 52 additions & 18 deletions synapse/http/matrixfederationclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,8 @@ def _send_request(
timeout=None,
long_retries=False,
ignore_backoff=False,
backoff_on_404=False
backoff_on_404=False,
try_trailing_slash_on_404=False,
):
"""
Sends a request to the given server.
Expand All @@ -212,6 +213,11 @@ def _send_request(

backoff_on_404 (bool): Back off if we get a 404

try_trailing_slash_on_404 (bool): True if on a 404 response we
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it might be worth adding a note on why this is a useful thing to do ("workaround for #3622 in Synapse 0.99.2 and earlier" ?)

should try appending a trailing slash to the end of the
request. This will be attempted before backing off if backing
off has been enabled.

Returns:
Deferred[twisted.web.client.Response]: resolves with the HTTP
response object on success.
Expand Down Expand Up @@ -473,7 +479,8 @@ def put_json(self, destination, path, args={}, data={},
json_data_callback=None,
long_retries=False, timeout=None,
ignore_backoff=False,
backoff_on_404=False):
backoff_on_404=False,
try_trailing_slash_on_404=False):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
try_trailing_slash_on_404=False):
try_trailing_slash_on_404=False,
):

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

flake unfortunately complains about visual indentations if we do this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/me shakes fist

""" Sends the specifed json data using PUT

Args:
Expand All @@ -493,7 +500,11 @@ def put_json(self, destination, path, args={}, data={},
and try the request anyway.
backoff_on_404 (bool): True if we should count a 404 response as
a failure of the server (and should therefore back off future
requests)
requests).
try_trailing_slash_on_404 (bool): True if on a 404 response we
should try appending a trailing slash to the end of the
request. This will be attempted before backing off if backing
off has been enabled.

Returns:
Deferred[dict|list]: Succeeds when we get a 2xx HTTP response. The
Expand All @@ -509,7 +520,6 @@ def put_json(self, destination, path, args={}, data={},
RequestSendFailed: If there were problems connecting to the
remote, due to e.g. DNS failures, connection timeouts etc.
"""

request = MatrixFederationRequest(
method="PUT",
destination=destination,
Expand All @@ -519,13 +529,26 @@ def put_json(self, destination, path, args={}, data={},
json=data,
)

response = yield self._send_request(
request,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: it's probably best to leave it as one arg on each line - it gets a bit impenetrable otherwise.

long_retries=long_retries,
timeout=timeout,
ignore_backoff=ignore_backoff,
backoff_on_404=backoff_on_404,
)
send_request_args = {
"request": request,
"long_retries": long_retries,
"timeout": timeout,
"ignore_backoff": ignore_backoff,
# Do not backoff on the initial request if we're trying with trailing slashes
# Otherwise we may end up waiting to contact a server that is actually up
"backoff_on_404": False if try_trailing_slash_on_404 else backoff_on_404,
}

response = yield self._send_request(**send_request_args)

# If enabled, retry with a trailing slash if we received a 404
if try_trailing_slash_on_404 and response.code == 404:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you seem to have missed the 400 case here, which brings me to:

how about implementing this with a wrapper which you can use in both cases?

def _send_request_with_optional_trailing_slash(request, try_trailing_slash_on_404=False, **kwargs):
    self._send_request(request, **kwargs)
    if that_worked:
        return
    fiddle_with(request)
    self._send_request(request, **kwargs)

args["path"] += "/"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you sure this is the right thing to do?


# Re-enable backoff if enabled
send_request_args["backoff_on_404"] = backoff_on_404

response = yield self.get_json(**send_request_args)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we switch to get_json here?


body = yield _handle_json_response(
self.hs.get_reactor(), self.default_timeout, request, response,
Expand Down Expand Up @@ -592,7 +615,8 @@ def post_json(self, destination, path, data={}, long_retries=False,

@defer.inlineCallbacks
def get_json(self, destination, path, args=None, retry_on_dns_fail=True,
timeout=None, ignore_backoff=False):
timeout=None, ignore_backoff=False,
try_trailing_slash_on_404=False):
""" GETs some json from the given host homeserver and path

Args:
Expand All @@ -606,6 +630,9 @@ def get_json(self, destination, path, args=None, retry_on_dns_fail=True,
be retried.
ignore_backoff (bool): true to ignore the historical backoff data
and try the request anyway.
try_trailing_slash_on_404 (bool): True if on a 404 response we
should try appending a trailing slash to the end of the
request.
Returns:
Deferred[dict|list]: Succeeds when we get a 2xx HTTP response. The
result will be the decoded JSON body.
Expand All @@ -631,12 +658,19 @@ def get_json(self, destination, path, args=None, retry_on_dns_fail=True,
query=args,
)

response = yield self._send_request(
request,
retry_on_dns_fail=retry_on_dns_fail,
timeout=timeout,
ignore_backoff=ignore_backoff,
)
send_request_args = {
"request": request,
"retry_on_dns_fail": retry_on_dns_fail,
"timeout": timeout,
"ignore_backoff": ignore_backoff,
}

response = yield self._send_request(**send_request_args)

# If enabled, retry with a trailing slash if we received a 404
if try_trailing_slash_on_404 and response.code == 404:
args["path"] += "/"
response = yield self._send_request(**send_request_args)

body = yield _handle_json_response(
self.hs.get_reactor(), self.default_timeout, request, response,
Expand Down
2 changes: 2 additions & 0 deletions tests/handlers/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ def test_started_typing_remote_send(self):
json_data_callback=ANY,
long_retries=True,
backoff_on_404=True,
try_trailing_slash_on_404=True,
)

def test_started_typing_remote_recv(self):
Expand Down Expand Up @@ -269,6 +270,7 @@ def test_stopped_typing(self):
json_data_callback=ANY,
long_retries=True,
backoff_on_404=True,
try_trailing_slash_on_404=True,
)

self.assertEquals(self.event_source.get_current_key(), 1)
Expand Down