mirror of
https://git.anonymousland.org/anonymousland/synapse-product.git
synced 2024-12-17 13:54:22 -05:00
Follow redirects on .well-known (#4520)
This commit is contained in:
parent
f6813919e8
commit
c7b24ac3d0
1
changelog.d/4520.feature
Normal file
1
changelog.d/4520.feature
Normal file
@ -0,0 +1 @@
|
||||
Implement MSC1708 (.well-known routing for server-server federation)
|
@ -23,7 +23,7 @@ from zope.interface import implementer
|
||||
|
||||
from twisted.internet import defer
|
||||
from twisted.internet.endpoints import HostnameEndpoint, wrapClientTLS
|
||||
from twisted.web.client import URI, Agent, HTTPConnectionPool, readBody
|
||||
from twisted.web.client import URI, Agent, HTTPConnectionPool, RedirectAgent, readBody
|
||||
from twisted.web.http import stringToDatetime
|
||||
from twisted.web.http_headers import Headers
|
||||
from twisted.web.iweb import IAgent
|
||||
@ -93,7 +93,9 @@ class MatrixFederationAgent(object):
|
||||
# the param is called 'contextFactory', but actually passing a
|
||||
# contextfactory is deprecated, and it expects an IPolicyForHTTPS.
|
||||
agent_args['contextFactory'] = _well_known_tls_policy
|
||||
_well_known_agent = Agent(self._reactor, pool=self._pool, **agent_args)
|
||||
_well_known_agent = RedirectAgent(
|
||||
Agent(self._reactor, pool=self._pool, **agent_args),
|
||||
)
|
||||
self._well_known_agent = _well_known_agent
|
||||
|
||||
self._well_known_cache = _well_known_cache
|
||||
|
@ -470,6 +470,103 @@ class MatrixFederationAgentTests(TestCase):
|
||||
self.well_known_cache.expire()
|
||||
self.assertNotIn(b"testserv", self.well_known_cache)
|
||||
|
||||
def test_get_well_known_redirect(self):
|
||||
"""Test the behaviour when the server name has no port and no SRV record, but
|
||||
the .well-known has a 300 redirect
|
||||
"""
|
||||
self.mock_resolver.resolve_service.side_effect = lambda _: []
|
||||
self.reactor.lookups["testserv"] = "1.2.3.4"
|
||||
self.reactor.lookups["target-server"] = "1::f"
|
||||
|
||||
test_d = self._make_get_request(b"matrix://testserv/foo/bar")
|
||||
|
||||
# Nothing happened yet
|
||||
self.assertNoResult(test_d)
|
||||
|
||||
self.mock_resolver.resolve_service.assert_called_once_with(
|
||||
b"_matrix._tcp.testserv",
|
||||
)
|
||||
self.mock_resolver.resolve_service.reset_mock()
|
||||
|
||||
# there should be an attempt to connect on port 443 for the .well-known
|
||||
clients = self.reactor.tcpClients
|
||||
self.assertEqual(len(clients), 1)
|
||||
(host, port, client_factory, _timeout, _bindAddress) = clients.pop()
|
||||
self.assertEqual(host, '1.2.3.4')
|
||||
self.assertEqual(port, 443)
|
||||
|
||||
redirect_server = self._make_connection(
|
||||
client_factory,
|
||||
expected_sni=b"testserv",
|
||||
)
|
||||
|
||||
# send a 302 redirect
|
||||
self.assertEqual(len(redirect_server.requests), 1)
|
||||
request = redirect_server.requests[0]
|
||||
request.redirect(b'https://testserv/even_better_known')
|
||||
request.finish()
|
||||
|
||||
self.reactor.pump((0.1, ))
|
||||
|
||||
# now there should be another connection
|
||||
clients = self.reactor.tcpClients
|
||||
self.assertEqual(len(clients), 1)
|
||||
(host, port, client_factory, _timeout, _bindAddress) = clients.pop()
|
||||
self.assertEqual(host, '1.2.3.4')
|
||||
self.assertEqual(port, 443)
|
||||
|
||||
well_known_server = self._make_connection(
|
||||
client_factory,
|
||||
expected_sni=b"testserv",
|
||||
)
|
||||
|
||||
self.assertEqual(len(well_known_server.requests), 1, "No request after 302")
|
||||
request = well_known_server.requests[0]
|
||||
self.assertEqual(request.method, b'GET')
|
||||
self.assertEqual(request.path, b'/even_better_known')
|
||||
request.write(b'{ "m.server": "target-server" }')
|
||||
request.finish()
|
||||
|
||||
self.reactor.pump((0.1, ))
|
||||
|
||||
# there should be another SRV lookup
|
||||
self.mock_resolver.resolve_service.assert_called_once_with(
|
||||
b"_matrix._tcp.target-server",
|
||||
)
|
||||
|
||||
# now we should get a connection to the target server
|
||||
self.assertEqual(len(clients), 1)
|
||||
(host, port, client_factory, _timeout, _bindAddress) = clients[0]
|
||||
self.assertEqual(host, '1::f')
|
||||
self.assertEqual(port, 8448)
|
||||
|
||||
# make a test server, and wire up the client
|
||||
http_server = self._make_connection(
|
||||
client_factory,
|
||||
expected_sni=b'target-server',
|
||||
)
|
||||
|
||||
self.assertEqual(len(http_server.requests), 1)
|
||||
request = http_server.requests[0]
|
||||
self.assertEqual(request.method, b'GET')
|
||||
self.assertEqual(request.path, b'/foo/bar')
|
||||
self.assertEqual(
|
||||
request.requestHeaders.getRawHeaders(b'host'),
|
||||
[b'target-server'],
|
||||
)
|
||||
|
||||
# finish the request
|
||||
request.finish()
|
||||
self.reactor.pump((0.1,))
|
||||
self.successResultOf(test_d)
|
||||
|
||||
self.assertEqual(self.well_known_cache[b"testserv"], b"target-server")
|
||||
|
||||
# check the cache expires
|
||||
self.reactor.pump((25 * 3600,))
|
||||
self.well_known_cache.expire()
|
||||
self.assertNotIn(b"testserv", self.well_known_cache)
|
||||
|
||||
def test_get_hostname_srv(self):
|
||||
"""
|
||||
Test the behaviour when there is a single SRV record
|
||||
|
Loading…
Reference in New Issue
Block a user