diff options
Diffstat (limited to 'synapse/http/client.py')
-rw-r--r-- | synapse/http/client.py | 66 |
1 files changed, 57 insertions, 9 deletions
diff --git a/synapse/http/client.py b/synapse/http/client.py index 093bdf0e3f..ebf1aa47c4 100644 --- a/synapse/http/client.py +++ b/synapse/http/client.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright 2014 matrix.org +# Copyright 2014 OpenMarket Ltd # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,7 +15,8 @@ from twisted.internet import defer, reactor -from twisted.web.client import _AgentBase, _URI, readBody +from twisted.internet.error import DNSLookupError +from twisted.web.client import _AgentBase, _URI, readBody, FileBodyProducer from twisted.web.http_headers import Headers from synapse.http.endpoint import matrix_endpoint @@ -23,7 +24,9 @@ from synapse.util.async import sleep from syutil.jsonutil import encode_canonical_json -from synapse.api.errors import CodeMessageException +from synapse.api.errors import CodeMessageException, SynapseError + +from StringIO import StringIO import json import logging @@ -43,6 +46,7 @@ _destination_mappings = { class HttpClient(object): """ Interface for talking json over http """ + RETRY_DNS_LOOKUP_FAILURES = "__retry_dns" def put_json(self, destination, path, data): """ Sends the specifed json data using PUT @@ -142,13 +146,43 @@ class TwistedHttpClient(HttpClient): destination = _destination_mappings[destination] logger.debug("get_json args: %s", args) + + retry_on_dns_fail = True + if HttpClient.RETRY_DNS_LOOKUP_FAILURES in args: + # FIXME: This isn't ideal, but the interface exposed in get_json + # isn't comprehensive enough to give caller's any control over + # their connection mechanics. + retry_on_dns_fail = args.pop(HttpClient.RETRY_DNS_LOOKUP_FAILURES) + query_bytes = urllib.urlencode(args, True) + logger.debug("Query bytes: %s Retry DNS: %s", args, retry_on_dns_fail) response = yield self._create_request( destination.encode("ascii"), "GET", path.encode("ascii"), - query_bytes=query_bytes + query_bytes=query_bytes, + retry_on_dns_fail=retry_on_dns_fail + ) + + body = yield readBody(response) + + defer.returnValue(json.loads(body)) + + @defer.inlineCallbacks + def post_urlencoded_get_json(self, destination, path, args={}): + if destination in _destination_mappings: + destination = _destination_mappings[destination] + + logger.debug("post_urlencoded_get_json args: %s", args) + query_bytes = urllib.urlencode(args, True) + + response = yield self._create_request( + destination.encode("ascii"), + "POST", + path.encode("ascii"), + producer=FileBodyProducer(StringIO(urllib.urlencode(args))), + headers_dict={"Content-Type": ["application/x-www-form-urlencoded"]} ) body = yield readBody(response) @@ -157,7 +191,8 @@ class TwistedHttpClient(HttpClient): @defer.inlineCallbacks def _create_request(self, destination, method, path_bytes, param_bytes=b"", - query_bytes=b"", producer=None, headers_dict={}): + query_bytes=b"", producer=None, headers_dict={}, + retry_on_dns_fail=True): """ Creates and sends a request to the given url """ headers_dict[b"User-Agent"] = [b"Synapse"] @@ -178,10 +213,7 @@ class TwistedHttpClient(HttpClient): retries_left = 5 # TODO: setup and pass in an ssl_context to enable TLS - endpoint = matrix_endpoint( - reactor, destination, timeout=10, - ssl_context_factory=self.hs.tls_context_factory - ) + endpoint = self._getEndpoint(reactor, destination); while True: try: @@ -199,6 +231,11 @@ class TwistedHttpClient(HttpClient): logger.debug("Got response to %s", method) break except Exception as e: + if not retry_on_dns_fail and isinstance(e, DNSLookupError): + logger.warn("DNS Lookup failed to %s with %s", destination, + e) + raise SynapseError(400, "Domain specified not found.") + logger.exception("Got error in _create_request") _print_ex(e) @@ -223,6 +260,17 @@ class TwistedHttpClient(HttpClient): defer.returnValue(response) + def _getEndpoint(self, reactor, destination): + return matrix_endpoint( + reactor, destination, timeout=10, + ssl_context_factory=self.hs.tls_context_factory + ) + + +class PlainHttpClient(TwistedHttpClient): + def _getEndpoint(self, reactor, destination): + return matrix_endpoint(reactor, destination, timeout=10) + def _print_ex(e): if hasattr(e, "reasons") and e.reasons: |