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

Fix exceptions in logs when failing to get remote room list #10541

Merged
merged 4 commits into from
Aug 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions changelog.d/10541.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix exceptions in logs when failing to get remote room list.
3 changes: 2 additions & 1 deletion synapse/federation/federation_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1108,7 +1108,8 @@ async def get_public_rooms(
The response from the remote server.

Raises:
HttpResponseException: There was an exception returned from the remote server
HttpResponseException / RequestSendFailed: There was an exception
returned from the remote server
SynapseException: M_FORBIDDEN when the remote server has disallowed publicRoom
requests over federation

Expand Down
46 changes: 28 additions & 18 deletions synapse/handlers/room_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,12 @@ async def get_remote_public_room_list(
include_all_networks: bool = False,
third_party_instance_id: Optional[str] = None,
) -> JsonDict:
"""Get the public room list from remote server

Raises:
SynapseError
"""

if not self.enable_room_list_search:
return {"chunk": [], "total_room_count_estimate": 0}

Expand Down Expand Up @@ -395,13 +401,16 @@ async def get_remote_public_room_list(
limit = None
since_token = None

res = await self._get_remote_list_cached(
server_name,
limit=limit,
since_token=since_token,
include_all_networks=include_all_networks,
third_party_instance_id=third_party_instance_id,
)
try:
res = await self._get_remote_list_cached(
server_name,
limit=limit,
since_token=since_token,
include_all_networks=include_all_networks,
third_party_instance_id=third_party_instance_id,
)
except (RequestSendFailed, HttpResponseException):
raise SynapseError(502, "Failed to fetch room list")

if search_filter:
res = {
Expand All @@ -423,20 +432,21 @@ async def _get_remote_list_cached(
include_all_networks: bool = False,
third_party_instance_id: Optional[str] = None,
) -> JsonDict:
"""Wrapper around FederationClient.get_public_rooms that caches the
Copy link
Member

Choose a reason for hiding this comment

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

I've got to wonder if caching a RequestSendFailed is the right thing to do, but that's a separate problem. 🤷‍♂️

Copy link
Member Author

Choose a reason for hiding this comment

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

🤷‍♂️

result.
"""

repl_layer = self.hs.get_federation_client()
if search_filter:
# We can't cache when asking for search
try:
return await repl_layer.get_public_rooms(
server_name,
limit=limit,
since_token=since_token,
search_filter=search_filter,
include_all_networks=include_all_networks,
third_party_instance_id=third_party_instance_id,
)
except (RequestSendFailed, HttpResponseException):
raise SynapseError(502, "Failed to fetch room list")
return await repl_layer.get_public_rooms(
server_name,
limit=limit,
since_token=since_token,
search_filter=search_filter,
include_all_networks=include_all_networks,
third_party_instance_id=third_party_instance_id,
)

key = (
server_name,
Expand Down
30 changes: 12 additions & 18 deletions synapse/rest/client/v1/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
from synapse.api.errors import (
AuthError,
Codes,
HttpResponseException,
InvalidClientCredentialsError,
ShadowBanError,
SynapseError,
Expand Down Expand Up @@ -778,12 +777,9 @@ async def on_GET(self, request):
Codes.INVALID_PARAM,
)

try:
data = await handler.get_remote_public_room_list(
server, limit=limit, since_token=since_token
)
except HttpResponseException as e:
raise e.to_synapse_error()
data = await handler.get_remote_public_room_list(
server, limit=limit, since_token=since_token
)
else:
data = await handler.get_local_public_room_list(
limit=limit, since_token=since_token
Expand Down Expand Up @@ -831,17 +827,15 @@ async def on_POST(self, request):
Codes.INVALID_PARAM,
)

try:
data = await handler.get_remote_public_room_list(
server,
limit=limit,
since_token=since_token,
search_filter=search_filter,
include_all_networks=include_all_networks,
third_party_instance_id=third_party_instance_id,
)
except HttpResponseException as e:
raise e.to_synapse_error()
data = await handler.get_remote_public_room_list(
server,
limit=limit,
since_token=since_token,
search_filter=search_filter,
include_all_networks=include_all_networks,
third_party_instance_id=third_party_instance_id,
)

else:
data = await handler.get_local_public_room_list(
limit=limit,
Expand Down
92 changes: 91 additions & 1 deletion tests/rest/client/v1/test_rooms.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@

import json
from typing import Iterable
from unittest.mock import Mock
from unittest.mock import Mock, call
from urllib import parse as urlparse

from twisted.internet import defer

import synapse.rest.admin
from synapse.api.constants import EventContentFields, EventTypes, Membership
from synapse.api.errors import HttpResponseException
from synapse.handlers.pagination import PurgeStatus
from synapse.rest import admin
from synapse.rest.client.v1 import directory, login, profile, room
Expand Down Expand Up @@ -1124,6 +1127,93 @@ def test_restricted_auth(self):
self.assertEqual(channel.code, 200, channel.result)


class PublicRoomsTestRemoteSearchFallbackTestCase(unittest.HomeserverTestCase):
"""Test that we correctly fallback to local filtering if a remote server
doesn't support search.
"""

servlets = [
synapse.rest.admin.register_servlets_for_client_rest_resource,
room.register_servlets,
login.register_servlets,
]

def make_homeserver(self, reactor, clock):
return self.setup_test_homeserver(federation_client=Mock())

def prepare(self, reactor, clock, hs):
self.register_user("user", "pass")
self.token = self.login("user", "pass")

self.federation_client = hs.get_federation_client()

def test_simple(self):
"Simple test for searching rooms over federation"
self.federation_client.get_public_rooms.side_effect = (
lambda *a, **k: defer.succeed({})
)

search_filter = {"generic_search_term": "foobar"}

channel = self.make_request(
"POST",
b"/_matrix/client/r0/publicRooms?server=testserv",
content={"filter": search_filter},
access_token=self.token,
)
self.assertEqual(channel.code, 200, channel.result)

self.federation_client.get_public_rooms.assert_called_once_with(
"testserv",
limit=100,
since_token=None,
search_filter=search_filter,
include_all_networks=False,
third_party_instance_id=None,
)

def test_fallback(self):
"Test that searching public rooms over federation falls back if it gets a 404"

# The `get_public_rooms` should be called again if the first call fails
# with a 404, when using search filters.
self.federation_client.get_public_rooms.side_effect = (
HttpResponseException(404, "Not Found", b""),
defer.succeed({}),
)

search_filter = {"generic_search_term": "foobar"}

channel = self.make_request(
"POST",
b"/_matrix/client/r0/publicRooms?server=testserv",
content={"filter": search_filter},
access_token=self.token,
)
self.assertEqual(channel.code, 200, channel.result)

self.federation_client.get_public_rooms.assert_has_calls(
[
call(
"testserv",
limit=100,
since_token=None,
search_filter=search_filter,
include_all_networks=False,
third_party_instance_id=None,
),
call(
"testserv",
limit=None,
since_token=None,
search_filter=None,
include_all_networks=False,
third_party_instance_id=None,
),
]
)


class PerRoomProfilesForbiddenTestCase(unittest.HomeserverTestCase):

servlets = [
Expand Down