test_matrix_federation_agent.py 66 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831
  1. # Copyright 2019 New Vector Ltd
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import base64
  15. import logging
  16. import os
  17. from typing import Generator, List, Optional, cast
  18. from unittest.mock import AsyncMock, call, patch
  19. import treq
  20. from netaddr import IPSet
  21. from service_identity import VerificationError
  22. from zope.interface import implementer
  23. from twisted.internet import defer
  24. from twisted.internet._sslverify import ClientTLSOptions, OpenSSLCertificateOptions
  25. from twisted.internet.defer import Deferred
  26. from twisted.internet.endpoints import _WrappingProtocol
  27. from twisted.internet.interfaces import (
  28. IOpenSSLClientConnectionCreator,
  29. IProtocolFactory,
  30. )
  31. from twisted.internet.protocol import Factory, Protocol
  32. from twisted.protocols.tls import TLSMemoryBIOProtocol
  33. from twisted.web._newclient import ResponseNeverReceived
  34. from twisted.web.client import Agent
  35. from twisted.web.http import HTTPChannel, Request
  36. from twisted.web.http_headers import Headers
  37. from twisted.web.iweb import IPolicyForHTTPS, IResponse
  38. from synapse.config.homeserver import HomeServerConfig
  39. from synapse.crypto.context_factory import FederationPolicyForHTTPS
  40. from synapse.http.federation.matrix_federation_agent import MatrixFederationAgent
  41. from synapse.http.federation.srv_resolver import Server, SrvResolver
  42. from synapse.http.federation.well_known_resolver import (
  43. WELL_KNOWN_MAX_SIZE,
  44. WellKnownResolver,
  45. _cache_period_from_headers,
  46. )
  47. from synapse.logging.context import (
  48. SENTINEL_CONTEXT,
  49. LoggingContext,
  50. LoggingContextOrSentinel,
  51. current_context,
  52. )
  53. from synapse.types import ISynapseReactor
  54. from synapse.util.caches.ttlcache import TTLCache
  55. from tests import unittest
  56. from tests.http import dummy_address, get_test_ca_cert_file, wrap_server_factory_for_tls
  57. from tests.server import FakeTransport, ThreadedMemoryReactorClock
  58. from tests.utils import checked_cast, default_config
  59. logger = logging.getLogger(__name__)
  60. class MatrixFederationAgentTests(unittest.TestCase):
  61. def setUp(self) -> None:
  62. self.reactor = ThreadedMemoryReactorClock()
  63. self.mock_resolver = AsyncMock(spec=SrvResolver)
  64. config_dict = default_config("test", parse=False)
  65. config_dict["federation_custom_ca_list"] = [get_test_ca_cert_file()]
  66. self._config = config = HomeServerConfig()
  67. config.parse_config_dict(config_dict, "", "")
  68. self.tls_factory = FederationPolicyForHTTPS(config)
  69. self.well_known_cache: TTLCache[bytes, Optional[bytes]] = TTLCache(
  70. "test_cache", timer=self.reactor.seconds
  71. )
  72. self.had_well_known_cache: TTLCache[bytes, bool] = TTLCache(
  73. "test_cache", timer=self.reactor.seconds
  74. )
  75. self.well_known_resolver = WellKnownResolver(
  76. self.reactor,
  77. Agent(self.reactor, contextFactory=self.tls_factory),
  78. b"test-agent",
  79. well_known_cache=self.well_known_cache,
  80. had_well_known_cache=self.had_well_known_cache,
  81. )
  82. def _make_connection(
  83. self,
  84. client_factory: IProtocolFactory,
  85. ssl: bool = True,
  86. expected_sni: Optional[bytes] = None,
  87. tls_sanlist: Optional[List[bytes]] = None,
  88. ) -> HTTPChannel:
  89. """Builds a test server, and completes the outgoing client connection
  90. Args:
  91. client_factory: the the factory that the
  92. application is trying to use to make the outbound connection. We will
  93. invoke it to build the client Protocol
  94. ssl: If true, we will expect an ssl connection and wrap
  95. server_factory with a TLSMemoryBIOFactory
  96. False is set only for when proxy expect http connection.
  97. Otherwise federation requests use always https.
  98. expected_sni: the expected SNI value
  99. tls_sanlist: list of SAN entries for the TLS cert presented by the server.
  100. Returns:
  101. the server Protocol returned by server_factory
  102. """
  103. # build the test server
  104. server_factory = _get_test_protocol_factory()
  105. if ssl:
  106. server_factory = wrap_server_factory_for_tls(
  107. server_factory,
  108. self.reactor,
  109. tls_sanlist
  110. or [
  111. b"DNS:testserv",
  112. b"DNS:target-server",
  113. b"DNS:xn--bcher-kva.com",
  114. b"IP:1.2.3.4",
  115. b"IP:::1",
  116. ],
  117. )
  118. server_protocol = server_factory.buildProtocol(dummy_address)
  119. assert server_protocol is not None
  120. # now, tell the client protocol factory to build the client protocol (it will be a
  121. # _WrappingProtocol, around a TLSMemoryBIOProtocol, around an
  122. # HTTP11ClientProtocol) and wire the output of said protocol up to the server via
  123. # a FakeTransport.
  124. #
  125. # Normally this would be done by the TCP socket code in Twisted, but we are
  126. # stubbing that out here.
  127. # NB: we use a checked_cast here to workaround https://github.com/Shoobx/mypy-zope/issues/91)
  128. client_protocol = checked_cast(
  129. _WrappingProtocol, client_factory.buildProtocol(dummy_address)
  130. )
  131. client_protocol.makeConnection(
  132. FakeTransport(server_protocol, self.reactor, client_protocol)
  133. )
  134. # tell the server protocol to send its stuff back to the client, too
  135. server_protocol.makeConnection(
  136. FakeTransport(client_protocol, self.reactor, server_protocol)
  137. )
  138. if ssl:
  139. assert isinstance(server_protocol, TLSMemoryBIOProtocol)
  140. # fish the test server back out of the server-side TLS protocol.
  141. http_protocol = server_protocol.wrappedProtocol
  142. # grab a hold of the TLS connection, in case it gets torn down
  143. tls_connection = server_protocol._tlsConnection
  144. else:
  145. http_protocol = server_protocol
  146. tls_connection = None
  147. assert isinstance(http_protocol, HTTPChannel)
  148. # give the reactor a pump to get the TLS juices flowing (if needed)
  149. self.reactor.advance(0)
  150. # check the SNI
  151. if expected_sni is not None:
  152. server_name = tls_connection.get_servername()
  153. self.assertEqual(
  154. server_name,
  155. expected_sni,
  156. f"Expected SNI {expected_sni!s} but got {server_name!s}",
  157. )
  158. return http_protocol
  159. @defer.inlineCallbacks
  160. def _make_get_request(
  161. self, uri: bytes
  162. ) -> Generator["Deferred[object]", object, IResponse]:
  163. """
  164. Sends a simple GET request via the agent, and checks its logcontext management
  165. """
  166. with LoggingContext("one") as context:
  167. fetch_d: Deferred[IResponse] = self.agent.request(b"GET", uri)
  168. # Nothing happened yet
  169. self.assertNoResult(fetch_d)
  170. # should have reset logcontext to the sentinel
  171. _check_logcontext(SENTINEL_CONTEXT)
  172. fetch_res: IResponse
  173. try:
  174. fetch_res = yield fetch_d # type: ignore[misc, assignment]
  175. return fetch_res
  176. except Exception as e:
  177. logger.info("Fetch of %s failed: %s", uri.decode("ascii"), e)
  178. raise
  179. finally:
  180. _check_logcontext(context)
  181. def _handle_well_known_connection(
  182. self,
  183. client_factory: IProtocolFactory,
  184. expected_sni: bytes,
  185. content: bytes,
  186. response_headers: Optional[dict] = None,
  187. ) -> HTTPChannel:
  188. """Handle an outgoing HTTPs connection: wire it up to a server, check that the
  189. request is for a .well-known, and send the response.
  190. Args:
  191. client_factory: outgoing connection
  192. expected_sni: SNI that we expect the outgoing connection to send
  193. content: content to send back as the .well-known
  194. Returns:
  195. server impl
  196. """
  197. # make the connection for .well-known
  198. well_known_server = self._make_connection(
  199. client_factory, expected_sni=expected_sni
  200. )
  201. # check the .well-known request and send a response
  202. self.assertEqual(len(well_known_server.requests), 1)
  203. request = well_known_server.requests[0]
  204. self.assertEqual(
  205. request.requestHeaders.getRawHeaders(b"user-agent"), [b"test-agent"]
  206. )
  207. self._send_well_known_response(request, content, headers=response_headers or {})
  208. return well_known_server
  209. def _send_well_known_response(
  210. self,
  211. request: Request,
  212. content: bytes,
  213. headers: Optional[dict] = None,
  214. ) -> None:
  215. """Check that an incoming request looks like a valid .well-known request, and
  216. send back the response.
  217. """
  218. self.assertEqual(request.method, b"GET")
  219. self.assertEqual(request.path, b"/.well-known/matrix/server")
  220. self.assertEqual(request.requestHeaders.getRawHeaders(b"host"), [b"testserv"])
  221. # send back a response
  222. for k, v in (headers or {}).items():
  223. request.setHeader(k, v)
  224. request.write(content)
  225. request.finish()
  226. self.reactor.pump((0.1,))
  227. def _make_agent(self) -> MatrixFederationAgent:
  228. """
  229. If a proxy server is set, the MatrixFederationAgent must be created again
  230. because it is created too early during setUp
  231. """
  232. return MatrixFederationAgent(
  233. reactor=cast(ISynapseReactor, self.reactor),
  234. tls_client_options_factory=self.tls_factory,
  235. user_agent=b"test-agent", # Note that this is unused since _well_known_resolver is provided.
  236. ip_allowlist=IPSet(),
  237. ip_blocklist=IPSet(),
  238. _srv_resolver=self.mock_resolver,
  239. _well_known_resolver=self.well_known_resolver,
  240. )
  241. def test_get(self) -> None:
  242. """happy-path test of a GET request with an explicit port"""
  243. self._do_get()
  244. @patch.dict(
  245. os.environ,
  246. {"https_proxy": "proxy.com", "no_proxy": "testserv"},
  247. )
  248. def test_get_bypass_proxy(self) -> None:
  249. """test of a GET request with an explicit port and bypass proxy"""
  250. self._do_get()
  251. def _do_get(self) -> None:
  252. """test of a GET request with an explicit port"""
  253. self.agent = self._make_agent()
  254. self.reactor.lookups["testserv"] = "1.2.3.4"
  255. test_d = self._make_get_request(b"matrix-federation://testserv:8448/foo/bar")
  256. # Nothing happened yet
  257. self.assertNoResult(test_d)
  258. # Make sure treq is trying to connect
  259. clients = self.reactor.tcpClients
  260. self.assertEqual(len(clients), 1)
  261. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  262. self.assertEqual(host, "1.2.3.4")
  263. self.assertEqual(port, 8448)
  264. # make a test server, and wire up the client
  265. http_server = self._make_connection(client_factory, expected_sni=b"testserv")
  266. self.assertEqual(len(http_server.requests), 1)
  267. request = http_server.requests[0]
  268. self.assertEqual(request.method, b"GET")
  269. self.assertEqual(request.path, b"/foo/bar")
  270. self.assertEqual(
  271. request.requestHeaders.getRawHeaders(b"host"), [b"testserv:8448"]
  272. )
  273. self.assertEqual(
  274. request.requestHeaders.getRawHeaders(b"user-agent"), [b"test-agent"]
  275. )
  276. content = request.content.read()
  277. self.assertEqual(content, b"")
  278. # Deferred is still without a result
  279. self.assertNoResult(test_d)
  280. # send the headers
  281. request.responseHeaders.setRawHeaders(b"Content-Type", [b"application/json"])
  282. request.write("")
  283. self.reactor.pump((0.1,))
  284. response = self.successResultOf(test_d)
  285. # that should give us a Response object
  286. self.assertEqual(response.code, 200)
  287. # Send the body
  288. request.write(b'{ "a": 1 }')
  289. request.finish()
  290. self.reactor.pump((0.1,))
  291. # check it can be read
  292. json = self.successResultOf(treq.json_content(response))
  293. self.assertEqual(json, {"a": 1})
  294. @patch.dict(
  295. os.environ, {"https_proxy": "http://proxy.com", "no_proxy": "unused.com"}
  296. )
  297. def test_get_via_http_proxy(self) -> None:
  298. """test for federation request through a http proxy"""
  299. self._do_get_via_proxy(expect_proxy_ssl=False, expected_auth_credentials=None)
  300. @patch.dict(
  301. os.environ,
  302. {"https_proxy": "http://user:pass@proxy.com", "no_proxy": "unused.com"},
  303. )
  304. def test_get_via_http_proxy_with_auth(self) -> None:
  305. """test for federation request through a http proxy with authentication"""
  306. self._do_get_via_proxy(
  307. expect_proxy_ssl=False, expected_auth_credentials=b"user:pass"
  308. )
  309. @patch.dict(
  310. os.environ, {"https_proxy": "https://proxy.com", "no_proxy": "unused.com"}
  311. )
  312. def test_get_via_https_proxy(self) -> None:
  313. """test for federation request through a https proxy"""
  314. self._do_get_via_proxy(expect_proxy_ssl=True, expected_auth_credentials=None)
  315. @patch.dict(
  316. os.environ,
  317. {"https_proxy": "https://user:pass@proxy.com", "no_proxy": "unused.com"},
  318. )
  319. def test_get_via_https_proxy_with_auth(self) -> None:
  320. """test for federation request through a https proxy with authentication"""
  321. self._do_get_via_proxy(
  322. expect_proxy_ssl=True, expected_auth_credentials=b"user:pass"
  323. )
  324. def _do_get_via_proxy(
  325. self,
  326. expect_proxy_ssl: bool = False,
  327. expected_auth_credentials: Optional[bytes] = None,
  328. ) -> None:
  329. """Send a https federation request via an agent and check that it is correctly
  330. received at the proxy and client. The proxy can use either http or https.
  331. Args:
  332. expect_proxy_ssl: True if we expect the request to connect to the proxy via https.
  333. expected_auth_credentials: credentials we expect to be presented to authenticate at the proxy
  334. """
  335. self.agent = self._make_agent()
  336. self.reactor.lookups["testserv"] = "1.2.3.4"
  337. self.reactor.lookups["proxy.com"] = "9.9.9.9"
  338. test_d = self._make_get_request(b"matrix-federation://testserv:8448/foo/bar")
  339. # Nothing happened yet
  340. self.assertNoResult(test_d)
  341. # Make sure treq is trying to connect
  342. clients = self.reactor.tcpClients
  343. self.assertEqual(len(clients), 1)
  344. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  345. # make sure we are connecting to the proxy
  346. self.assertEqual(host, "9.9.9.9")
  347. self.assertEqual(port, 1080)
  348. # make a test server to act as the proxy, and wire up the client
  349. proxy_server = self._make_connection(
  350. client_factory,
  351. ssl=expect_proxy_ssl,
  352. tls_sanlist=[b"DNS:proxy.com"] if expect_proxy_ssl else None,
  353. expected_sni=b"proxy.com" if expect_proxy_ssl else None,
  354. )
  355. assert isinstance(proxy_server, HTTPChannel)
  356. # now there should be a pending CONNECT request
  357. self.assertEqual(len(proxy_server.requests), 1)
  358. request = proxy_server.requests[0]
  359. self.assertEqual(request.method, b"CONNECT")
  360. self.assertEqual(request.path, b"testserv:8448")
  361. # Check whether auth credentials have been supplied to the proxy
  362. proxy_auth_header_values = request.requestHeaders.getRawHeaders(
  363. b"Proxy-Authorization"
  364. )
  365. if expected_auth_credentials is not None:
  366. # Compute the correct header value for Proxy-Authorization
  367. encoded_credentials = base64.b64encode(expected_auth_credentials)
  368. expected_header_value = b"Basic " + encoded_credentials
  369. # Validate the header's value
  370. self.assertIn(expected_header_value, proxy_auth_header_values)
  371. else:
  372. # Check that the Proxy-Authorization header has not been supplied to the proxy
  373. self.assertIsNone(proxy_auth_header_values)
  374. # tell the proxy server not to close the connection
  375. proxy_server.persistent = True
  376. request.finish()
  377. # now we make another test server to act as the upstream HTTP server.
  378. server_ssl_protocol = wrap_server_factory_for_tls(
  379. _get_test_protocol_factory(),
  380. self.reactor,
  381. sanlist=[
  382. b"DNS:testserv",
  383. b"DNS:target-server",
  384. b"DNS:xn--bcher-kva.com",
  385. b"IP:1.2.3.4",
  386. b"IP:::1",
  387. ],
  388. ).buildProtocol(dummy_address)
  389. # Tell the HTTP server to send outgoing traffic back via the proxy's transport.
  390. proxy_server_transport = proxy_server.transport
  391. assert proxy_server_transport is not None
  392. server_ssl_protocol.makeConnection(proxy_server_transport)
  393. # ... and replace the protocol on the proxy's transport with the
  394. # TLSMemoryBIOProtocol for the test server, so that incoming traffic
  395. # to the proxy gets sent over to the HTTP(s) server.
  396. # See also comment at `_do_https_request_via_proxy`
  397. # in ../test_proxyagent.py for more details
  398. if expect_proxy_ssl:
  399. assert isinstance(proxy_server_transport, TLSMemoryBIOProtocol)
  400. proxy_server_transport.wrappedProtocol = server_ssl_protocol
  401. else:
  402. assert isinstance(proxy_server_transport, FakeTransport)
  403. client_protocol = proxy_server_transport.other
  404. assert isinstance(client_protocol, Protocol)
  405. c2s_transport = checked_cast(FakeTransport, client_protocol.transport)
  406. c2s_transport.other = server_ssl_protocol
  407. self.reactor.advance(0)
  408. server_name = server_ssl_protocol._tlsConnection.get_servername()
  409. expected_sni = b"testserv"
  410. self.assertEqual(
  411. server_name,
  412. expected_sni,
  413. f"Expected SNI {expected_sni!s} but got {server_name!s}",
  414. )
  415. # now there should be a pending request
  416. http_server = server_ssl_protocol.wrappedProtocol
  417. assert isinstance(http_server, HTTPChannel)
  418. self.assertEqual(len(http_server.requests), 1)
  419. request = http_server.requests[0]
  420. self.assertEqual(request.method, b"GET")
  421. self.assertEqual(request.path, b"/foo/bar")
  422. self.assertEqual(
  423. request.requestHeaders.getRawHeaders(b"host"), [b"testserv:8448"]
  424. )
  425. self.assertEqual(
  426. request.requestHeaders.getRawHeaders(b"user-agent"), [b"test-agent"]
  427. )
  428. # Check that the destination server DID NOT receive proxy credentials
  429. self.assertIsNone(request.requestHeaders.getRawHeaders(b"Proxy-Authorization"))
  430. content = request.content.read()
  431. self.assertEqual(content, b"")
  432. # Deferred is still without a result
  433. self.assertNoResult(test_d)
  434. # send the headers
  435. request.responseHeaders.setRawHeaders(b"Content-Type", [b"application/json"])
  436. request.write("")
  437. self.reactor.pump((0.1,))
  438. response = self.successResultOf(test_d)
  439. # that should give us a Response object
  440. self.assertEqual(response.code, 200)
  441. # Send the body
  442. request.write(b'{ "a": 1 }')
  443. request.finish()
  444. self.reactor.pump((0.1,))
  445. # check it can be read
  446. json = self.successResultOf(treq.json_content(response))
  447. self.assertEqual(json, {"a": 1})
  448. def test_get_ip_address(self) -> None:
  449. """
  450. Test the behaviour when the server name contains an explicit IP (with no port)
  451. """
  452. self.agent = self._make_agent()
  453. # there will be a getaddrinfo on the IP
  454. self.reactor.lookups["1.2.3.4"] = "1.2.3.4"
  455. test_d = self._make_get_request(b"matrix-federation://1.2.3.4/foo/bar")
  456. # Nothing happened yet
  457. self.assertNoResult(test_d)
  458. # Make sure treq is trying to connect
  459. clients = self.reactor.tcpClients
  460. self.assertEqual(len(clients), 1)
  461. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  462. self.assertEqual(host, "1.2.3.4")
  463. self.assertEqual(port, 8448)
  464. # make a test server, and wire up the client
  465. http_server = self._make_connection(client_factory, expected_sni=None)
  466. self.assertEqual(len(http_server.requests), 1)
  467. request = http_server.requests[0]
  468. self.assertEqual(request.method, b"GET")
  469. self.assertEqual(request.path, b"/foo/bar")
  470. self.assertEqual(request.requestHeaders.getRawHeaders(b"host"), [b"1.2.3.4"])
  471. # finish the request
  472. request.finish()
  473. self.reactor.pump((0.1,))
  474. self.successResultOf(test_d)
  475. def test_get_ipv6_address(self) -> None:
  476. """
  477. Test the behaviour when the server name contains an explicit IPv6 address
  478. (with no port)
  479. """
  480. self.agent = self._make_agent()
  481. # there will be a getaddrinfo on the IP
  482. self.reactor.lookups["::1"] = "::1"
  483. test_d = self._make_get_request(b"matrix-federation://[::1]/foo/bar")
  484. # Nothing happened yet
  485. self.assertNoResult(test_d)
  486. # Make sure treq is trying to connect
  487. clients = self.reactor.tcpClients
  488. self.assertEqual(len(clients), 1)
  489. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  490. self.assertEqual(host, "::1")
  491. self.assertEqual(port, 8448)
  492. # make a test server, and wire up the client
  493. http_server = self._make_connection(client_factory, expected_sni=None)
  494. self.assertEqual(len(http_server.requests), 1)
  495. request = http_server.requests[0]
  496. self.assertEqual(request.method, b"GET")
  497. self.assertEqual(request.path, b"/foo/bar")
  498. self.assertEqual(request.requestHeaders.getRawHeaders(b"host"), [b"[::1]"])
  499. # finish the request
  500. request.finish()
  501. self.reactor.pump((0.1,))
  502. self.successResultOf(test_d)
  503. def test_get_ipv6_address_with_port(self) -> None:
  504. """
  505. Test the behaviour when the server name contains an explicit IPv6 address
  506. (with explicit port)
  507. """
  508. self.agent = self._make_agent()
  509. # there will be a getaddrinfo on the IP
  510. self.reactor.lookups["::1"] = "::1"
  511. test_d = self._make_get_request(b"matrix-federation://[::1]:80/foo/bar")
  512. # Nothing happened yet
  513. self.assertNoResult(test_d)
  514. # Make sure treq is trying to connect
  515. clients = self.reactor.tcpClients
  516. self.assertEqual(len(clients), 1)
  517. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  518. self.assertEqual(host, "::1")
  519. self.assertEqual(port, 80)
  520. # make a test server, and wire up the client
  521. http_server = self._make_connection(client_factory, expected_sni=None)
  522. self.assertEqual(len(http_server.requests), 1)
  523. request = http_server.requests[0]
  524. self.assertEqual(request.method, b"GET")
  525. self.assertEqual(request.path, b"/foo/bar")
  526. self.assertEqual(request.requestHeaders.getRawHeaders(b"host"), [b"[::1]:80"])
  527. # finish the request
  528. request.finish()
  529. self.reactor.pump((0.1,))
  530. self.successResultOf(test_d)
  531. def test_get_hostname_bad_cert(self) -> None:
  532. """
  533. Test the behaviour when the certificate on the server doesn't match the hostname
  534. """
  535. self.agent = self._make_agent()
  536. self.mock_resolver.resolve_service.return_value = []
  537. self.reactor.lookups["testserv1"] = "1.2.3.4"
  538. test_d = self._make_get_request(b"matrix-federation://testserv1/foo/bar")
  539. # Nothing happened yet
  540. self.assertNoResult(test_d)
  541. # No SRV record lookup yet
  542. self.mock_resolver.resolve_service.assert_not_called()
  543. # there should be an attempt to connect on port 443 for the .well-known
  544. clients = self.reactor.tcpClients
  545. self.assertEqual(len(clients), 1)
  546. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  547. self.assertEqual(host, "1.2.3.4")
  548. self.assertEqual(port, 443)
  549. # fonx the connection
  550. client_factory.clientConnectionFailed(None, Exception("nope"))
  551. # attemptdelay on the hostnameendpoint is 0.3, so takes that long before the
  552. # .well-known request fails.
  553. self.reactor.pump((0.4,))
  554. # now there should be two SRV lookups
  555. self.mock_resolver.resolve_service.assert_has_calls(
  556. [call(b"_matrix-fed._tcp.testserv1"), call(b"_matrix._tcp.testserv1")]
  557. )
  558. # we should fall back to a direct connection
  559. self.assertEqual(len(clients), 2)
  560. (host, port, client_factory, _timeout, _bindAddress) = clients[1]
  561. self.assertEqual(host, "1.2.3.4")
  562. self.assertEqual(port, 8448)
  563. # make a test server, and wire up the client
  564. http_server = self._make_connection(client_factory, expected_sni=b"testserv1")
  565. # there should be no requests
  566. self.assertEqual(len(http_server.requests), 0)
  567. # ... and the request should have failed
  568. e = self.failureResultOf(test_d, ResponseNeverReceived)
  569. failure_reason = e.value.reasons[0]
  570. self.assertIsInstance(failure_reason.value, VerificationError)
  571. def test_get_ip_address_bad_cert(self) -> None:
  572. """
  573. Test the behaviour when the server name contains an explicit IP, but
  574. the server cert doesn't cover it
  575. """
  576. self.agent = self._make_agent()
  577. # there will be a getaddrinfo on the IP
  578. self.reactor.lookups["1.2.3.5"] = "1.2.3.5"
  579. test_d = self._make_get_request(b"matrix-federation://1.2.3.5/foo/bar")
  580. # Nothing happened yet
  581. self.assertNoResult(test_d)
  582. # Make sure treq is trying to connect
  583. clients = self.reactor.tcpClients
  584. self.assertEqual(len(clients), 1)
  585. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  586. self.assertEqual(host, "1.2.3.5")
  587. self.assertEqual(port, 8448)
  588. # make a test server, and wire up the client
  589. http_server = self._make_connection(client_factory, expected_sni=None)
  590. # there should be no requests
  591. self.assertEqual(len(http_server.requests), 0)
  592. # ... and the request should have failed
  593. e = self.failureResultOf(test_d, ResponseNeverReceived)
  594. failure_reason = e.value.reasons[0]
  595. self.assertIsInstance(failure_reason.value, VerificationError)
  596. def test_get_no_srv_no_well_known(self) -> None:
  597. """
  598. Test the behaviour when the server name has no port, no SRV, and no well-known
  599. """
  600. self.agent = self._make_agent()
  601. self.mock_resolver.resolve_service.return_value = []
  602. self.reactor.lookups["testserv"] = "1.2.3.4"
  603. test_d = self._make_get_request(b"matrix-federation://testserv/foo/bar")
  604. # Nothing happened yet
  605. self.assertNoResult(test_d)
  606. # No SRV record lookup yet
  607. self.mock_resolver.resolve_service.assert_not_called()
  608. # there should be an attempt to connect on port 443 for the .well-known
  609. clients = self.reactor.tcpClients
  610. self.assertEqual(len(clients), 1)
  611. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  612. self.assertEqual(host, "1.2.3.4")
  613. self.assertEqual(port, 443)
  614. # fonx the connection
  615. client_factory.clientConnectionFailed(None, Exception("nope"))
  616. # attemptdelay on the hostnameendpoint is 0.3, so takes that long before the
  617. # .well-known request fails.
  618. self.reactor.pump((0.4,))
  619. # now there should be two SRV lookups
  620. self.mock_resolver.resolve_service.assert_has_calls(
  621. [call(b"_matrix-fed._tcp.testserv"), call(b"_matrix._tcp.testserv")]
  622. )
  623. # we should fall back to a direct connection
  624. self.assertEqual(len(clients), 2)
  625. (host, port, client_factory, _timeout, _bindAddress) = clients[1]
  626. self.assertEqual(host, "1.2.3.4")
  627. self.assertEqual(port, 8448)
  628. # make a test server, and wire up the client
  629. http_server = self._make_connection(client_factory, expected_sni=b"testserv")
  630. self.assertEqual(len(http_server.requests), 1)
  631. request = http_server.requests[0]
  632. self.assertEqual(request.method, b"GET")
  633. self.assertEqual(request.path, b"/foo/bar")
  634. self.assertEqual(request.requestHeaders.getRawHeaders(b"host"), [b"testserv"])
  635. # finish the request
  636. request.finish()
  637. self.reactor.pump((0.1,))
  638. self.successResultOf(test_d)
  639. def test_get_well_known(self) -> None:
  640. """Test the behaviour when the .well-known delegates elsewhere"""
  641. self.agent = self._make_agent()
  642. self.mock_resolver.resolve_service.return_value = []
  643. self.reactor.lookups["testserv"] = "1.2.3.4"
  644. self.reactor.lookups["target-server"] = "1::f"
  645. test_d = self._make_get_request(b"matrix-federation://testserv/foo/bar")
  646. # Nothing happened yet
  647. self.assertNoResult(test_d)
  648. # there should be an attempt to connect on port 443 for the .well-known
  649. clients = self.reactor.tcpClients
  650. self.assertEqual(len(clients), 1)
  651. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  652. self.assertEqual(host, "1.2.3.4")
  653. self.assertEqual(port, 443)
  654. self._handle_well_known_connection(
  655. client_factory,
  656. expected_sni=b"testserv",
  657. content=b'{ "m.server": "target-server" }',
  658. )
  659. # there should be two SRV lookups
  660. self.mock_resolver.resolve_service.assert_has_calls(
  661. [
  662. call(b"_matrix-fed._tcp.target-server"),
  663. call(b"_matrix._tcp.target-server"),
  664. ]
  665. )
  666. # now we should get a connection to the target server
  667. self.assertEqual(len(clients), 2)
  668. (host, port, client_factory, _timeout, _bindAddress) = clients[1]
  669. self.assertEqual(host, "1::f")
  670. self.assertEqual(port, 8448)
  671. # make a test server, and wire up the client
  672. http_server = self._make_connection(
  673. client_factory, expected_sni=b"target-server"
  674. )
  675. self.assertEqual(len(http_server.requests), 1)
  676. request = http_server.requests[0]
  677. self.assertEqual(request.method, b"GET")
  678. self.assertEqual(request.path, b"/foo/bar")
  679. self.assertEqual(
  680. request.requestHeaders.getRawHeaders(b"host"), [b"target-server"]
  681. )
  682. # finish the request
  683. request.finish()
  684. self.reactor.pump((0.1,))
  685. self.successResultOf(test_d)
  686. self.assertEqual(self.well_known_cache[b"testserv"], b"target-server")
  687. # check the cache expires
  688. self.reactor.pump((48 * 3600,))
  689. self.well_known_cache.expire()
  690. self.assertNotIn(b"testserv", self.well_known_cache)
  691. def test_get_well_known_redirect(self) -> None:
  692. """Test the behaviour when the server name has no port and no SRV record, but
  693. the .well-known has a 300 redirect
  694. """
  695. self.agent = self._make_agent()
  696. self.mock_resolver.resolve_service.return_value = []
  697. self.reactor.lookups["testserv"] = "1.2.3.4"
  698. self.reactor.lookups["target-server"] = "1::f"
  699. test_d = self._make_get_request(b"matrix-federation://testserv/foo/bar")
  700. # Nothing happened yet
  701. self.assertNoResult(test_d)
  702. # there should be an attempt to connect on port 443 for the .well-known
  703. clients = self.reactor.tcpClients
  704. self.assertEqual(len(clients), 1)
  705. (host, port, client_factory, _timeout, _bindAddress) = clients.pop()
  706. self.assertEqual(host, "1.2.3.4")
  707. self.assertEqual(port, 443)
  708. redirect_server = self._make_connection(
  709. client_factory, expected_sni=b"testserv"
  710. )
  711. # send a 302 redirect
  712. self.assertEqual(len(redirect_server.requests), 1)
  713. request = redirect_server.requests[0]
  714. request.redirect(b"https://testserv/even_better_known")
  715. request.finish()
  716. self.reactor.pump((0.1,))
  717. # now there should be another connection
  718. clients = self.reactor.tcpClients
  719. self.assertEqual(len(clients), 1)
  720. (host, port, client_factory, _timeout, _bindAddress) = clients.pop()
  721. self.assertEqual(host, "1.2.3.4")
  722. self.assertEqual(port, 443)
  723. well_known_server = self._make_connection(
  724. client_factory, expected_sni=b"testserv"
  725. )
  726. self.assertEqual(len(well_known_server.requests), 1, "No request after 302")
  727. request = well_known_server.requests[0]
  728. self.assertEqual(request.method, b"GET")
  729. self.assertEqual(request.path, b"/even_better_known")
  730. request.write(b'{ "m.server": "target-server" }')
  731. request.finish()
  732. self.reactor.pump((0.1,))
  733. # there should be two SRV lookups
  734. self.mock_resolver.resolve_service.assert_has_calls(
  735. [
  736. call(b"_matrix-fed._tcp.target-server"),
  737. call(b"_matrix._tcp.target-server"),
  738. ]
  739. )
  740. # now we should get a connection to the target server
  741. self.assertEqual(len(clients), 1)
  742. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  743. self.assertEqual(host, "1::f")
  744. self.assertEqual(port, 8448)
  745. # make a test server, and wire up the client
  746. http_server = self._make_connection(
  747. client_factory, expected_sni=b"target-server"
  748. )
  749. self.assertEqual(len(http_server.requests), 1)
  750. request = http_server.requests[0]
  751. self.assertEqual(request.method, b"GET")
  752. self.assertEqual(request.path, b"/foo/bar")
  753. self.assertEqual(
  754. request.requestHeaders.getRawHeaders(b"host"), [b"target-server"]
  755. )
  756. # finish the request
  757. request.finish()
  758. self.reactor.pump((0.1,))
  759. self.successResultOf(test_d)
  760. self.assertEqual(self.well_known_cache[b"testserv"], b"target-server")
  761. # check the cache expires
  762. self.reactor.pump((48 * 3600,))
  763. self.well_known_cache.expire()
  764. self.assertNotIn(b"testserv", self.well_known_cache)
  765. def test_get_invalid_well_known(self) -> None:
  766. """
  767. Test the behaviour when the server name has an *invalid* well-known (and no SRV)
  768. """
  769. self.agent = self._make_agent()
  770. self.mock_resolver.resolve_service.return_value = []
  771. self.reactor.lookups["testserv"] = "1.2.3.4"
  772. test_d = self._make_get_request(b"matrix-federation://testserv/foo/bar")
  773. # Nothing happened yet
  774. self.assertNoResult(test_d)
  775. # No SRV record lookup yet
  776. self.mock_resolver.resolve_service.assert_not_called()
  777. # there should be an attempt to connect on port 443 for the .well-known
  778. clients = self.reactor.tcpClients
  779. self.assertEqual(len(clients), 1)
  780. (host, port, client_factory, _timeout, _bindAddress) = clients.pop()
  781. self.assertEqual(host, "1.2.3.4")
  782. self.assertEqual(port, 443)
  783. self._handle_well_known_connection(
  784. client_factory, expected_sni=b"testserv", content=b"NOT JSON"
  785. )
  786. # now there should be two SRV lookups
  787. self.mock_resolver.resolve_service.assert_has_calls(
  788. [call(b"_matrix-fed._tcp.testserv"), call(b"_matrix._tcp.testserv")]
  789. )
  790. # we should fall back to a direct connection
  791. self.assertEqual(len(clients), 1)
  792. (host, port, client_factory, _timeout, _bindAddress) = clients.pop()
  793. self.assertEqual(host, "1.2.3.4")
  794. self.assertEqual(port, 8448)
  795. # make a test server, and wire up the client
  796. http_server = self._make_connection(client_factory, expected_sni=b"testserv")
  797. self.assertEqual(len(http_server.requests), 1)
  798. request = http_server.requests[0]
  799. self.assertEqual(request.method, b"GET")
  800. self.assertEqual(request.path, b"/foo/bar")
  801. self.assertEqual(request.requestHeaders.getRawHeaders(b"host"), [b"testserv"])
  802. # finish the request
  803. request.finish()
  804. self.reactor.pump((0.1,))
  805. self.successResultOf(test_d)
  806. def test_get_well_known_unsigned_cert(self) -> None:
  807. """Test the behaviour when the .well-known server presents a cert
  808. not signed by a CA
  809. """
  810. # we use the same test server as the other tests, but use an agent with
  811. # the config left to the default, which will not trust it (since the
  812. # presented cert is signed by a test CA)
  813. self.mock_resolver.resolve_service.return_value = []
  814. self.reactor.lookups["testserv"] = "1.2.3.4"
  815. config = default_config("test", parse=True)
  816. # Build a new agent and WellKnownResolver with a different tls factory
  817. tls_factory = FederationPolicyForHTTPS(config)
  818. agent = MatrixFederationAgent(
  819. reactor=self.reactor,
  820. tls_client_options_factory=tls_factory,
  821. user_agent=b"test-agent", # This is unused since _well_known_resolver is passed below.
  822. ip_allowlist=IPSet(),
  823. ip_blocklist=IPSet(),
  824. _srv_resolver=self.mock_resolver,
  825. _well_known_resolver=WellKnownResolver(
  826. cast(ISynapseReactor, self.reactor),
  827. Agent(self.reactor, contextFactory=tls_factory),
  828. b"test-agent",
  829. well_known_cache=self.well_known_cache,
  830. had_well_known_cache=self.had_well_known_cache,
  831. ),
  832. )
  833. test_d = agent.request(b"GET", b"matrix-federation://testserv/foo/bar")
  834. # Nothing happened yet
  835. self.assertNoResult(test_d)
  836. # there should be an attempt to connect on port 443 for the .well-known
  837. clients = self.reactor.tcpClients
  838. self.assertEqual(len(clients), 1)
  839. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  840. self.assertEqual(host, "1.2.3.4")
  841. self.assertEqual(port, 443)
  842. http_proto = self._make_connection(client_factory, expected_sni=b"testserv")
  843. # there should be no requests
  844. self.assertEqual(len(http_proto.requests), 0)
  845. # and there should be two SRV lookups instead
  846. self.mock_resolver.resolve_service.assert_has_calls(
  847. [call(b"_matrix-fed._tcp.testserv"), call(b"_matrix._tcp.testserv")]
  848. )
  849. def test_get_hostname_srv(self) -> None:
  850. """
  851. Test the behaviour when there is a single SRV record for _matrix-fed.
  852. """
  853. self.agent = self._make_agent()
  854. self.mock_resolver.resolve_service.return_value = [
  855. Server(host=b"srvtarget", port=8443)
  856. ]
  857. self.reactor.lookups["srvtarget"] = "1.2.3.4"
  858. test_d = self._make_get_request(b"matrix-federation://testserv/foo/bar")
  859. # Nothing happened yet
  860. self.assertNoResult(test_d)
  861. # the request for a .well-known will have failed with a DNS lookup error.
  862. self.mock_resolver.resolve_service.assert_called_once_with(
  863. b"_matrix-fed._tcp.testserv"
  864. )
  865. # Make sure treq is trying to connect
  866. clients = self.reactor.tcpClients
  867. self.assertEqual(len(clients), 1)
  868. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  869. self.assertEqual(host, "1.2.3.4")
  870. self.assertEqual(port, 8443)
  871. # make a test server, and wire up the client
  872. http_server = self._make_connection(client_factory, expected_sni=b"testserv")
  873. self.assertEqual(len(http_server.requests), 1)
  874. request = http_server.requests[0]
  875. self.assertEqual(request.method, b"GET")
  876. self.assertEqual(request.path, b"/foo/bar")
  877. self.assertEqual(request.requestHeaders.getRawHeaders(b"host"), [b"testserv"])
  878. # finish the request
  879. request.finish()
  880. self.reactor.pump((0.1,))
  881. self.successResultOf(test_d)
  882. def test_get_hostname_srv_legacy(self) -> None:
  883. """
  884. Test the behaviour when there is a single SRV record for _matrix.
  885. """
  886. self.agent = self._make_agent()
  887. # Return no entries for the _matrix-fed lookup, and a response for _matrix.
  888. self.mock_resolver.resolve_service.side_effect = [
  889. [],
  890. [Server(host=b"srvtarget", port=8443)],
  891. ]
  892. self.reactor.lookups["srvtarget"] = "1.2.3.4"
  893. test_d = self._make_get_request(b"matrix-federation://testserv/foo/bar")
  894. # Nothing happened yet
  895. self.assertNoResult(test_d)
  896. # the request for a .well-known will have failed with a DNS lookup error.
  897. self.mock_resolver.resolve_service.assert_has_calls(
  898. [call(b"_matrix-fed._tcp.testserv"), call(b"_matrix._tcp.testserv")]
  899. )
  900. # Make sure treq is trying to connect
  901. clients = self.reactor.tcpClients
  902. self.assertEqual(len(clients), 1)
  903. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  904. self.assertEqual(host, "1.2.3.4")
  905. self.assertEqual(port, 8443)
  906. # make a test server, and wire up the client
  907. http_server = self._make_connection(client_factory, expected_sni=b"testserv")
  908. self.assertEqual(len(http_server.requests), 1)
  909. request = http_server.requests[0]
  910. self.assertEqual(request.method, b"GET")
  911. self.assertEqual(request.path, b"/foo/bar")
  912. self.assertEqual(request.requestHeaders.getRawHeaders(b"host"), [b"testserv"])
  913. # finish the request
  914. request.finish()
  915. self.reactor.pump((0.1,))
  916. self.successResultOf(test_d)
  917. def test_get_well_known_srv(self) -> None:
  918. """Test the behaviour when the .well-known redirects to a place where there
  919. is a _matrix-fed SRV record.
  920. """
  921. self.agent = self._make_agent()
  922. self.reactor.lookups["testserv"] = "1.2.3.4"
  923. self.reactor.lookups["srvtarget"] = "5.6.7.8"
  924. test_d = self._make_get_request(b"matrix-federation://testserv/foo/bar")
  925. # Nothing happened yet
  926. self.assertNoResult(test_d)
  927. # there should be an attempt to connect on port 443 for the .well-known
  928. clients = self.reactor.tcpClients
  929. self.assertEqual(len(clients), 1)
  930. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  931. self.assertEqual(host, "1.2.3.4")
  932. self.assertEqual(port, 443)
  933. self.mock_resolver.resolve_service.return_value = [
  934. Server(host=b"srvtarget", port=8443)
  935. ]
  936. self._handle_well_known_connection(
  937. client_factory,
  938. expected_sni=b"testserv",
  939. content=b'{ "m.server": "target-server" }',
  940. )
  941. # there should be a SRV lookup
  942. self.mock_resolver.resolve_service.assert_called_once_with(
  943. b"_matrix-fed._tcp.target-server"
  944. )
  945. # now we should get a connection to the target of the SRV record
  946. self.assertEqual(len(clients), 2)
  947. (host, port, client_factory, _timeout, _bindAddress) = clients[1]
  948. self.assertEqual(host, "5.6.7.8")
  949. self.assertEqual(port, 8443)
  950. # make a test server, and wire up the client
  951. http_server = self._make_connection(
  952. client_factory, expected_sni=b"target-server"
  953. )
  954. self.assertEqual(len(http_server.requests), 1)
  955. request = http_server.requests[0]
  956. self.assertEqual(request.method, b"GET")
  957. self.assertEqual(request.path, b"/foo/bar")
  958. self.assertEqual(
  959. request.requestHeaders.getRawHeaders(b"host"), [b"target-server"]
  960. )
  961. # finish the request
  962. request.finish()
  963. self.reactor.pump((0.1,))
  964. self.successResultOf(test_d)
  965. def test_get_well_known_srv_legacy(self) -> None:
  966. """Test the behaviour when the .well-known redirects to a place where there
  967. is a _matrix SRV record.
  968. """
  969. self.agent = self._make_agent()
  970. self.reactor.lookups["testserv"] = "1.2.3.4"
  971. self.reactor.lookups["srvtarget"] = "5.6.7.8"
  972. test_d = self._make_get_request(b"matrix-federation://testserv/foo/bar")
  973. # Nothing happened yet
  974. self.assertNoResult(test_d)
  975. # there should be an attempt to connect on port 443 for the .well-known
  976. clients = self.reactor.tcpClients
  977. self.assertEqual(len(clients), 1)
  978. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  979. self.assertEqual(host, "1.2.3.4")
  980. self.assertEqual(port, 443)
  981. # Return no entries for the _matrix-fed lookup, and a response for _matrix.
  982. self.mock_resolver.resolve_service.side_effect = [
  983. [],
  984. [Server(host=b"srvtarget", port=8443)],
  985. ]
  986. self._handle_well_known_connection(
  987. client_factory,
  988. expected_sni=b"testserv",
  989. content=b'{ "m.server": "target-server" }',
  990. )
  991. # there should be two SRV lookups
  992. self.mock_resolver.resolve_service.assert_has_calls(
  993. [
  994. call(b"_matrix-fed._tcp.target-server"),
  995. call(b"_matrix._tcp.target-server"),
  996. ]
  997. )
  998. # now we should get a connection to the target of the SRV record
  999. self.assertEqual(len(clients), 2)
  1000. (host, port, client_factory, _timeout, _bindAddress) = clients[1]
  1001. self.assertEqual(host, "5.6.7.8")
  1002. self.assertEqual(port, 8443)
  1003. # make a test server, and wire up the client
  1004. http_server = self._make_connection(
  1005. client_factory, expected_sni=b"target-server"
  1006. )
  1007. self.assertEqual(len(http_server.requests), 1)
  1008. request = http_server.requests[0]
  1009. self.assertEqual(request.method, b"GET")
  1010. self.assertEqual(request.path, b"/foo/bar")
  1011. self.assertEqual(
  1012. request.requestHeaders.getRawHeaders(b"host"), [b"target-server"]
  1013. )
  1014. # finish the request
  1015. request.finish()
  1016. self.reactor.pump((0.1,))
  1017. self.successResultOf(test_d)
  1018. def test_idna_servername(self) -> None:
  1019. """test the behaviour when the server name has idna chars in"""
  1020. self.agent = self._make_agent()
  1021. self.mock_resolver.resolve_service.return_value = []
  1022. # the resolver is always called with the IDNA hostname as a native string.
  1023. self.reactor.lookups["xn--bcher-kva.com"] = "1.2.3.4"
  1024. # this is idna for bücher.com
  1025. test_d = self._make_get_request(
  1026. b"matrix-federation://xn--bcher-kva.com/foo/bar"
  1027. )
  1028. # Nothing happened yet
  1029. self.assertNoResult(test_d)
  1030. # No SRV record lookup yet
  1031. self.mock_resolver.resolve_service.assert_not_called()
  1032. # there should be an attempt to connect on port 443 for the .well-known
  1033. clients = self.reactor.tcpClients
  1034. self.assertEqual(len(clients), 1)
  1035. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  1036. self.assertEqual(host, "1.2.3.4")
  1037. self.assertEqual(port, 443)
  1038. # fonx the connection
  1039. client_factory.clientConnectionFailed(None, Exception("nope"))
  1040. # attemptdelay on the hostnameendpoint is 0.3, so takes that long before the
  1041. # .well-known request fails.
  1042. self.reactor.pump((0.4,))
  1043. # now there should have been a SRV lookup
  1044. self.mock_resolver.resolve_service.assert_has_calls(
  1045. [
  1046. call(b"_matrix-fed._tcp.xn--bcher-kva.com"),
  1047. call(b"_matrix._tcp.xn--bcher-kva.com"),
  1048. ]
  1049. )
  1050. # We should fall back to port 8448
  1051. clients = self.reactor.tcpClients
  1052. self.assertEqual(len(clients), 2)
  1053. (host, port, client_factory, _timeout, _bindAddress) = clients[1]
  1054. self.assertEqual(host, "1.2.3.4")
  1055. self.assertEqual(port, 8448)
  1056. # make a test server, and wire up the client
  1057. http_server = self._make_connection(
  1058. client_factory, expected_sni=b"xn--bcher-kva.com"
  1059. )
  1060. self.assertEqual(len(http_server.requests), 1)
  1061. request = http_server.requests[0]
  1062. self.assertEqual(request.method, b"GET")
  1063. self.assertEqual(request.path, b"/foo/bar")
  1064. self.assertEqual(
  1065. request.requestHeaders.getRawHeaders(b"host"), [b"xn--bcher-kva.com"]
  1066. )
  1067. # finish the request
  1068. request.finish()
  1069. self.reactor.pump((0.1,))
  1070. self.successResultOf(test_d)
  1071. def test_idna_srv_target(self) -> None:
  1072. """test the behaviour when the target of a _matrix-fed SRV record has idna chars"""
  1073. self.agent = self._make_agent()
  1074. self.mock_resolver.resolve_service.return_value = [
  1075. Server(host=b"xn--trget-3qa.com", port=8443)
  1076. ] # târget.com
  1077. self.reactor.lookups["xn--trget-3qa.com"] = "1.2.3.4"
  1078. test_d = self._make_get_request(
  1079. b"matrix-federation://xn--bcher-kva.com/foo/bar"
  1080. )
  1081. # Nothing happened yet
  1082. self.assertNoResult(test_d)
  1083. self.mock_resolver.resolve_service.assert_called_once_with(
  1084. b"_matrix-fed._tcp.xn--bcher-kva.com"
  1085. )
  1086. # Make sure treq is trying to connect
  1087. clients = self.reactor.tcpClients
  1088. self.assertEqual(len(clients), 1)
  1089. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  1090. self.assertEqual(host, "1.2.3.4")
  1091. self.assertEqual(port, 8443)
  1092. # make a test server, and wire up the client
  1093. http_server = self._make_connection(
  1094. client_factory, expected_sni=b"xn--bcher-kva.com"
  1095. )
  1096. self.assertEqual(len(http_server.requests), 1)
  1097. request = http_server.requests[0]
  1098. self.assertEqual(request.method, b"GET")
  1099. self.assertEqual(request.path, b"/foo/bar")
  1100. self.assertEqual(
  1101. request.requestHeaders.getRawHeaders(b"host"), [b"xn--bcher-kva.com"]
  1102. )
  1103. # finish the request
  1104. request.finish()
  1105. self.reactor.pump((0.1,))
  1106. self.successResultOf(test_d)
  1107. def test_idna_srv_target_legacy(self) -> None:
  1108. """test the behaviour when the target of a _matrix SRV record has idna chars"""
  1109. self.agent = self._make_agent()
  1110. # Return no entries for the _matrix-fed lookup, and a response for _matrix.
  1111. self.mock_resolver.resolve_service.side_effect = [
  1112. [],
  1113. [Server(host=b"xn--trget-3qa.com", port=8443)],
  1114. ] # târget.com
  1115. self.reactor.lookups["xn--trget-3qa.com"] = "1.2.3.4"
  1116. test_d = self._make_get_request(
  1117. b"matrix-federation://xn--bcher-kva.com/foo/bar"
  1118. )
  1119. # Nothing happened yet
  1120. self.assertNoResult(test_d)
  1121. self.mock_resolver.resolve_service.assert_has_calls(
  1122. [
  1123. call(b"_matrix-fed._tcp.xn--bcher-kva.com"),
  1124. call(b"_matrix._tcp.xn--bcher-kva.com"),
  1125. ]
  1126. )
  1127. # Make sure treq is trying to connect
  1128. clients = self.reactor.tcpClients
  1129. self.assertEqual(len(clients), 1)
  1130. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  1131. self.assertEqual(host, "1.2.3.4")
  1132. self.assertEqual(port, 8443)
  1133. # make a test server, and wire up the client
  1134. http_server = self._make_connection(
  1135. client_factory, expected_sni=b"xn--bcher-kva.com"
  1136. )
  1137. self.assertEqual(len(http_server.requests), 1)
  1138. request = http_server.requests[0]
  1139. self.assertEqual(request.method, b"GET")
  1140. self.assertEqual(request.path, b"/foo/bar")
  1141. self.assertEqual(
  1142. request.requestHeaders.getRawHeaders(b"host"), [b"xn--bcher-kva.com"]
  1143. )
  1144. # finish the request
  1145. request.finish()
  1146. self.reactor.pump((0.1,))
  1147. self.successResultOf(test_d)
  1148. def test_well_known_cache(self) -> None:
  1149. self.reactor.lookups["testserv"] = "1.2.3.4"
  1150. fetch_d = defer.ensureDeferred(
  1151. self.well_known_resolver.get_well_known(b"testserv")
  1152. )
  1153. # there should be an attempt to connect on port 443 for the .well-known
  1154. clients = self.reactor.tcpClients
  1155. self.assertEqual(len(clients), 1)
  1156. (host, port, client_factory, _timeout, _bindAddress) = clients.pop(0)
  1157. self.assertEqual(host, "1.2.3.4")
  1158. self.assertEqual(port, 443)
  1159. well_known_server = self._handle_well_known_connection(
  1160. client_factory,
  1161. expected_sni=b"testserv",
  1162. response_headers={b"Cache-Control": b"max-age=1000"},
  1163. content=b'{ "m.server": "target-server" }',
  1164. )
  1165. r = self.successResultOf(fetch_d)
  1166. self.assertEqual(r.delegated_server, b"target-server")
  1167. # close the tcp connection
  1168. well_known_server.loseConnection()
  1169. # repeat the request: it should hit the cache
  1170. fetch_d = defer.ensureDeferred(
  1171. self.well_known_resolver.get_well_known(b"testserv")
  1172. )
  1173. r = self.successResultOf(fetch_d)
  1174. self.assertEqual(r.delegated_server, b"target-server")
  1175. # expire the cache
  1176. self.reactor.pump((1000.0,))
  1177. # now it should connect again
  1178. fetch_d = defer.ensureDeferred(
  1179. self.well_known_resolver.get_well_known(b"testserv")
  1180. )
  1181. self.assertEqual(len(clients), 1)
  1182. (host, port, client_factory, _timeout, _bindAddress) = clients.pop(0)
  1183. self.assertEqual(host, "1.2.3.4")
  1184. self.assertEqual(port, 443)
  1185. self._handle_well_known_connection(
  1186. client_factory,
  1187. expected_sni=b"testserv",
  1188. content=b'{ "m.server": "other-server" }',
  1189. )
  1190. r = self.successResultOf(fetch_d)
  1191. self.assertEqual(r.delegated_server, b"other-server")
  1192. def test_well_known_cache_with_temp_failure(self) -> None:
  1193. """Test that we refetch well-known before the cache expires, and that
  1194. it ignores transient errors.
  1195. """
  1196. self.reactor.lookups["testserv"] = "1.2.3.4"
  1197. fetch_d = defer.ensureDeferred(
  1198. self.well_known_resolver.get_well_known(b"testserv")
  1199. )
  1200. # there should be an attempt to connect on port 443 for the .well-known
  1201. clients = self.reactor.tcpClients
  1202. self.assertEqual(len(clients), 1)
  1203. (host, port, client_factory, _timeout, _bindAddress) = clients.pop(0)
  1204. self.assertEqual(host, "1.2.3.4")
  1205. self.assertEqual(port, 443)
  1206. well_known_server = self._handle_well_known_connection(
  1207. client_factory,
  1208. expected_sni=b"testserv",
  1209. response_headers={b"Cache-Control": b"max-age=1000"},
  1210. content=b'{ "m.server": "target-server" }',
  1211. )
  1212. r = self.successResultOf(fetch_d)
  1213. self.assertEqual(r.delegated_server, b"target-server")
  1214. # close the tcp connection
  1215. well_known_server.loseConnection()
  1216. # Get close to the cache expiry, this will cause the resolver to do
  1217. # another lookup.
  1218. self.reactor.pump((900.0,))
  1219. fetch_d = defer.ensureDeferred(
  1220. self.well_known_resolver.get_well_known(b"testserv")
  1221. )
  1222. # The resolver may retry a few times, so fonx all requests that come along
  1223. attempts = 0
  1224. while self.reactor.tcpClients:
  1225. clients = self.reactor.tcpClients
  1226. (host, port, client_factory, _timeout, _bindAddress) = clients.pop(0)
  1227. attempts += 1
  1228. # fonx the connection attempt, this will be treated as a temporary
  1229. # failure.
  1230. client_factory.clientConnectionFailed(None, Exception("nope"))
  1231. # There's a few sleeps involved, so we have to pump the reactor a
  1232. # bit.
  1233. self.reactor.pump((1.0, 1.0))
  1234. # We expect to see more than one attempt as there was previously a valid
  1235. # well known.
  1236. self.assertGreater(attempts, 1)
  1237. # Resolver should return cached value, despite the lookup failing.
  1238. r = self.successResultOf(fetch_d)
  1239. self.assertEqual(r.delegated_server, b"target-server")
  1240. # Expire both caches and repeat the request
  1241. self.reactor.pump((10000.0,))
  1242. # Repeat the request, this time it should fail if the lookup fails.
  1243. fetch_d = defer.ensureDeferred(
  1244. self.well_known_resolver.get_well_known(b"testserv")
  1245. )
  1246. clients = self.reactor.tcpClients
  1247. (host, port, client_factory, _timeout, _bindAddress) = clients.pop(0)
  1248. client_factory.clientConnectionFailed(None, Exception("nope"))
  1249. self.reactor.pump((0.4,))
  1250. r = self.successResultOf(fetch_d)
  1251. self.assertEqual(r.delegated_server, None)
  1252. def test_well_known_too_large(self) -> None:
  1253. """A well-known query that returns a result which is too large should be rejected."""
  1254. self.reactor.lookups["testserv"] = "1.2.3.4"
  1255. fetch_d = defer.ensureDeferred(
  1256. self.well_known_resolver.get_well_known(b"testserv")
  1257. )
  1258. # there should be an attempt to connect on port 443 for the .well-known
  1259. clients = self.reactor.tcpClients
  1260. self.assertEqual(len(clients), 1)
  1261. (host, port, client_factory, _timeout, _bindAddress) = clients.pop(0)
  1262. self.assertEqual(host, "1.2.3.4")
  1263. self.assertEqual(port, 443)
  1264. self._handle_well_known_connection(
  1265. client_factory,
  1266. expected_sni=b"testserv",
  1267. response_headers={b"Cache-Control": b"max-age=1000"},
  1268. content=b'{ "m.server": "' + (b"a" * WELL_KNOWN_MAX_SIZE) + b'" }',
  1269. )
  1270. # The result is successful, but disabled delegation.
  1271. r = self.successResultOf(fetch_d)
  1272. self.assertIsNone(r.delegated_server)
  1273. def test_srv_fallbacks(self) -> None:
  1274. """Test that other SRV results are tried if the first one fails for _matrix-fed SRV."""
  1275. self.agent = self._make_agent()
  1276. self.mock_resolver.resolve_service.return_value = [
  1277. Server(host=b"target.com", port=8443),
  1278. Server(host=b"target.com", port=8444),
  1279. ]
  1280. self.reactor.lookups["target.com"] = "1.2.3.4"
  1281. test_d = self._make_get_request(b"matrix-federation://testserv/foo/bar")
  1282. # Nothing happened yet
  1283. self.assertNoResult(test_d)
  1284. self.mock_resolver.resolve_service.assert_called_once_with(
  1285. b"_matrix-fed._tcp.testserv"
  1286. )
  1287. # We should see an attempt to connect to the first server
  1288. clients = self.reactor.tcpClients
  1289. self.assertEqual(len(clients), 1)
  1290. (host, port, client_factory, _timeout, _bindAddress) = clients.pop(0)
  1291. self.assertEqual(host, "1.2.3.4")
  1292. self.assertEqual(port, 8443)
  1293. # Fonx the connection
  1294. client_factory.clientConnectionFailed(None, Exception("nope"))
  1295. # There's a 300ms delay in HostnameEndpoint
  1296. self.reactor.pump((0.4,))
  1297. # Hasn't failed yet
  1298. self.assertNoResult(test_d)
  1299. # We shouldnow see an attempt to connect to the second server
  1300. clients = self.reactor.tcpClients
  1301. self.assertEqual(len(clients), 1)
  1302. (host, port, client_factory, _timeout, _bindAddress) = clients.pop(0)
  1303. self.assertEqual(host, "1.2.3.4")
  1304. self.assertEqual(port, 8444)
  1305. # make a test server, and wire up the client
  1306. http_server = self._make_connection(client_factory, expected_sni=b"testserv")
  1307. self.assertEqual(len(http_server.requests), 1)
  1308. request = http_server.requests[0]
  1309. self.assertEqual(request.method, b"GET")
  1310. self.assertEqual(request.path, b"/foo/bar")
  1311. self.assertEqual(request.requestHeaders.getRawHeaders(b"host"), [b"testserv"])
  1312. # finish the request
  1313. request.finish()
  1314. self.reactor.pump((0.1,))
  1315. self.successResultOf(test_d)
  1316. def test_srv_fallbacks_legacy(self) -> None:
  1317. """Test that other SRV results are tried if the first one fails for _matrix SRV."""
  1318. self.agent = self._make_agent()
  1319. # Return no entries for the _matrix-fed lookup, and a response for _matrix.
  1320. self.mock_resolver.resolve_service.side_effect = [
  1321. [],
  1322. [
  1323. Server(host=b"target.com", port=8443),
  1324. Server(host=b"target.com", port=8444),
  1325. ],
  1326. ]
  1327. self.reactor.lookups["target.com"] = "1.2.3.4"
  1328. test_d = self._make_get_request(b"matrix-federation://testserv/foo/bar")
  1329. # Nothing happened yet
  1330. self.assertNoResult(test_d)
  1331. self.mock_resolver.resolve_service.assert_has_calls(
  1332. [call(b"_matrix-fed._tcp.testserv"), call(b"_matrix._tcp.testserv")]
  1333. )
  1334. # We should see an attempt to connect to the first server
  1335. clients = self.reactor.tcpClients
  1336. self.assertEqual(len(clients), 1)
  1337. (host, port, client_factory, _timeout, _bindAddress) = clients.pop(0)
  1338. self.assertEqual(host, "1.2.3.4")
  1339. self.assertEqual(port, 8443)
  1340. # Fonx the connection
  1341. client_factory.clientConnectionFailed(None, Exception("nope"))
  1342. # There's a 300ms delay in HostnameEndpoint
  1343. self.reactor.pump((0.4,))
  1344. # Hasn't failed yet
  1345. self.assertNoResult(test_d)
  1346. # We shouldnow see an attempt to connect to the second server
  1347. clients = self.reactor.tcpClients
  1348. self.assertEqual(len(clients), 1)
  1349. (host, port, client_factory, _timeout, _bindAddress) = clients.pop(0)
  1350. self.assertEqual(host, "1.2.3.4")
  1351. self.assertEqual(port, 8444)
  1352. # make a test server, and wire up the client
  1353. http_server = self._make_connection(client_factory, expected_sni=b"testserv")
  1354. self.assertEqual(len(http_server.requests), 1)
  1355. request = http_server.requests[0]
  1356. self.assertEqual(request.method, b"GET")
  1357. self.assertEqual(request.path, b"/foo/bar")
  1358. self.assertEqual(request.requestHeaders.getRawHeaders(b"host"), [b"testserv"])
  1359. # finish the request
  1360. request.finish()
  1361. self.reactor.pump((0.1,))
  1362. self.successResultOf(test_d)
  1363. def test_srv_no_fallback_to_legacy(self) -> None:
  1364. """Test that _matrix SRV results are not tried if the _matrix-fed one fails."""
  1365. self.agent = self._make_agent()
  1366. # Return a failing entry for _matrix-fed.
  1367. self.mock_resolver.resolve_service.side_effect = [
  1368. [Server(host=b"target.com", port=8443)],
  1369. [],
  1370. ]
  1371. self.reactor.lookups["target.com"] = "1.2.3.4"
  1372. test_d = self._make_get_request(b"matrix-federation://testserv/foo/bar")
  1373. # Nothing happened yet
  1374. self.assertNoResult(test_d)
  1375. # Only the _matrix-fed is checked, _matrix is ignored.
  1376. self.mock_resolver.resolve_service.assert_called_once_with(
  1377. b"_matrix-fed._tcp.testserv"
  1378. )
  1379. # We should see an attempt to connect to the first server
  1380. clients = self.reactor.tcpClients
  1381. self.assertEqual(len(clients), 1)
  1382. (host, port, client_factory, _timeout, _bindAddress) = clients.pop(0)
  1383. self.assertEqual(host, "1.2.3.4")
  1384. self.assertEqual(port, 8443)
  1385. # Fonx the connection
  1386. client_factory.clientConnectionFailed(None, Exception("nope"))
  1387. # There's a 300ms delay in HostnameEndpoint
  1388. self.reactor.pump((0.4,))
  1389. # Failed to resolve a server.
  1390. self.assertFailure(test_d, Exception)
  1391. class TestCachePeriodFromHeaders(unittest.TestCase):
  1392. def test_cache_control(self) -> None:
  1393. # uppercase
  1394. self.assertEqual(
  1395. _cache_period_from_headers(
  1396. Headers({b"Cache-Control": [b"foo, Max-Age = 100, bar"]})
  1397. ),
  1398. 100,
  1399. )
  1400. # missing value
  1401. self.assertIsNone(
  1402. _cache_period_from_headers(Headers({b"Cache-Control": [b"max-age=, bar"]}))
  1403. )
  1404. # hackernews: bogus due to semicolon
  1405. self.assertIsNone(
  1406. _cache_period_from_headers(
  1407. Headers({b"Cache-Control": [b"private; max-age=0"]})
  1408. )
  1409. )
  1410. # github
  1411. self.assertEqual(
  1412. _cache_period_from_headers(
  1413. Headers({b"Cache-Control": [b"max-age=0, private, must-revalidate"]})
  1414. ),
  1415. 0,
  1416. )
  1417. # google
  1418. self.assertEqual(
  1419. _cache_period_from_headers(
  1420. Headers({b"cache-control": [b"private, max-age=0"]})
  1421. ),
  1422. 0,
  1423. )
  1424. def test_expires(self) -> None:
  1425. self.assertEqual(
  1426. _cache_period_from_headers(
  1427. Headers({b"Expires": [b"Wed, 30 Jan 2019 07:35:33 GMT"]}),
  1428. time_now=lambda: 1548833700,
  1429. ),
  1430. 33,
  1431. )
  1432. # cache-control overrides expires
  1433. self.assertEqual(
  1434. _cache_period_from_headers(
  1435. Headers(
  1436. {
  1437. b"cache-control": [b"max-age=10"],
  1438. b"Expires": [b"Wed, 30 Jan 2019 07:35:33 GMT"],
  1439. }
  1440. ),
  1441. time_now=lambda: 1548833700,
  1442. ),
  1443. 10,
  1444. )
  1445. # invalid expires means immediate expiry
  1446. self.assertEqual(_cache_period_from_headers(Headers({b"Expires": [b"0"]})), 0)
  1447. def _check_logcontext(context: LoggingContextOrSentinel) -> None:
  1448. current = current_context()
  1449. if current is not context:
  1450. raise AssertionError("Expected logcontext %s but was %s" % (context, current))
  1451. def _get_test_protocol_factory() -> IProtocolFactory:
  1452. """Get a protocol Factory which will build an HTTPChannel
  1453. Returns:
  1454. interfaces.IProtocolFactory
  1455. """
  1456. server_factory = Factory.forProtocol(HTTPChannel)
  1457. # Request.finish expects the factory to have a 'log' method.
  1458. server_factory.log = _log_request
  1459. return server_factory
  1460. def _log_request(request: str) -> None:
  1461. """Implements Factory.log, which is expected by Request.finish"""
  1462. logger.info(f"Completed request {request}")
  1463. @implementer(IPolicyForHTTPS)
  1464. class TrustingTLSPolicyForHTTPS:
  1465. """An IPolicyForHTTPS which checks that the certificate belongs to the
  1466. right server, but doesn't check the certificate chain."""
  1467. def creatorForNetloc(
  1468. self, hostname: bytes, port: int
  1469. ) -> IOpenSSLClientConnectionCreator:
  1470. certificateOptions = OpenSSLCertificateOptions()
  1471. return ClientTLSOptions(hostname, certificateOptions.getContext())