summary refs log tree commit diff
diff options
context:
space:
mode:
-rwxr-xr-xsynapse/app/homeserver.py4
-rw-r--r--synapse/handlers/directory.py4
-rw-r--r--synapse/handlers/login.py6
-rw-r--r--synapse/handlers/register.py11
-rw-r--r--synapse/http/client.py290
-rw-r--r--tests/handlers/test_directory.py4
6 files changed, 163 insertions, 156 deletions
diff --git a/synapse/app/homeserver.py b/synapse/app/homeserver.py
index 2f1b954902..61d574a00f 100755
--- a/synapse/app/homeserver.py
+++ b/synapse/app/homeserver.py
@@ -25,7 +25,7 @@ from twisted.web.static import File
 from twisted.web.server import Site
 from synapse.http.server import JsonResource, RootRedirect
 from synapse.http.content_repository import ContentRepoResource
-from synapse.http.client import TwistedHttpClient
+from synapse.http.client import MatrixHttpClient
 from synapse.api.urls import (
     CLIENT_PREFIX, FEDERATION_PREFIX, WEB_CLIENT_PREFIX, CONTENT_REPO_PREFIX
 )
@@ -47,7 +47,7 @@ logger = logging.getLogger(__name__)
 class SynapseHomeServer(HomeServer):
 
     def build_http_client(self):
-        return TwistedHttpClient(self)
+        return MatrixHttpClient(self)
 
     def build_resource_for_client(self):
         return JsonResource()
diff --git a/synapse/handlers/directory.py b/synapse/handlers/directory.py
index 84c3a1d56f..cec7737e09 100644
--- a/synapse/handlers/directory.py
+++ b/synapse/handlers/directory.py
@@ -18,7 +18,7 @@ from twisted.internet import defer
 from ._base import BaseHandler
 
 from synapse.api.errors import SynapseError
-from synapse.http.client import HttpClient
+from synapse.http.client import MatrixHttpClient
 from synapse.api.events.room import RoomAliasesEvent
 
 import logging
@@ -98,7 +98,7 @@ class DirectoryHandler(BaseHandler):
                 query_type="directory",
                 args={
                     "room_alias": room_alias.to_string(),
-                    HttpClient.RETRY_DNS_LOOKUP_FAILURES: False
+                    MatrixHttpClient.RETRY_DNS_LOOKUP_FAILURES: False
                 }
             )
 
diff --git a/synapse/handlers/login.py b/synapse/handlers/login.py
index 80ffdd2726..3f152e18f0 100644
--- a/synapse/handlers/login.py
+++ b/synapse/handlers/login.py
@@ -17,7 +17,7 @@ from twisted.internet import defer
 
 from ._base import BaseHandler
 from synapse.api.errors import LoginError, Codes
-from synapse.http.client import PlainHttpClient
+from synapse.http.client import IdentityServerHttpClient
 from synapse.util.emailutils import EmailException
 import synapse.util.emailutils as emailutils
 
@@ -97,10 +97,10 @@ class LoginHandler(BaseHandler):
 
     @defer.inlineCallbacks
     def _query_email(self, email):
-        httpCli = PlainHttpClient(self.hs)
+        httpCli = IdentityServerHttpClient(self.hs)
         data = yield httpCli.get_json(
             'matrix.org:8090',  # TODO FIXME This should be configurable.
             "/_matrix/identity/api/v1/lookup?medium=email&address=" +
             "%s" % urllib.quote(email)
         )
-        defer.returnValue(data)
\ No newline at end of file
+        defer.returnValue(data)
diff --git a/synapse/handlers/register.py b/synapse/handlers/register.py
index a019d770d4..266495056e 100644
--- a/synapse/handlers/register.py
+++ b/synapse/handlers/register.py
@@ -22,7 +22,8 @@ from synapse.api.errors import (
 )
 from ._base import BaseHandler
 import synapse.util.stringutils as stringutils
-from synapse.http.client import PlainHttpClient
+from synapse.http.client import IdentityServerHttpClient
+from synapse.http.client import CaptchaServerHttpClient
 
 import base64
 import bcrypt
@@ -154,7 +155,9 @@ class RegistrationHandler(BaseHandler):
 
     @defer.inlineCallbacks
     def _threepid_from_creds(self, creds):
-        httpCli = PlainHttpClient(self.hs)
+        # TODO: get this from the homeserver rather than creating a new one for
+        # each request
+        httpCli = IdentityServerHttpClient(self.hs)
         # XXX: make this configurable!
         trustedIdServers = ['matrix.org:8090']
         if not creds['idServer'] in trustedIdServers:
@@ -203,7 +206,9 @@ class RegistrationHandler(BaseHandler):
 
     @defer.inlineCallbacks
     def _submit_captcha(self, ip_addr, private_key, challenge, response):
-        client = PlainHttpClient(self.hs)
+        # TODO: get this from the homeserver rather than creating a new one for
+        # each request
+        client = CaptchaServerHttpClient(self.hs)
         data = yield client.post_urlencoded_get_raw(
             "www.google.com:80",
             "/recaptcha/api/verify",
diff --git a/synapse/http/client.py b/synapse/http/client.py
index 822afeec1d..e02cce5642 100644
--- a/synapse/http/client.py
+++ b/synapse/http/client.py
@@ -36,49 +36,6 @@ import urllib
 logger = logging.getLogger(__name__)
 
 
-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
-
-        Args:
-            destination (str): The remote server to send the HTTP request
-                to.
-            path (str): The HTTP path.
-            data (dict): A dict containing the data that will be used as
-                the request body. This will be encoded as JSON.
-
-        Returns:
-            Deferred: Succeeds when we get a 2xx HTTP response. The result
-            will be the decoded JSON body. On a 4xx or 5xx error response a
-            CodeMessageException is raised.
-        """
-        pass
-
-    def get_json(self, destination, path, args=None):
-        """ Get's some json from the given host homeserver and path
-
-        Args:
-            destination (str): The remote server to send the HTTP request
-                to.
-            path (str): The HTTP path.
-            args (dict): A dictionary used to create query strings, defaults to
-                None.
-                **Note**: The value of each key is assumed to be an iterable
-                and *not* a string.
-
-        Returns:
-            Deferred: Succeeds when we get *any* HTTP response.
-
-            The result of the deferred is a tuple of `(code, response)`,
-            where `response` is a dict representing the decoded JSON body.
-        """
-        pass
-
-
 class MatrixHttpAgent(_AgentBase):
 
     def __init__(self, reactor, pool=None):
@@ -102,23 +59,114 @@ class MatrixHttpAgent(_AgentBase):
                                          parsed_URI.originForm)
 
 
-class TwistedHttpClient(HttpClient):
-    """ Wrapper around the twisted HTTP client api.
+class BaseHttpClient(object):
+    """Base class for HTTP clients using twisted.
+    """
+
+    def __init__(self, hs):
+        self.agent = MatrixHttpAgent(reactor)
+        self.hs = hs
+
+    @defer.inlineCallbacks
+    def _create_request(self, destination, method, path_bytes, param_bytes=b"",
+                        query_bytes=b"", producer=None, headers_dict={},
+                        retry_on_dns_fail=True, on_send_callback=None):
+        """ Creates and sends a request to the given url
+        """
+        headers_dict[b"User-Agent"] = [b"Synapse"]
+        headers_dict[b"Host"] = [destination]
+
+        logger.debug("Sending request to %s: %s %s;%s?%s",
+                     destination, method, path_bytes, param_bytes, query_bytes)
+
+        logger.debug(
+            "Types: %s",
+            [
+                type(destination), type(method), type(path_bytes),
+                type(param_bytes),
+                type(query_bytes)
+            ]
+        )
+
+        retries_left = 5
+
+        endpoint = self._getEndpoint(reactor, destination);
+
+        while True:
+            if on_send_callback:
+                on_send_callback(destination, method, path_bytes, producer)
+
+            try:
+                response = yield self.agent.request(
+                    destination,
+                    endpoint,
+                    method,
+                    path_bytes,
+                    param_bytes,
+                    query_bytes,
+                    Headers(headers_dict),
+                    producer
+                )
+
+                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)
+
+                if retries_left:
+                    yield sleep(2 ** (5 - retries_left))
+                    retries_left -= 1
+                else:
+                    raise
+
+        if 200 <= response.code < 300:
+            # We need to update the transactions table to say it was sent?
+            pass
+        else:
+            # :'(
+            # Update transactions table?
+            logger.error(
+                "Got response %d %s", response.code, response.phrase
+            )
+            raise CodeMessageException(
+                response.code, response.phrase
+            )
+
+        defer.returnValue(response)
+
+
+class MatrixHttpClient(BaseHttpClient):
+    """ Wrapper around the twisted HTTP client api. Implements 
 
     Attributes:
         agent (twisted.web.client.Agent): The twisted Agent used to send the
             requests.
     """
 
-    def __init__(self, hs):
-        self.agent = MatrixHttpAgent(reactor)
-        self.hs = hs
+    RETRY_DNS_LOOKUP_FAILURES = "__retry_dns"
 
     @defer.inlineCallbacks
     def put_json(self, destination, path, data, on_send_callback=None):
-        if destination in _destination_mappings:
-            destination = _destination_mappings[destination]
+        """ Sends the specifed json data using PUT
 
+        Args:
+            destination (str): The remote server to send the HTTP request
+                to.
+            path (str): The HTTP path.
+            data (dict): A dict containing the data that will be used as
+                the request body. This will be encoded as JSON.
+
+        Returns:
+            Deferred: Succeeds when we get a 2xx HTTP response. The result
+            will be the decoded JSON body. On a 4xx or 5xx error response a
+            CodeMessageException is raised.
+        """
         response = yield self._create_request(
             destination.encode("ascii"),
             "PUT",
@@ -136,9 +184,23 @@ class TwistedHttpClient(HttpClient):
 
     @defer.inlineCallbacks
     def get_json(self, destination, path, args={}):
-        if destination in _destination_mappings:
-            destination = _destination_mappings[destination]
+        """ Get's some json from the given host homeserver and path
+
+        Args:
+            destination (str): The remote server to send the HTTP request
+                to.
+            path (str): The HTTP path.
+            args (dict): A dictionary used to create query strings, defaults to
+                None.
+                **Note**: The value of each key is assumed to be an iterable
+                and *not* a string.
+
+        Returns:
+            Deferred: Succeeds when we get *any* HTTP response.
 
+            The result of the deferred is a tuple of `(code, response)`,
+            where `response` is a dict representing the decoded JSON body.
+        """
         logger.debug("get_json args: %s", args)
 
         retry_on_dns_fail = True
@@ -163,6 +225,22 @@ class TwistedHttpClient(HttpClient):
 
         defer.returnValue(json.loads(body))
 
+
+    def _getEndpoint(self, reactor, destination):
+        return matrix_endpoint(
+            reactor, destination, timeout=10,
+            ssl_context_factory=self.hs.tls_context_factory
+        )
+
+
+class IdentityServerHttpClient(BaseHttpClient):
+    """Separate HTTP client for talking to the Identity servers since they
+    don't use SRV records and talk x-www-form-urlencoded rather than JSON.
+    """
+    def _getEndpoint(self, reactor, destination):
+        #TODO: This should be talking TLS
+        return matrix_endpoint(reactor, destination, timeout=10)
+
     @defer.inlineCallbacks
     def post_urlencoded_get_json(self, destination, path, args={}):
         if destination in _destination_mappings:
@@ -176,16 +254,25 @@ class TwistedHttpClient(HttpClient):
             "POST",
             path.encode("ascii"),
             producer=FileBodyProducer(StringIO(urllib.urlencode(args))),
-            headers_dict={"Content-Type": ["application/x-www-form-urlencoded"]}
+            headers_dict={
+                "Content-Type": ["application/x-www-form-urlencoded"]
+            }
         )
 
         body = yield readBody(response)
 
         defer.returnValue(json.loads(body))
-        
-    # XXX FIXME : I'm so sorry.
+
+
+class CaptchaServerHttpClient(MatrixHttpClient):
+    """Separate HTTP client for talking to google's captcha servers"""
+
+    def _getEndpoint(self, reactor, destination):
+        return matrix_endpoint(reactor, destination, timeout=10)
+
     @defer.inlineCallbacks
-    def post_urlencoded_get_raw(self, destination, path, accept_partial=False, args={}):
+    def post_urlencoded_get_raw(self, destination, path, accept_partial=False,
+                                args={}):
         if destination in _destination_mappings:
             destination = _destination_mappings[destination]
 
@@ -196,7 +283,9 @@ class TwistedHttpClient(HttpClient):
             "POST",
             path.encode("ascii"),
             producer=FileBodyProducer(StringIO(urllib.urlencode(args))),
-            headers_dict={"Content-Type": ["application/x-www-form-urlencoded"]}
+            headers_dict={
+                "Content-Type": ["application/x-www-form-urlencoded"]
+            }
         )
 
         try:
@@ -207,93 +296,6 @@ class TwistedHttpClient(HttpClient):
                 defer.returnValue(e.response)
             else:
                 raise e
-        
-
-    @defer.inlineCallbacks
-    def _create_request(self, destination, method, path_bytes, param_bytes=b"",
-                        query_bytes=b"", producer=None, headers_dict={},
-                        retry_on_dns_fail=True, on_send_callback=None):
-        """ Creates and sends a request to the given url
-        """
-        headers_dict[b"User-Agent"] = [b"Synapse"]
-        headers_dict[b"Host"] = [destination]
-
-        logger.debug("Sending request to %s: %s %s;%s?%s",
-                     destination, method, path_bytes, param_bytes, query_bytes)
-
-        logger.debug(
-            "Types: %s",
-            [
-                type(destination), type(method), type(path_bytes),
-                type(param_bytes),
-                type(query_bytes)
-            ]
-        )
-
-        retries_left = 5
-
-        # TODO: setup and pass in an ssl_context to enable TLS
-        endpoint = self._getEndpoint(reactor, destination);
-
-        while True:
-            if on_send_callback:
-                on_send_callback(destination, method, path_bytes, producer)
-
-            try:
-                response = yield self.agent.request(
-                    destination,
-                    endpoint,
-                    method,
-                    path_bytes,
-                    param_bytes,
-                    query_bytes,
-                    Headers(headers_dict),
-                    producer
-                )
-
-                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)
-
-                if retries_left:
-                    yield sleep(2 ** (5 - retries_left))
-                    retries_left -= 1
-                else:
-                    raise
-
-        if 200 <= response.code < 300:
-            # We need to update the transactions table to say it was sent?
-            pass
-        else:
-            # :'(
-            # Update transactions table?
-            logger.error(
-                "Got response %d %s", response.code, response.phrase
-            )
-            raise CodeMessageException(
-                response.code, response.phrase
-            )
-
-        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:
diff --git a/tests/handlers/test_directory.py b/tests/handlers/test_directory.py
index dd5d85dde6..0c31502dd4 100644
--- a/tests/handlers/test_directory.py
+++ b/tests/handlers/test_directory.py
@@ -20,7 +20,7 @@ from twisted.internet import defer
 from mock import Mock
 
 from synapse.server import HomeServer
-from synapse.http.client import HttpClient
+from synapse.http.client import MatrixHttpClient
 from synapse.handlers.directory import DirectoryHandler
 from synapse.storage.directory import RoomAliasMapping
 
@@ -95,7 +95,7 @@ class DirectoryTestCase(unittest.TestCase):
             query_type="directory",
             args={
                 "room_alias": "#another:remote",
-                HttpClient.RETRY_DNS_LOOKUP_FAILURES: False
+                MatrixHttpClient.RETRY_DNS_LOOKUP_FAILURES: False
             }
         )