test_matrix_federation_agent.py 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2019 New Vector Ltd
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. import logging
  16. from mock import Mock
  17. import treq
  18. from netaddr import IPSet
  19. from service_identity import VerificationError
  20. from zope.interface import implementer
  21. from twisted.internet import defer
  22. from twisted.internet._sslverify import ClientTLSOptions, OpenSSLCertificateOptions
  23. from twisted.internet.protocol import Factory
  24. from twisted.protocols.tls import TLSMemoryBIOFactory
  25. from twisted.web._newclient import ResponseNeverReceived
  26. from twisted.web.client import Agent
  27. from twisted.web.http import HTTPChannel
  28. from twisted.web.http_headers import Headers
  29. from twisted.web.iweb import IPolicyForHTTPS
  30. from synapse.config.homeserver import HomeServerConfig
  31. from synapse.crypto.context_factory import FederationPolicyForHTTPS
  32. from synapse.http.federation.matrix_federation_agent import MatrixFederationAgent
  33. from synapse.http.federation.srv_resolver import Server
  34. from synapse.http.federation.well_known_resolver import (
  35. WELL_KNOWN_MAX_SIZE,
  36. WellKnownResolver,
  37. _cache_period_from_headers,
  38. )
  39. from synapse.logging.context import SENTINEL_CONTEXT, LoggingContext, current_context
  40. from synapse.util.caches.ttlcache import TTLCache
  41. from tests import unittest
  42. from tests.http import TestServerTLSConnectionFactory, get_test_ca_cert_file
  43. from tests.server import FakeTransport, ThreadedMemoryReactorClock
  44. from tests.utils import default_config
  45. logger = logging.getLogger(__name__)
  46. test_server_connection_factory = None
  47. def get_connection_factory():
  48. # this needs to happen once, but not until we are ready to run the first test
  49. global test_server_connection_factory
  50. if test_server_connection_factory is None:
  51. test_server_connection_factory = TestServerTLSConnectionFactory(
  52. sanlist=[
  53. b"DNS:testserv",
  54. b"DNS:target-server",
  55. b"DNS:xn--bcher-kva.com",
  56. b"IP:1.2.3.4",
  57. b"IP:::1",
  58. ]
  59. )
  60. return test_server_connection_factory
  61. # Once Async Mocks or lambdas are supported this can go away.
  62. def generate_resolve_service(result):
  63. async def resolve_service(_):
  64. return result
  65. return resolve_service
  66. class MatrixFederationAgentTests(unittest.TestCase):
  67. def setUp(self):
  68. self.reactor = ThreadedMemoryReactorClock()
  69. self.mock_resolver = Mock()
  70. config_dict = default_config("test", parse=False)
  71. config_dict["federation_custom_ca_list"] = [get_test_ca_cert_file()]
  72. self._config = config = HomeServerConfig()
  73. config.parse_config_dict(config_dict, "", "")
  74. self.tls_factory = FederationPolicyForHTTPS(config)
  75. self.well_known_cache = TTLCache("test_cache", timer=self.reactor.seconds)
  76. self.had_well_known_cache = TTLCache("test_cache", timer=self.reactor.seconds)
  77. self.well_known_resolver = WellKnownResolver(
  78. self.reactor,
  79. Agent(self.reactor, contextFactory=self.tls_factory),
  80. b"test-agent",
  81. well_known_cache=self.well_known_cache,
  82. had_well_known_cache=self.had_well_known_cache,
  83. )
  84. self.agent = MatrixFederationAgent(
  85. reactor=self.reactor,
  86. tls_client_options_factory=self.tls_factory,
  87. user_agent="test-agent", # Note that this is unused since _well_known_resolver is provided.
  88. ip_blacklist=IPSet(),
  89. _srv_resolver=self.mock_resolver,
  90. _well_known_resolver=self.well_known_resolver,
  91. )
  92. def _make_connection(self, client_factory, expected_sni):
  93. """Builds a test server, and completes the outgoing client connection
  94. Returns:
  95. HTTPChannel: the test server
  96. """
  97. # build the test server
  98. server_tls_protocol = _build_test_server(get_connection_factory())
  99. # now, tell the client protocol factory to build the client protocol (it will be a
  100. # _WrappingProtocol, around a TLSMemoryBIOProtocol, around an
  101. # HTTP11ClientProtocol) and wire the output of said protocol up to the server via
  102. # a FakeTransport.
  103. #
  104. # Normally this would be done by the TCP socket code in Twisted, but we are
  105. # stubbing that out here.
  106. client_protocol = client_factory.buildProtocol(None)
  107. client_protocol.makeConnection(
  108. FakeTransport(server_tls_protocol, self.reactor, client_protocol)
  109. )
  110. # tell the server tls protocol to send its stuff back to the client, too
  111. server_tls_protocol.makeConnection(
  112. FakeTransport(client_protocol, self.reactor, server_tls_protocol)
  113. )
  114. # grab a hold of the TLS connection, in case it gets torn down
  115. server_tls_connection = server_tls_protocol._tlsConnection
  116. # fish the test server back out of the server-side TLS protocol.
  117. http_protocol = server_tls_protocol.wrappedProtocol
  118. # give the reactor a pump to get the TLS juices flowing.
  119. self.reactor.pump((0.1,))
  120. # check the SNI
  121. server_name = server_tls_connection.get_servername()
  122. self.assertEqual(
  123. server_name,
  124. expected_sni,
  125. "Expected SNI %s but got %s" % (expected_sni, server_name),
  126. )
  127. return http_protocol
  128. @defer.inlineCallbacks
  129. def _make_get_request(self, uri):
  130. """
  131. Sends a simple GET request via the agent, and checks its logcontext management
  132. """
  133. with LoggingContext("one") as context:
  134. fetch_d = self.agent.request(b"GET", uri)
  135. # Nothing happened yet
  136. self.assertNoResult(fetch_d)
  137. # should have reset logcontext to the sentinel
  138. _check_logcontext(SENTINEL_CONTEXT)
  139. try:
  140. fetch_res = yield fetch_d
  141. return fetch_res
  142. except Exception as e:
  143. logger.info("Fetch of %s failed: %s", uri.decode("ascii"), e)
  144. raise
  145. finally:
  146. _check_logcontext(context)
  147. def _handle_well_known_connection(
  148. self, client_factory, expected_sni, content, response_headers={}
  149. ):
  150. """Handle an outgoing HTTPs connection: wire it up to a server, check that the
  151. request is for a .well-known, and send the response.
  152. Args:
  153. client_factory (IProtocolFactory): outgoing connection
  154. expected_sni (bytes): SNI that we expect the outgoing connection to send
  155. content (bytes): content to send back as the .well-known
  156. Returns:
  157. HTTPChannel: server impl
  158. """
  159. # make the connection for .well-known
  160. well_known_server = self._make_connection(
  161. client_factory, expected_sni=expected_sni
  162. )
  163. # check the .well-known request and send a response
  164. self.assertEqual(len(well_known_server.requests), 1)
  165. request = well_known_server.requests[0]
  166. self.assertEqual(
  167. request.requestHeaders.getRawHeaders(b"user-agent"), [b"test-agent"]
  168. )
  169. self._send_well_known_response(request, content, headers=response_headers)
  170. return well_known_server
  171. def _send_well_known_response(self, request, content, headers={}):
  172. """Check that an incoming request looks like a valid .well-known request, and
  173. send back the response.
  174. """
  175. self.assertEqual(request.method, b"GET")
  176. self.assertEqual(request.path, b"/.well-known/matrix/server")
  177. self.assertEqual(request.requestHeaders.getRawHeaders(b"host"), [b"testserv"])
  178. # send back a response
  179. for k, v in headers.items():
  180. request.setHeader(k, v)
  181. request.write(content)
  182. request.finish()
  183. self.reactor.pump((0.1,))
  184. def test_get(self):
  185. """
  186. happy-path test of a GET request with an explicit port
  187. """
  188. self.reactor.lookups["testserv"] = "1.2.3.4"
  189. test_d = self._make_get_request(b"matrix://testserv:8448/foo/bar")
  190. # Nothing happened yet
  191. self.assertNoResult(test_d)
  192. # Make sure treq is trying to connect
  193. clients = self.reactor.tcpClients
  194. self.assertEqual(len(clients), 1)
  195. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  196. self.assertEqual(host, "1.2.3.4")
  197. self.assertEqual(port, 8448)
  198. # make a test server, and wire up the client
  199. http_server = self._make_connection(client_factory, expected_sni=b"testserv")
  200. self.assertEqual(len(http_server.requests), 1)
  201. request = http_server.requests[0]
  202. self.assertEqual(request.method, b"GET")
  203. self.assertEqual(request.path, b"/foo/bar")
  204. self.assertEqual(
  205. request.requestHeaders.getRawHeaders(b"host"), [b"testserv:8448"]
  206. )
  207. self.assertEqual(
  208. request.requestHeaders.getRawHeaders(b"user-agent"), [b"test-agent"]
  209. )
  210. content = request.content.read()
  211. self.assertEqual(content, b"")
  212. # Deferred is still without a result
  213. self.assertNoResult(test_d)
  214. # send the headers
  215. request.responseHeaders.setRawHeaders(b"Content-Type", [b"application/json"])
  216. request.write("")
  217. self.reactor.pump((0.1,))
  218. response = self.successResultOf(test_d)
  219. # that should give us a Response object
  220. self.assertEqual(response.code, 200)
  221. # Send the body
  222. request.write('{ "a": 1 }'.encode("ascii"))
  223. request.finish()
  224. self.reactor.pump((0.1,))
  225. # check it can be read
  226. json = self.successResultOf(treq.json_content(response))
  227. self.assertEqual(json, {"a": 1})
  228. def test_get_ip_address(self):
  229. """
  230. Test the behaviour when the server name contains an explicit IP (with no port)
  231. """
  232. # there will be a getaddrinfo on the IP
  233. self.reactor.lookups["1.2.3.4"] = "1.2.3.4"
  234. test_d = self._make_get_request(b"matrix://1.2.3.4/foo/bar")
  235. # Nothing happened yet
  236. self.assertNoResult(test_d)
  237. # Make sure treq is trying to connect
  238. clients = self.reactor.tcpClients
  239. self.assertEqual(len(clients), 1)
  240. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  241. self.assertEqual(host, "1.2.3.4")
  242. self.assertEqual(port, 8448)
  243. # make a test server, and wire up the client
  244. http_server = self._make_connection(client_factory, expected_sni=None)
  245. self.assertEqual(len(http_server.requests), 1)
  246. request = http_server.requests[0]
  247. self.assertEqual(request.method, b"GET")
  248. self.assertEqual(request.path, b"/foo/bar")
  249. self.assertEqual(request.requestHeaders.getRawHeaders(b"host"), [b"1.2.3.4"])
  250. # finish the request
  251. request.finish()
  252. self.reactor.pump((0.1,))
  253. self.successResultOf(test_d)
  254. def test_get_ipv6_address(self):
  255. """
  256. Test the behaviour when the server name contains an explicit IPv6 address
  257. (with no port)
  258. """
  259. # there will be a getaddrinfo on the IP
  260. self.reactor.lookups["::1"] = "::1"
  261. test_d = self._make_get_request(b"matrix://[::1]/foo/bar")
  262. # Nothing happened yet
  263. self.assertNoResult(test_d)
  264. # Make sure treq is trying to connect
  265. clients = self.reactor.tcpClients
  266. self.assertEqual(len(clients), 1)
  267. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  268. self.assertEqual(host, "::1")
  269. self.assertEqual(port, 8448)
  270. # make a test server, and wire up the client
  271. http_server = self._make_connection(client_factory, expected_sni=None)
  272. self.assertEqual(len(http_server.requests), 1)
  273. request = http_server.requests[0]
  274. self.assertEqual(request.method, b"GET")
  275. self.assertEqual(request.path, b"/foo/bar")
  276. self.assertEqual(request.requestHeaders.getRawHeaders(b"host"), [b"[::1]"])
  277. # finish the request
  278. request.finish()
  279. self.reactor.pump((0.1,))
  280. self.successResultOf(test_d)
  281. def test_get_ipv6_address_with_port(self):
  282. """
  283. Test the behaviour when the server name contains an explicit IPv6 address
  284. (with explicit port)
  285. """
  286. # there will be a getaddrinfo on the IP
  287. self.reactor.lookups["::1"] = "::1"
  288. test_d = self._make_get_request(b"matrix://[::1]:80/foo/bar")
  289. # Nothing happened yet
  290. self.assertNoResult(test_d)
  291. # Make sure treq is trying to connect
  292. clients = self.reactor.tcpClients
  293. self.assertEqual(len(clients), 1)
  294. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  295. self.assertEqual(host, "::1")
  296. self.assertEqual(port, 80)
  297. # make a test server, and wire up the client
  298. http_server = self._make_connection(client_factory, expected_sni=None)
  299. self.assertEqual(len(http_server.requests), 1)
  300. request = http_server.requests[0]
  301. self.assertEqual(request.method, b"GET")
  302. self.assertEqual(request.path, b"/foo/bar")
  303. self.assertEqual(request.requestHeaders.getRawHeaders(b"host"), [b"[::1]:80"])
  304. # finish the request
  305. request.finish()
  306. self.reactor.pump((0.1,))
  307. self.successResultOf(test_d)
  308. def test_get_hostname_bad_cert(self):
  309. """
  310. Test the behaviour when the certificate on the server doesn't match the hostname
  311. """
  312. self.mock_resolver.resolve_service.side_effect = generate_resolve_service([])
  313. self.reactor.lookups["testserv1"] = "1.2.3.4"
  314. test_d = self._make_get_request(b"matrix://testserv1/foo/bar")
  315. # Nothing happened yet
  316. self.assertNoResult(test_d)
  317. # No SRV record lookup yet
  318. self.mock_resolver.resolve_service.assert_not_called()
  319. # there should be an attempt to connect on port 443 for the .well-known
  320. clients = self.reactor.tcpClients
  321. self.assertEqual(len(clients), 1)
  322. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  323. self.assertEqual(host, "1.2.3.4")
  324. self.assertEqual(port, 443)
  325. # fonx the connection
  326. client_factory.clientConnectionFailed(None, Exception("nope"))
  327. # attemptdelay on the hostnameendpoint is 0.3, so takes that long before the
  328. # .well-known request fails.
  329. self.reactor.pump((0.4,))
  330. # now there should be a SRV lookup
  331. self.mock_resolver.resolve_service.assert_called_once_with(
  332. b"_matrix._tcp.testserv1"
  333. )
  334. # we should fall back to a direct connection
  335. self.assertEqual(len(clients), 2)
  336. (host, port, client_factory, _timeout, _bindAddress) = clients[1]
  337. self.assertEqual(host, "1.2.3.4")
  338. self.assertEqual(port, 8448)
  339. # make a test server, and wire up the client
  340. http_server = self._make_connection(client_factory, expected_sni=b"testserv1")
  341. # there should be no requests
  342. self.assertEqual(len(http_server.requests), 0)
  343. # ... and the request should have failed
  344. e = self.failureResultOf(test_d, ResponseNeverReceived)
  345. failure_reason = e.value.reasons[0]
  346. self.assertIsInstance(failure_reason.value, VerificationError)
  347. def test_get_ip_address_bad_cert(self):
  348. """
  349. Test the behaviour when the server name contains an explicit IP, but
  350. the server cert doesn't cover it
  351. """
  352. # there will be a getaddrinfo on the IP
  353. self.reactor.lookups["1.2.3.5"] = "1.2.3.5"
  354. test_d = self._make_get_request(b"matrix://1.2.3.5/foo/bar")
  355. # Nothing happened yet
  356. self.assertNoResult(test_d)
  357. # Make sure treq is trying to connect
  358. clients = self.reactor.tcpClients
  359. self.assertEqual(len(clients), 1)
  360. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  361. self.assertEqual(host, "1.2.3.5")
  362. self.assertEqual(port, 8448)
  363. # make a test server, and wire up the client
  364. http_server = self._make_connection(client_factory, expected_sni=None)
  365. # there should be no requests
  366. self.assertEqual(len(http_server.requests), 0)
  367. # ... and the request should have failed
  368. e = self.failureResultOf(test_d, ResponseNeverReceived)
  369. failure_reason = e.value.reasons[0]
  370. self.assertIsInstance(failure_reason.value, VerificationError)
  371. def test_get_no_srv_no_well_known(self):
  372. """
  373. Test the behaviour when the server name has no port, no SRV, and no well-known
  374. """
  375. self.mock_resolver.resolve_service.side_effect = generate_resolve_service([])
  376. self.reactor.lookups["testserv"] = "1.2.3.4"
  377. test_d = self._make_get_request(b"matrix://testserv/foo/bar")
  378. # Nothing happened yet
  379. self.assertNoResult(test_d)
  380. # No SRV record lookup yet
  381. self.mock_resolver.resolve_service.assert_not_called()
  382. # there should be an attempt to connect on port 443 for the .well-known
  383. clients = self.reactor.tcpClients
  384. self.assertEqual(len(clients), 1)
  385. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  386. self.assertEqual(host, "1.2.3.4")
  387. self.assertEqual(port, 443)
  388. # fonx the connection
  389. client_factory.clientConnectionFailed(None, Exception("nope"))
  390. # attemptdelay on the hostnameendpoint is 0.3, so takes that long before the
  391. # .well-known request fails.
  392. self.reactor.pump((0.4,))
  393. # now there should be a SRV lookup
  394. self.mock_resolver.resolve_service.assert_called_once_with(
  395. b"_matrix._tcp.testserv"
  396. )
  397. # we should fall back to a direct connection
  398. self.assertEqual(len(clients), 2)
  399. (host, port, client_factory, _timeout, _bindAddress) = clients[1]
  400. self.assertEqual(host, "1.2.3.4")
  401. self.assertEqual(port, 8448)
  402. # make a test server, and wire up the client
  403. http_server = self._make_connection(client_factory, expected_sni=b"testserv")
  404. self.assertEqual(len(http_server.requests), 1)
  405. request = http_server.requests[0]
  406. self.assertEqual(request.method, b"GET")
  407. self.assertEqual(request.path, b"/foo/bar")
  408. self.assertEqual(request.requestHeaders.getRawHeaders(b"host"), [b"testserv"])
  409. # finish the request
  410. request.finish()
  411. self.reactor.pump((0.1,))
  412. self.successResultOf(test_d)
  413. def test_get_well_known(self):
  414. """Test the behaviour when the .well-known delegates elsewhere"""
  415. self.mock_resolver.resolve_service.side_effect = generate_resolve_service([])
  416. self.reactor.lookups["testserv"] = "1.2.3.4"
  417. self.reactor.lookups["target-server"] = "1::f"
  418. test_d = self._make_get_request(b"matrix://testserv/foo/bar")
  419. # Nothing happened yet
  420. self.assertNoResult(test_d)
  421. # there should be an attempt to connect on port 443 for the .well-known
  422. clients = self.reactor.tcpClients
  423. self.assertEqual(len(clients), 1)
  424. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  425. self.assertEqual(host, "1.2.3.4")
  426. self.assertEqual(port, 443)
  427. self._handle_well_known_connection(
  428. client_factory,
  429. expected_sni=b"testserv",
  430. content=b'{ "m.server": "target-server" }',
  431. )
  432. # there should be a SRV lookup
  433. self.mock_resolver.resolve_service.assert_called_once_with(
  434. b"_matrix._tcp.target-server"
  435. )
  436. # now we should get a connection to the target server
  437. self.assertEqual(len(clients), 2)
  438. (host, port, client_factory, _timeout, _bindAddress) = clients[1]
  439. self.assertEqual(host, "1::f")
  440. self.assertEqual(port, 8448)
  441. # make a test server, and wire up the client
  442. http_server = self._make_connection(
  443. client_factory, expected_sni=b"target-server"
  444. )
  445. self.assertEqual(len(http_server.requests), 1)
  446. request = http_server.requests[0]
  447. self.assertEqual(request.method, b"GET")
  448. self.assertEqual(request.path, b"/foo/bar")
  449. self.assertEqual(
  450. request.requestHeaders.getRawHeaders(b"host"), [b"target-server"]
  451. )
  452. # finish the request
  453. request.finish()
  454. self.reactor.pump((0.1,))
  455. self.successResultOf(test_d)
  456. self.assertEqual(self.well_known_cache[b"testserv"], b"target-server")
  457. # check the cache expires
  458. self.reactor.pump((48 * 3600,))
  459. self.well_known_cache.expire()
  460. self.assertNotIn(b"testserv", self.well_known_cache)
  461. def test_get_well_known_redirect(self):
  462. """Test the behaviour when the server name has no port and no SRV record, but
  463. the .well-known has a 300 redirect
  464. """
  465. self.mock_resolver.resolve_service.side_effect = generate_resolve_service([])
  466. self.reactor.lookups["testserv"] = "1.2.3.4"
  467. self.reactor.lookups["target-server"] = "1::f"
  468. test_d = self._make_get_request(b"matrix://testserv/foo/bar")
  469. # Nothing happened yet
  470. self.assertNoResult(test_d)
  471. # there should be an attempt to connect on port 443 for the .well-known
  472. clients = self.reactor.tcpClients
  473. self.assertEqual(len(clients), 1)
  474. (host, port, client_factory, _timeout, _bindAddress) = clients.pop()
  475. self.assertEqual(host, "1.2.3.4")
  476. self.assertEqual(port, 443)
  477. redirect_server = self._make_connection(
  478. client_factory, expected_sni=b"testserv"
  479. )
  480. # send a 302 redirect
  481. self.assertEqual(len(redirect_server.requests), 1)
  482. request = redirect_server.requests[0]
  483. request.redirect(b"https://testserv/even_better_known")
  484. request.finish()
  485. self.reactor.pump((0.1,))
  486. # now there should be another connection
  487. clients = self.reactor.tcpClients
  488. self.assertEqual(len(clients), 1)
  489. (host, port, client_factory, _timeout, _bindAddress) = clients.pop()
  490. self.assertEqual(host, "1.2.3.4")
  491. self.assertEqual(port, 443)
  492. well_known_server = self._make_connection(
  493. client_factory, expected_sni=b"testserv"
  494. )
  495. self.assertEqual(len(well_known_server.requests), 1, "No request after 302")
  496. request = well_known_server.requests[0]
  497. self.assertEqual(request.method, b"GET")
  498. self.assertEqual(request.path, b"/even_better_known")
  499. request.write(b'{ "m.server": "target-server" }')
  500. request.finish()
  501. self.reactor.pump((0.1,))
  502. # there should be a SRV lookup
  503. self.mock_resolver.resolve_service.assert_called_once_with(
  504. b"_matrix._tcp.target-server"
  505. )
  506. # now we should get a connection to the target server
  507. self.assertEqual(len(clients), 1)
  508. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  509. self.assertEqual(host, "1::f")
  510. self.assertEqual(port, 8448)
  511. # make a test server, and wire up the client
  512. http_server = self._make_connection(
  513. client_factory, expected_sni=b"target-server"
  514. )
  515. self.assertEqual(len(http_server.requests), 1)
  516. request = http_server.requests[0]
  517. self.assertEqual(request.method, b"GET")
  518. self.assertEqual(request.path, b"/foo/bar")
  519. self.assertEqual(
  520. request.requestHeaders.getRawHeaders(b"host"), [b"target-server"]
  521. )
  522. # finish the request
  523. request.finish()
  524. self.reactor.pump((0.1,))
  525. self.successResultOf(test_d)
  526. self.assertEqual(self.well_known_cache[b"testserv"], b"target-server")
  527. # check the cache expires
  528. self.reactor.pump((48 * 3600,))
  529. self.well_known_cache.expire()
  530. self.assertNotIn(b"testserv", self.well_known_cache)
  531. def test_get_invalid_well_known(self):
  532. """
  533. Test the behaviour when the server name has an *invalid* well-known (and no SRV)
  534. """
  535. self.mock_resolver.resolve_service.side_effect = generate_resolve_service([])
  536. self.reactor.lookups["testserv"] = "1.2.3.4"
  537. test_d = self._make_get_request(b"matrix://testserv/foo/bar")
  538. # Nothing happened yet
  539. self.assertNoResult(test_d)
  540. # No SRV record lookup yet
  541. self.mock_resolver.resolve_service.assert_not_called()
  542. # there should be an attempt to connect on port 443 for the .well-known
  543. clients = self.reactor.tcpClients
  544. self.assertEqual(len(clients), 1)
  545. (host, port, client_factory, _timeout, _bindAddress) = clients.pop()
  546. self.assertEqual(host, "1.2.3.4")
  547. self.assertEqual(port, 443)
  548. self._handle_well_known_connection(
  549. client_factory, expected_sni=b"testserv", content=b"NOT JSON"
  550. )
  551. # now there should be a SRV lookup
  552. self.mock_resolver.resolve_service.assert_called_once_with(
  553. b"_matrix._tcp.testserv"
  554. )
  555. # we should fall back to a direct connection
  556. self.assertEqual(len(clients), 1)
  557. (host, port, client_factory, _timeout, _bindAddress) = clients.pop()
  558. self.assertEqual(host, "1.2.3.4")
  559. self.assertEqual(port, 8448)
  560. # make a test server, and wire up the client
  561. http_server = self._make_connection(client_factory, expected_sni=b"testserv")
  562. self.assertEqual(len(http_server.requests), 1)
  563. request = http_server.requests[0]
  564. self.assertEqual(request.method, b"GET")
  565. self.assertEqual(request.path, b"/foo/bar")
  566. self.assertEqual(request.requestHeaders.getRawHeaders(b"host"), [b"testserv"])
  567. # finish the request
  568. request.finish()
  569. self.reactor.pump((0.1,))
  570. self.successResultOf(test_d)
  571. def test_get_well_known_unsigned_cert(self):
  572. """Test the behaviour when the .well-known server presents a cert
  573. not signed by a CA
  574. """
  575. # we use the same test server as the other tests, but use an agent with
  576. # the config left to the default, which will not trust it (since the
  577. # presented cert is signed by a test CA)
  578. self.mock_resolver.resolve_service.side_effect = generate_resolve_service([])
  579. self.reactor.lookups["testserv"] = "1.2.3.4"
  580. config = default_config("test", parse=True)
  581. # Build a new agent and WellKnownResolver with a different tls factory
  582. tls_factory = FederationPolicyForHTTPS(config)
  583. agent = MatrixFederationAgent(
  584. reactor=self.reactor,
  585. tls_client_options_factory=tls_factory,
  586. user_agent=b"test-agent", # This is unused since _well_known_resolver is passed below.
  587. ip_blacklist=IPSet(),
  588. _srv_resolver=self.mock_resolver,
  589. _well_known_resolver=WellKnownResolver(
  590. self.reactor,
  591. Agent(self.reactor, contextFactory=tls_factory),
  592. b"test-agent",
  593. well_known_cache=self.well_known_cache,
  594. had_well_known_cache=self.had_well_known_cache,
  595. ),
  596. )
  597. test_d = agent.request(b"GET", b"matrix://testserv/foo/bar")
  598. # Nothing happened yet
  599. self.assertNoResult(test_d)
  600. # there should be an attempt to connect on port 443 for the .well-known
  601. clients = self.reactor.tcpClients
  602. self.assertEqual(len(clients), 1)
  603. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  604. self.assertEqual(host, "1.2.3.4")
  605. self.assertEqual(port, 443)
  606. http_proto = self._make_connection(client_factory, expected_sni=b"testserv")
  607. # there should be no requests
  608. self.assertEqual(len(http_proto.requests), 0)
  609. # and there should be a SRV lookup instead
  610. self.mock_resolver.resolve_service.assert_called_once_with(
  611. b"_matrix._tcp.testserv"
  612. )
  613. def test_get_hostname_srv(self):
  614. """
  615. Test the behaviour when there is a single SRV record
  616. """
  617. self.mock_resolver.resolve_service.side_effect = generate_resolve_service(
  618. [Server(host=b"srvtarget", port=8443)]
  619. )
  620. self.reactor.lookups["srvtarget"] = "1.2.3.4"
  621. test_d = self._make_get_request(b"matrix://testserv/foo/bar")
  622. # Nothing happened yet
  623. self.assertNoResult(test_d)
  624. # the request for a .well-known will have failed with a DNS lookup error.
  625. self.mock_resolver.resolve_service.assert_called_once_with(
  626. b"_matrix._tcp.testserv"
  627. )
  628. # Make sure treq is trying to connect
  629. clients = self.reactor.tcpClients
  630. self.assertEqual(len(clients), 1)
  631. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  632. self.assertEqual(host, "1.2.3.4")
  633. self.assertEqual(port, 8443)
  634. # make a test server, and wire up the client
  635. http_server = self._make_connection(client_factory, expected_sni=b"testserv")
  636. self.assertEqual(len(http_server.requests), 1)
  637. request = http_server.requests[0]
  638. self.assertEqual(request.method, b"GET")
  639. self.assertEqual(request.path, b"/foo/bar")
  640. self.assertEqual(request.requestHeaders.getRawHeaders(b"host"), [b"testserv"])
  641. # finish the request
  642. request.finish()
  643. self.reactor.pump((0.1,))
  644. self.successResultOf(test_d)
  645. def test_get_well_known_srv(self):
  646. """Test the behaviour when the .well-known redirects to a place where there
  647. is a SRV.
  648. """
  649. self.reactor.lookups["testserv"] = "1.2.3.4"
  650. self.reactor.lookups["srvtarget"] = "5.6.7.8"
  651. test_d = self._make_get_request(b"matrix://testserv/foo/bar")
  652. # Nothing happened yet
  653. self.assertNoResult(test_d)
  654. # there should be an attempt to connect on port 443 for the .well-known
  655. clients = self.reactor.tcpClients
  656. self.assertEqual(len(clients), 1)
  657. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  658. self.assertEqual(host, "1.2.3.4")
  659. self.assertEqual(port, 443)
  660. self.mock_resolver.resolve_service.side_effect = generate_resolve_service(
  661. [Server(host=b"srvtarget", port=8443)]
  662. )
  663. self._handle_well_known_connection(
  664. client_factory,
  665. expected_sni=b"testserv",
  666. content=b'{ "m.server": "target-server" }',
  667. )
  668. # there should be a SRV lookup
  669. self.mock_resolver.resolve_service.assert_called_once_with(
  670. b"_matrix._tcp.target-server"
  671. )
  672. # now we should get a connection to the target of the SRV record
  673. self.assertEqual(len(clients), 2)
  674. (host, port, client_factory, _timeout, _bindAddress) = clients[1]
  675. self.assertEqual(host, "5.6.7.8")
  676. self.assertEqual(port, 8443)
  677. # make a test server, and wire up the client
  678. http_server = self._make_connection(
  679. client_factory, expected_sni=b"target-server"
  680. )
  681. self.assertEqual(len(http_server.requests), 1)
  682. request = http_server.requests[0]
  683. self.assertEqual(request.method, b"GET")
  684. self.assertEqual(request.path, b"/foo/bar")
  685. self.assertEqual(
  686. request.requestHeaders.getRawHeaders(b"host"), [b"target-server"]
  687. )
  688. # finish the request
  689. request.finish()
  690. self.reactor.pump((0.1,))
  691. self.successResultOf(test_d)
  692. def test_idna_servername(self):
  693. """test the behaviour when the server name has idna chars in"""
  694. self.mock_resolver.resolve_service.side_effect = generate_resolve_service([])
  695. # the resolver is always called with the IDNA hostname as a native string.
  696. self.reactor.lookups["xn--bcher-kva.com"] = "1.2.3.4"
  697. # this is idna for bücher.com
  698. test_d = self._make_get_request(b"matrix://xn--bcher-kva.com/foo/bar")
  699. # Nothing happened yet
  700. self.assertNoResult(test_d)
  701. # No SRV record lookup yet
  702. self.mock_resolver.resolve_service.assert_not_called()
  703. # there should be an attempt to connect on port 443 for the .well-known
  704. clients = self.reactor.tcpClients
  705. self.assertEqual(len(clients), 1)
  706. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  707. self.assertEqual(host, "1.2.3.4")
  708. self.assertEqual(port, 443)
  709. # fonx the connection
  710. client_factory.clientConnectionFailed(None, Exception("nope"))
  711. # attemptdelay on the hostnameendpoint is 0.3, so takes that long before the
  712. # .well-known request fails.
  713. self.reactor.pump((0.4,))
  714. # now there should have been a SRV lookup
  715. self.mock_resolver.resolve_service.assert_called_once_with(
  716. b"_matrix._tcp.xn--bcher-kva.com"
  717. )
  718. # We should fall back to port 8448
  719. clients = self.reactor.tcpClients
  720. self.assertEqual(len(clients), 2)
  721. (host, port, client_factory, _timeout, _bindAddress) = clients[1]
  722. self.assertEqual(host, "1.2.3.4")
  723. self.assertEqual(port, 8448)
  724. # make a test server, and wire up the client
  725. http_server = self._make_connection(
  726. client_factory, expected_sni=b"xn--bcher-kva.com"
  727. )
  728. self.assertEqual(len(http_server.requests), 1)
  729. request = http_server.requests[0]
  730. self.assertEqual(request.method, b"GET")
  731. self.assertEqual(request.path, b"/foo/bar")
  732. self.assertEqual(
  733. request.requestHeaders.getRawHeaders(b"host"), [b"xn--bcher-kva.com"]
  734. )
  735. # finish the request
  736. request.finish()
  737. self.reactor.pump((0.1,))
  738. self.successResultOf(test_d)
  739. def test_idna_srv_target(self):
  740. """test the behaviour when the target of a SRV record has idna chars"""
  741. self.mock_resolver.resolve_service.side_effect = generate_resolve_service(
  742. [Server(host=b"xn--trget-3qa.com", port=8443)] # târget.com
  743. )
  744. self.reactor.lookups["xn--trget-3qa.com"] = "1.2.3.4"
  745. test_d = self._make_get_request(b"matrix://xn--bcher-kva.com/foo/bar")
  746. # Nothing happened yet
  747. self.assertNoResult(test_d)
  748. self.mock_resolver.resolve_service.assert_called_once_with(
  749. b"_matrix._tcp.xn--bcher-kva.com"
  750. )
  751. # Make sure treq is trying to connect
  752. clients = self.reactor.tcpClients
  753. self.assertEqual(len(clients), 1)
  754. (host, port, client_factory, _timeout, _bindAddress) = clients[0]
  755. self.assertEqual(host, "1.2.3.4")
  756. self.assertEqual(port, 8443)
  757. # make a test server, and wire up the client
  758. http_server = self._make_connection(
  759. client_factory, expected_sni=b"xn--bcher-kva.com"
  760. )
  761. self.assertEqual(len(http_server.requests), 1)
  762. request = http_server.requests[0]
  763. self.assertEqual(request.method, b"GET")
  764. self.assertEqual(request.path, b"/foo/bar")
  765. self.assertEqual(
  766. request.requestHeaders.getRawHeaders(b"host"), [b"xn--bcher-kva.com"]
  767. )
  768. # finish the request
  769. request.finish()
  770. self.reactor.pump((0.1,))
  771. self.successResultOf(test_d)
  772. def test_well_known_cache(self):
  773. self.reactor.lookups["testserv"] = "1.2.3.4"
  774. fetch_d = defer.ensureDeferred(
  775. self.well_known_resolver.get_well_known(b"testserv")
  776. )
  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(0)
  781. self.assertEqual(host, "1.2.3.4")
  782. self.assertEqual(port, 443)
  783. well_known_server = self._handle_well_known_connection(
  784. client_factory,
  785. expected_sni=b"testserv",
  786. response_headers={b"Cache-Control": b"max-age=1000"},
  787. content=b'{ "m.server": "target-server" }',
  788. )
  789. r = self.successResultOf(fetch_d)
  790. self.assertEqual(r.delegated_server, b"target-server")
  791. # close the tcp connection
  792. well_known_server.loseConnection()
  793. # repeat the request: it should hit the cache
  794. fetch_d = defer.ensureDeferred(
  795. self.well_known_resolver.get_well_known(b"testserv")
  796. )
  797. r = self.successResultOf(fetch_d)
  798. self.assertEqual(r.delegated_server, b"target-server")
  799. # expire the cache
  800. self.reactor.pump((1000.0,))
  801. # now it should connect again
  802. fetch_d = defer.ensureDeferred(
  803. self.well_known_resolver.get_well_known(b"testserv")
  804. )
  805. self.assertEqual(len(clients), 1)
  806. (host, port, client_factory, _timeout, _bindAddress) = clients.pop(0)
  807. self.assertEqual(host, "1.2.3.4")
  808. self.assertEqual(port, 443)
  809. self._handle_well_known_connection(
  810. client_factory,
  811. expected_sni=b"testserv",
  812. content=b'{ "m.server": "other-server" }',
  813. )
  814. r = self.successResultOf(fetch_d)
  815. self.assertEqual(r.delegated_server, b"other-server")
  816. def test_well_known_cache_with_temp_failure(self):
  817. """Test that we refetch well-known before the cache expires, and that
  818. it ignores transient errors.
  819. """
  820. self.reactor.lookups["testserv"] = "1.2.3.4"
  821. fetch_d = defer.ensureDeferred(
  822. self.well_known_resolver.get_well_known(b"testserv")
  823. )
  824. # there should be an attempt to connect on port 443 for the .well-known
  825. clients = self.reactor.tcpClients
  826. self.assertEqual(len(clients), 1)
  827. (host, port, client_factory, _timeout, _bindAddress) = clients.pop(0)
  828. self.assertEqual(host, "1.2.3.4")
  829. self.assertEqual(port, 443)
  830. well_known_server = self._handle_well_known_connection(
  831. client_factory,
  832. expected_sni=b"testserv",
  833. response_headers={b"Cache-Control": b"max-age=1000"},
  834. content=b'{ "m.server": "target-server" }',
  835. )
  836. r = self.successResultOf(fetch_d)
  837. self.assertEqual(r.delegated_server, b"target-server")
  838. # close the tcp connection
  839. well_known_server.loseConnection()
  840. # Get close to the cache expiry, this will cause the resolver to do
  841. # another lookup.
  842. self.reactor.pump((900.0,))
  843. fetch_d = defer.ensureDeferred(
  844. self.well_known_resolver.get_well_known(b"testserv")
  845. )
  846. # The resolver may retry a few times, so fonx all requests that come along
  847. attempts = 0
  848. while self.reactor.tcpClients:
  849. clients = self.reactor.tcpClients
  850. (host, port, client_factory, _timeout, _bindAddress) = clients.pop(0)
  851. attempts += 1
  852. # fonx the connection attempt, this will be treated as a temporary
  853. # failure.
  854. client_factory.clientConnectionFailed(None, Exception("nope"))
  855. # There's a few sleeps involved, so we have to pump the reactor a
  856. # bit.
  857. self.reactor.pump((1.0, 1.0))
  858. # We expect to see more than one attempt as there was previously a valid
  859. # well known.
  860. self.assertGreater(attempts, 1)
  861. # Resolver should return cached value, despite the lookup failing.
  862. r = self.successResultOf(fetch_d)
  863. self.assertEqual(r.delegated_server, b"target-server")
  864. # Expire both caches and repeat the request
  865. self.reactor.pump((10000.0,))
  866. # Repeat the request, this time it should fail if the lookup fails.
  867. fetch_d = defer.ensureDeferred(
  868. self.well_known_resolver.get_well_known(b"testserv")
  869. )
  870. clients = self.reactor.tcpClients
  871. (host, port, client_factory, _timeout, _bindAddress) = clients.pop(0)
  872. client_factory.clientConnectionFailed(None, Exception("nope"))
  873. self.reactor.pump((0.4,))
  874. r = self.successResultOf(fetch_d)
  875. self.assertEqual(r.delegated_server, None)
  876. def test_well_known_too_large(self):
  877. """A well-known query that returns a result which is too large should be rejected."""
  878. self.reactor.lookups["testserv"] = "1.2.3.4"
  879. fetch_d = defer.ensureDeferred(
  880. self.well_known_resolver.get_well_known(b"testserv")
  881. )
  882. # there should be an attempt to connect on port 443 for the .well-known
  883. clients = self.reactor.tcpClients
  884. self.assertEqual(len(clients), 1)
  885. (host, port, client_factory, _timeout, _bindAddress) = clients.pop(0)
  886. self.assertEqual(host, "1.2.3.4")
  887. self.assertEqual(port, 443)
  888. self._handle_well_known_connection(
  889. client_factory,
  890. expected_sni=b"testserv",
  891. response_headers={b"Cache-Control": b"max-age=1000"},
  892. content=b'{ "m.server": "' + (b"a" * WELL_KNOWN_MAX_SIZE) + b'" }',
  893. )
  894. # The result is successful, but disabled delegation.
  895. r = self.successResultOf(fetch_d)
  896. self.assertIsNone(r.delegated_server)
  897. def test_srv_fallbacks(self):
  898. """Test that other SRV results are tried if the first one fails."""
  899. self.mock_resolver.resolve_service.side_effect = generate_resolve_service(
  900. [
  901. Server(host=b"target.com", port=8443),
  902. Server(host=b"target.com", port=8444),
  903. ]
  904. )
  905. self.reactor.lookups["target.com"] = "1.2.3.4"
  906. test_d = self._make_get_request(b"matrix://testserv/foo/bar")
  907. # Nothing happened yet
  908. self.assertNoResult(test_d)
  909. self.mock_resolver.resolve_service.assert_called_once_with(
  910. b"_matrix._tcp.testserv"
  911. )
  912. # We should see an attempt to connect to the first server
  913. clients = self.reactor.tcpClients
  914. self.assertEqual(len(clients), 1)
  915. (host, port, client_factory, _timeout, _bindAddress) = clients.pop(0)
  916. self.assertEqual(host, "1.2.3.4")
  917. self.assertEqual(port, 8443)
  918. # Fonx the connection
  919. client_factory.clientConnectionFailed(None, Exception("nope"))
  920. # There's a 300ms delay in HostnameEndpoint
  921. self.reactor.pump((0.4,))
  922. # Hasn't failed yet
  923. self.assertNoResult(test_d)
  924. # We shouldnow see an attempt to connect to the second server
  925. clients = self.reactor.tcpClients
  926. self.assertEqual(len(clients), 1)
  927. (host, port, client_factory, _timeout, _bindAddress) = clients.pop(0)
  928. self.assertEqual(host, "1.2.3.4")
  929. self.assertEqual(port, 8444)
  930. # make a test server, and wire up the client
  931. http_server = self._make_connection(client_factory, expected_sni=b"testserv")
  932. self.assertEqual(len(http_server.requests), 1)
  933. request = http_server.requests[0]
  934. self.assertEqual(request.method, b"GET")
  935. self.assertEqual(request.path, b"/foo/bar")
  936. self.assertEqual(request.requestHeaders.getRawHeaders(b"host"), [b"testserv"])
  937. # finish the request
  938. request.finish()
  939. self.reactor.pump((0.1,))
  940. self.successResultOf(test_d)
  941. class TestCachePeriodFromHeaders(unittest.TestCase):
  942. def test_cache_control(self):
  943. # uppercase
  944. self.assertEqual(
  945. _cache_period_from_headers(
  946. Headers({b"Cache-Control": [b"foo, Max-Age = 100, bar"]})
  947. ),
  948. 100,
  949. )
  950. # missing value
  951. self.assertIsNone(
  952. _cache_period_from_headers(Headers({b"Cache-Control": [b"max-age=, bar"]}))
  953. )
  954. # hackernews: bogus due to semicolon
  955. self.assertIsNone(
  956. _cache_period_from_headers(
  957. Headers({b"Cache-Control": [b"private; max-age=0"]})
  958. )
  959. )
  960. # github
  961. self.assertEqual(
  962. _cache_period_from_headers(
  963. Headers({b"Cache-Control": [b"max-age=0, private, must-revalidate"]})
  964. ),
  965. 0,
  966. )
  967. # google
  968. self.assertEqual(
  969. _cache_period_from_headers(
  970. Headers({b"cache-control": [b"private, max-age=0"]})
  971. ),
  972. 0,
  973. )
  974. def test_expires(self):
  975. self.assertEqual(
  976. _cache_period_from_headers(
  977. Headers({b"Expires": [b"Wed, 30 Jan 2019 07:35:33 GMT"]}),
  978. time_now=lambda: 1548833700,
  979. ),
  980. 33,
  981. )
  982. # cache-control overrides expires
  983. self.assertEqual(
  984. _cache_period_from_headers(
  985. Headers(
  986. {
  987. b"cache-control": [b"max-age=10"],
  988. b"Expires": [b"Wed, 30 Jan 2019 07:35:33 GMT"],
  989. }
  990. ),
  991. time_now=lambda: 1548833700,
  992. ),
  993. 10,
  994. )
  995. # invalid expires means immediate expiry
  996. self.assertEqual(_cache_period_from_headers(Headers({b"Expires": [b"0"]})), 0)
  997. def _check_logcontext(context):
  998. current = current_context()
  999. if current is not context:
  1000. raise AssertionError("Expected logcontext %s but was %s" % (context, current))
  1001. def _build_test_server(connection_creator):
  1002. """Construct a test server
  1003. This builds an HTTP channel, wrapped with a TLSMemoryBIOProtocol
  1004. Args:
  1005. connection_creator (IOpenSSLServerConnectionCreator): thing to build
  1006. SSL connections
  1007. sanlist (list[bytes]): list of the SAN entries for the cert returned
  1008. by the server
  1009. Returns:
  1010. TLSMemoryBIOProtocol
  1011. """
  1012. server_factory = Factory.forProtocol(HTTPChannel)
  1013. # Request.finish expects the factory to have a 'log' method.
  1014. server_factory.log = _log_request
  1015. server_tls_factory = TLSMemoryBIOFactory(
  1016. connection_creator, isClient=False, wrappedFactory=server_factory
  1017. )
  1018. return server_tls_factory.buildProtocol(None)
  1019. def _log_request(request):
  1020. """Implements Factory.log, which is expected by Request.finish"""
  1021. logger.info("Completed request %s", request)
  1022. @implementer(IPolicyForHTTPS)
  1023. class TrustingTLSPolicyForHTTPS:
  1024. """An IPolicyForHTTPS which checks that the certificate belongs to the
  1025. right server, but doesn't check the certificate chain."""
  1026. def creatorForNetloc(self, hostname, port):
  1027. certificateOptions = OpenSSLCertificateOptions()
  1028. return ClientTLSOptions(hostname, certificateOptions.getContext())