Beispiel #1
0
    def connect_any_redis_attempts(self):
        """If redis is enabled we need to deal with workers connecting to a
        redis server. We don't want to use a real Redis server so we use a
        fake one.
        """
        clients = self.reactor.tcpClients
        self.assertEqual(len(clients), 1)
        (host, port, client_factory, _timeout, _bindAddress) = clients.pop(0)
        self.assertEqual(host, "localhost")
        self.assertEqual(port, 6379)

        client_protocol = client_factory.buildProtocol(None)
        server_protocol = self._redis_server.buildProtocol(None)

        client_to_server_transport = FakeTransport(server_protocol,
                                                   self.reactor,
                                                   client_protocol)
        client_protocol.makeConnection(client_to_server_transport)

        server_to_client_transport = FakeTransport(client_protocol,
                                                   self.reactor,
                                                   server_protocol)
        server_protocol.makeConnection(server_to_client_transport)

        return client_to_server_transport, server_to_client_transport
Beispiel #2
0
    def test_overlong_title(self):
        self.lookups["matrix.org"] = [(IPv4Address, "10.1.2.3")]

        end_content = (b"<html><head>"
                       b"<title>" + b"x" * 2000 + b"</title>"
                       b'<meta property="og:description" content="hi" />'
                       b"</head></html>")

        channel = self.make_request(
            "GET",
            "preview_url?url=http://matrix.org",
            shorthand=False,
            await_result=False,
        )
        self.pump()

        client = self.reactor.tcpClients[0][2].buildProtocol(None)
        server = AccumulatingProtocol()
        server.makeConnection(FakeTransport(client, self.reactor))
        client.makeConnection(FakeTransport(server, self.reactor))
        client.dataReceived(
            (b"HTTP/1.0 200 OK\r\nContent-Length: %d\r\n"
             b'Content-Type: text/html; charset="windows-1251"\r\n\r\n') %
            (len(end_content), ) + end_content)

        self.pump()
        self.assertEqual(channel.code, 200)
        res = channel.json_body
        # We should only see the `og:description` field, as `title` is too long and should be stripped out
        self.assertCountEqual(["og:description"], res.keys())
Beispiel #3
0
    def test_nonexistent_image(self) -> None:
        """If the preview image doesn't exist, ensure some data is returned."""
        self.lookups["matrix.org"] = [(IPv4Address, "10.1.2.3")]

        end_content = (
            b"""<html><body><img src="http://cdn.matrix.org/foo.jpg"></body></html>"""
        )

        channel = self.make_request(
            "GET",
            "preview_url?url=http://matrix.org",
            shorthand=False,
            await_result=False,
        )
        self.pump()

        client = self.reactor.tcpClients[0][2].buildProtocol(None)
        server = AccumulatingProtocol()
        server.makeConnection(FakeTransport(client, self.reactor))
        client.makeConnection(FakeTransport(server, self.reactor))
        client.dataReceived(
            (b"HTTP/1.0 200 OK\r\nContent-Length: %d\r\n"
             b'Content-Type: text/html; charset="utf8"\r\n\r\n') %
            (len(end_content), ) + end_content)

        self.pump()
        self.assertEqual(channel.code, 200)

        # The image should not be in the result.
        self.assertNotIn("og:image", channel.json_body)
Beispiel #4
0
    def test_inline_data_url(self) -> None:
        """
        An inline image (as a data URL) should be parsed properly.
        """
        self.lookups["matrix.org"] = [(IPv4Address, "10.1.2.3")]

        data = base64.b64encode(SMALL_PNG)

        end_content = (b"<html><head>"
                       b'<img src="data:image/png;base64,%s" />'
                       b"</head></html>") % (data, )

        channel = self.make_request(
            "GET",
            "preview_url?url=http://matrix.org",
            shorthand=False,
            await_result=False,
        )
        self.pump()

        client = self.reactor.tcpClients[0][2].buildProtocol(None)
        server = AccumulatingProtocol()
        server.makeConnection(FakeTransport(client, self.reactor))
        client.makeConnection(FakeTransport(server, self.reactor))
        client.dataReceived(
            (b"HTTP/1.0 200 OK\r\nContent-Length: %d\r\n"
             b'Content-Type: text/html; charset="utf8"\r\n\r\n') %
            (len(end_content), ) + end_content)

        self.pump()
        self.assertEqual(channel.code, 200)
        self._assert_small_png(channel.json_body)
Beispiel #5
0
    def _handle_http_replication_attempt(self, hs, repl_port):
        """Handles a connection attempt to the given HS replication HTTP
        listener on the given port.
        """

        # We should have at least one outbound connection attempt, where the
        # last is one to the HTTP repication IP/port.
        clients = self.reactor.tcpClients
        self.assertGreaterEqual(len(clients), 1)
        (host, port, client_factory, _timeout, _bindAddress) = clients.pop()
        self.assertEqual(host, "1.2.3.4")
        self.assertEqual(port, repl_port)

        # Set up client side protocol
        client_protocol = client_factory.buildProtocol(None)

        request_factory = OneShotRequestFactory()

        # Set up the server side protocol
        channel = _PushHTTPChannel(self.reactor)
        channel.requestFactory = request_factory
        channel.site = self._hs_to_site[hs]

        # Connect client to server and vice versa.
        client_to_server_transport = FakeTransport(channel, self.reactor,
                                                   client_protocol)
        client_protocol.makeConnection(client_to_server_transport)

        server_to_client_transport = FakeTransport(client_protocol,
                                                   self.reactor, channel)
        channel.makeConnection(server_to_client_transport)
Beispiel #6
0
    def test_audio_rejected(self) -> None:
        self.lookups["matrix.org"] = [(IPv4Address, "10.1.2.3")]

        end_content = b"anything"

        channel = self.make_request(
            "GET",
            "preview_url?url=http://matrix.org",
            shorthand=False,
            await_result=False,
        )
        self.pump()

        client = self.reactor.tcpClients[0][2].buildProtocol(None)
        server = AccumulatingProtocol()
        server.makeConnection(FakeTransport(client, self.reactor))
        client.makeConnection(FakeTransport(server, self.reactor))
        client.dataReceived((b"HTTP/1.0 200 OK\r\nContent-Length: %d\r\n"
                             b"Content-Type: audio/aac\r\n\r\n") %
                            (len(end_content)) + end_content)

        self.pump()
        self.assertEqual(channel.code, 502)
        self.assertEqual(
            channel.json_body,
            {
                "errcode":
                "M_UNKNOWN",
                "error":
                "Requested file's content type not allowed for this operation: audio/aac",
            },
        )
Beispiel #7
0
    def prepare(self, reactor, clock, hs):

        self.master_store = self.hs.get_datastore()
        self.storage = hs.get_storage()
        self.slaved_store = self.STORE_TYPE(Database(hs),
                                            self.hs.get_db_conn(), self.hs)
        self.event_id = 0

        server_factory = ReplicationStreamProtocolFactory(self.hs)
        self.streamer = server_factory.streamer

        handler_factory = Mock()
        self.replication_handler = ReplicationClientHandler(self.slaved_store)
        self.replication_handler.factory = handler_factory

        client_factory = ReplicationClientFactory(self.hs, "client_name",
                                                  self.replication_handler)

        server = server_factory.buildProtocol(None)
        client = client_factory.buildProtocol(None)

        client.makeConnection(FakeTransport(server, reactor))

        self.server_to_client_transport = FakeTransport(client, reactor)
        server.makeConnection(self.server_to_client_transport)
Beispiel #8
0
    def test_non_ascii_preview_httpequiv(self):
        self.lookups["matrix.org"] = [(IPv4Address, "8.8.8.8")]

        end_content = (
            b'<html><head>'
            b'<meta http-equiv="Content-Type" content="text/html; charset=windows-1251"/>'
            b'<meta property="og:title" content="\xe4\xea\xe0" />'
            b'<meta property="og:description" content="hi" />'
            b'</head></html>')

        request, channel = self.make_request(
            "GET", "url_preview?url=http://matrix.org", shorthand=False)
        request.render(self.preview_url)
        self.pump()

        client = self.reactor.tcpClients[0][2].buildProtocol(None)
        server = AccumulatingProtocol()
        server.makeConnection(FakeTransport(client, self.reactor))
        client.makeConnection(FakeTransport(server, self.reactor))
        client.dataReceived(
            (b"HTTP/1.0 200 OK\r\nContent-Length: %d\r\n"
             b"Content-Type: text/html; charset=\"utf8\"\r\n\r\n") %
            (len(end_content), ) + end_content)

        self.pump()
        self.assertEqual(channel.code, 200)
        self.assertEqual(channel.json_body["og:title"], u"\u0434\u043a\u0430")
    def test_blacklisted_ip_range_whitelisted_ip(self):
        """
        Blacklisted but then subsequently whitelisted IP addresses can be
        spidered.
        """
        self.lookups["example.com"] = [(IPv4Address, "1.1.1.1")]

        channel = self.make_request(
            "GET",
            "preview_url?url=http://example.com",
            shorthand=False,
            await_result=False,
        )
        self.pump()

        client = self.reactor.tcpClients[0][2].buildProtocol(None)

        server = AccumulatingProtocol()
        server.makeConnection(FakeTransport(client, self.reactor))
        client.makeConnection(FakeTransport(server, self.reactor))

        client.dataReceived(
            b"HTTP/1.0 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n"
            % (len(self.end_content),)
            + self.end_content
        )

        self.pump()
        self.assertEqual(channel.code, 200)
        self.assertEqual(
            channel.json_body, {"og:title": "~matrix~", "og:description": "hi"}
        )
    def test_non_ascii_preview_content_type(self):
        self.lookups["matrix.org"] = [(IPv4Address, "10.1.2.3")]

        end_content = (
            b"<html><head>"
            b'<meta property="og:title" content="\xe4\xea\xe0" />'
            b'<meta property="og:description" content="hi" />'
            b"</head></html>"
        )

        channel = self.make_request(
            "GET",
            "preview_url?url=http://matrix.org",
            shorthand=False,
            await_result=False,
        )
        self.pump()

        client = self.reactor.tcpClients[0][2].buildProtocol(None)
        server = AccumulatingProtocol()
        server.makeConnection(FakeTransport(client, self.reactor))
        client.makeConnection(FakeTransport(server, self.reactor))
        client.dataReceived(
            (
                b"HTTP/1.0 200 OK\r\nContent-Length: %d\r\n"
                b'Content-Type: text/html; charset="windows-1251"\r\n\r\n'
            )
            % (len(end_content),)
            + end_content
        )

        self.pump()
        self.assertEqual(channel.code, 200)
        self.assertEqual(channel.json_body["og:title"], "\u0434\u043a\u0430")
Beispiel #11
0
    def prepare(self, reactor, clock, hs):

        db_config = hs.config.database.get_single_database()
        self.master_store = self.hs.get_datastore()
        self.storage = hs.get_storage()
        database = hs.get_datastores().databases[0]
        self.slaved_store = self.STORE_TYPE(
            database, make_conn(db_config, database.engine), self.hs)
        self.event_id = 0

        server_factory = ReplicationStreamProtocolFactory(self.hs)
        self.streamer = hs.get_replication_streamer()

        # We now do some gut wrenching so that we have a client that is based
        # off of the slave store rather than the main store.
        self.replication_handler = ReplicationCommandHandler(self.hs)
        self.replication_handler._instance_name = "worker"
        self.replication_handler._replication_data_handler = ReplicationDataHandler(
            self.slaved_store)

        client_factory = DirectTcpReplicationClientFactory(
            self.hs, "client_name", self.replication_handler)
        client_factory.handler = self.replication_handler

        server = server_factory.buildProtocol(None)
        client = client_factory.buildProtocol(None)

        client.makeConnection(FakeTransport(server, reactor))

        self.server_to_client_transport = FakeTransport(client, reactor)
        server.makeConnection(self.server_to_client_transport)
Beispiel #12
0
    def _handle_http_replication_attempt(self, hs, repl_port):
        """Handles a connection attempt to the given HS replication HTTP
        listener on the given port.
        """

        # We should have at least one outbound connection attempt, where the
        # last is one to the HTTP repication IP/port.
        clients = self.reactor.tcpClients
        self.assertGreaterEqual(len(clients), 1)
        (host, port, client_factory, _timeout, _bindAddress) = clients.pop()
        self.assertEqual(host, "1.2.3.4")
        self.assertEqual(port, repl_port)

        # Set up client side protocol
        client_address = IPv4Address("TCP", "127.0.0.1", 1234)
        client_protocol = client_factory.buildProtocol(("127.0.0.1", 1234))

        # Set up the server side protocol
        server_address = IPv4Address("TCP", host, port)
        channel = self._hs_to_site[hs].buildProtocol((host, port))

        # Connect client to server and vice versa.
        client_to_server_transport = FakeTransport(channel, self.reactor,
                                                   client_protocol,
                                                   server_address,
                                                   client_address)
        client_protocol.makeConnection(client_to_server_transport)

        server_to_client_transport = FakeTransport(client_protocol,
                                                   self.reactor, channel,
                                                   client_address,
                                                   server_address)
        channel.makeConnection(server_to_client_transport)
Beispiel #13
0
    def _download_image(self) -> Tuple[str, str]:
        """Downloads an image into the URL cache.
        Returns:
            A (host, media_id) tuple representing the MXC URI of the image.
        """
        self.lookups["cdn.twitter.com"] = [(IPv4Address, "10.1.2.3")]

        channel = self.make_request(
            "GET",
            "preview_url?url=http://cdn.twitter.com/matrixdotorg",
            shorthand=False,
            await_result=False,
        )
        self.pump()

        client = self.reactor.tcpClients[0][2].buildProtocol(None)
        server = AccumulatingProtocol()
        server.makeConnection(FakeTransport(client, self.reactor))
        client.makeConnection(FakeTransport(server, self.reactor))
        client.dataReceived(
            b"HTTP/1.0 200 OK\r\nContent-Length: %d\r\nContent-Type: image/png\r\n\r\n"
            % (len(SMALL_PNG), ) + SMALL_PNG)

        self.pump()
        self.assertEqual(channel.code, 200)
        body = channel.json_body
        mxc_uri = body["og:image"]
        host, _port, media_id = parse_and_validate_mxc_uri(mxc_uri)
        self.assertIsNone(_port)
        return host, media_id
Beispiel #14
0
    def test_ipaddr(self):
        """
        IP addresses can be previewed directly.
        """
        self.lookups["example.com"] = [(IPv4Address, "8.8.8.8")]

        request, channel = self.make_request(
            "GET", "url_preview?url=http://example.com", shorthand=False)
        request.render(self.preview_url)
        self.pump()

        client = self.reactor.tcpClients[0][2].buildProtocol(None)
        server = AccumulatingProtocol()
        server.makeConnection(FakeTransport(client, self.reactor))
        client.makeConnection(FakeTransport(server, self.reactor))
        client.dataReceived(
            b"HTTP/1.0 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n"
            % (len(self.end_content), ) + self.end_content)

        self.pump()
        self.assertEqual(channel.code, 200)
        self.assertEqual(channel.json_body, {
            "og:title": "~matrix~",
            "og:description": "hi"
        })
    def test_cache_returns_correct_type(self):
        self.lookups["matrix.org"] = [(IPv4Address, "8.8.8.8")]

        request, channel = self.make_request(
            "GET", "url_preview?url=http://matrix.org", shorthand=False
        )
        request.render(self.preview_url)
        self.pump()

        client = self.reactor.tcpClients[0][2].buildProtocol(None)
        server = AccumulatingProtocol()
        server.makeConnection(FakeTransport(client, self.reactor))
        client.makeConnection(FakeTransport(server, self.reactor))
        client.dataReceived(
            b"HTTP/1.0 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n"
            % (len(self.end_content),)
            + self.end_content
        )

        self.pump()
        self.assertEqual(channel.code, 200)
        self.assertEqual(
            channel.json_body, {"og:title": "~matrix~", "og:description": "hi"}
        )

        # Check the cache returns the correct response
        request, channel = self.make_request(
            "GET", "url_preview?url=http://matrix.org", shorthand=False
        )
        request.render(self.preview_url)
        self.pump()

        # Check the cache response has the same content
        self.assertEqual(channel.code, 200)
        self.assertEqual(
            channel.json_body, {"og:title": "~matrix~", "og:description": "hi"}
        )

        # Clear the in-memory cache
        self.assertIn("http://matrix.org", self.preview_url._cache)
        self.preview_url._cache.pop("http://matrix.org")
        self.assertNotIn("http://matrix.org", self.preview_url._cache)

        # Check the database cache returns the correct response
        request, channel = self.make_request(
            "GET", "url_preview?url=http://matrix.org", shorthand=False
        )
        request.render(self.preview_url)
        self.pump()

        # Check the cache response has the same content
        self.assertEqual(channel.code, 200)
        self.assertEqual(
            channel.json_body, {"og:title": "~matrix~", "og:description": "hi"}
        )
Beispiel #16
0
    def make_worker_hs(self,
                       worker_app: str,
                       extra_config: dict = {},
                       **kwargs) -> HomeServer:
        """Make a new worker HS instance, correctly connecting replcation
        stream to the master HS.

        Args:
            worker_app: Type of worker, e.g. `synapse.app.federation_sender`.
            extra_config: Any extra config to use for this instances.
            **kwargs: Options that get passed to `self.setup_test_homeserver`,
                useful to e.g. pass some mocks for things like `http_client`

        Returns:
            The new worker HomeServer instance.
        """

        config = self._get_worker_hs_config()
        config["worker_app"] = worker_app
        config.update(extra_config)

        worker_hs = self.setup_test_homeserver(
            homeserverToUse=GenericWorkerServer,
            config=config,
            reactor=self.reactor,
            **kwargs)

        store = worker_hs.get_datastore()
        store.db_pool._db_pool = self.database_pool._db_pool

        repl_handler = ReplicationCommandHandler(worker_hs)
        client = ClientReplicationStreamProtocol(
            worker_hs,
            "client",
            "test",
            self.clock,
            repl_handler,
        )
        server = self.server_factory.buildProtocol(None)

        client_transport = FakeTransport(server, self.reactor)
        client.makeConnection(client_transport)

        server_transport = FakeTransport(client, self.reactor)
        server.makeConnection(server_transport)

        # Set up a resource for the worker
        resource = ReplicationRestResource(self.hs)

        for servlet in self.servlets:
            servlet(worker_hs, resource)

        self._worker_hs_to_resource[worker_hs] = resource

        return worker_hs
Beispiel #17
0
    def reconnect(self):
        if self._client_transport:
            self.client.close()

        if self._server_transport:
            self.server.close()

        self._client_transport = FakeTransport(self.server, self.reactor)
        self.client.makeConnection(self._client_transport)

        self._server_transport = FakeTransport(self.client, self.reactor)
        self.server.makeConnection(self._server_transport)
def connect_logging_client(reactor, client_id):
    # This is essentially tests.server.connect_client, but disabling autoflush on
    # the client transport. This is necessary to avoid an infinite loop due to
    # sending of data via the logging transport causing additional logs to be
    # written.
    factory = reactor.tcpClients.pop(client_id)[2]
    client = factory.buildProtocol(None)
    server = AccumulatingProtocol()
    server.makeConnection(FakeTransport(client, reactor))
    client.makeConnection(FakeTransport(server, reactor, autoflush=False))

    return client, server
Beispiel #19
0
    def prepare(self, reactor, clock, hs):
        # build a replication server
        server_factory = ReplicationStreamProtocolFactory(self.hs)
        self.streamer = server_factory.streamer
        server = server_factory.buildProtocol(None)

        # build a replication client, with a dummy handler
        self.test_handler = TestReplicationClientHandler()
        self.client = ClientReplicationStreamProtocol("client", "test", clock,
                                                      self.test_handler)

        # wire them together
        self.client.makeConnection(FakeTransport(server, reactor))
        server.makeConnection(FakeTransport(self.client, reactor))
Beispiel #20
0
    def test_oembed_photo(self) -> None:
        """Test an oEmbed endpoint which returns a 'photo' type which redirects the preview to a new URL."""
        self.lookups["publish.twitter.com"] = [(IPv4Address, "10.1.2.3")]
        self.lookups["cdn.twitter.com"] = [(IPv4Address, "10.1.2.3")]

        result = {
            "version": "1.0",
            "type": "photo",
            "url": "http://cdn.twitter.com/matrixdotorg",
        }
        oembed_content = json.dumps(result).encode("utf-8")

        channel = self.make_request(
            "GET",
            "preview_url?url=http://twitter.com/matrixdotorg/status/12345",
            shorthand=False,
            await_result=False,
        )
        self.pump()

        client = self.reactor.tcpClients[0][2].buildProtocol(None)
        server = AccumulatingProtocol()
        server.makeConnection(FakeTransport(client, self.reactor))
        client.makeConnection(FakeTransport(server, self.reactor))
        client.dataReceived(
            (b"HTTP/1.0 200 OK\r\nContent-Length: %d\r\n"
             b'Content-Type: application/json; charset="utf8"\r\n\r\n') %
            (len(oembed_content), ) + oembed_content)

        self.pump()

        # Ensure a second request is made to the photo URL.
        client = self.reactor.tcpClients[1][2].buildProtocol(None)
        server = AccumulatingProtocol()
        server.makeConnection(FakeTransport(client, self.reactor))
        client.makeConnection(FakeTransport(server, self.reactor))
        client.dataReceived((b"HTTP/1.0 200 OK\r\nContent-Length: %d\r\n"
                             b"Content-Type: image/png\r\n\r\n") %
                            (len(SMALL_PNG), ) + SMALL_PNG)

        self.pump()

        # Ensure the URL is what was requested.
        self.assertIn(b"/matrixdotorg", server.data)

        self.assertEqual(channel.code, 200)
        body = channel.json_body
        self.assertEqual(body["og:url"],
                         "http://twitter.com/matrixdotorg/status/12345")
        self._assert_small_png(body)
    def test_accept_language_config_option(self):
        """
        Accept-Language header is sent to the remote server
        """
        self.lookups["example.com"] = [(IPv4Address, "10.1.2.3")]

        # Build and make a request to the server
        channel = self.make_request(
            "GET",
            "preview_url?url=http://example.com",
            shorthand=False,
            await_result=False,
        )
        self.pump()

        # Extract Synapse's tcp client
        client = self.reactor.tcpClients[0][2].buildProtocol(None)

        # Build a fake remote server to reply with
        server = AccumulatingProtocol()

        # Connect the two together
        server.makeConnection(FakeTransport(client, self.reactor))
        client.makeConnection(FakeTransport(server, self.reactor))

        # Tell Synapse that it has received some data from the remote server
        client.dataReceived(
            b"HTTP/1.0 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n"
            % (len(self.end_content),)
            + self.end_content
        )

        # Move the reactor along until we get a response on our original channel
        self.pump()
        self.assertEqual(channel.code, 200)
        self.assertEqual(
            channel.json_body, {"og:title": "~matrix~", "og:description": "hi"}
        )

        # Check that the server received the Accept-Language header as part
        # of the request from Synapse
        self.assertIn(
            (
                b"Accept-Language: en-UK\r\n"
                b"Accept-Language: en-US;q=0.9\r\n"
                b"Accept-Language: fr;q=0.8\r\n"
                b"Accept-Language: *;q=0.7"
            ),
            server.data,
        )
    def test_oembed_rich(self):
        """Test an oEmbed endpoint which returns HTML content via the 'rich' type."""
        # Route the HTTP version to an HTTP endpoint so that the tests work.
        with patch.dict(
            "synapse.rest.media.v1.preview_url_resource._oembed_patterns",
            {
                re.compile(
                    r"http://twitter\.com/.+/status/.+"
                ): "http://publish.twitter.com/oembed",
            },
            clear=True,
        ):

            self.lookups["publish.twitter.com"] = [(IPv4Address, "10.1.2.3")]

            result = {
                "version": "1.0",
                "type": "rich",
                "html": "<div>Content Preview</div>",
            }
            end_content = json.dumps(result).encode("utf-8")

            channel = self.make_request(
                "GET",
                "preview_url?url=http://twitter.com/matrixdotorg/status/12345",
                shorthand=False,
                await_result=False,
            )
            self.pump()

            client = self.reactor.tcpClients[0][2].buildProtocol(None)
            server = AccumulatingProtocol()
            server.makeConnection(FakeTransport(client, self.reactor))
            client.makeConnection(FakeTransport(server, self.reactor))
            client.dataReceived(
                (
                    b"HTTP/1.0 200 OK\r\nContent-Length: %d\r\n"
                    b'Content-Type: application/json; charset="utf8"\r\n\r\n'
                )
                % (len(end_content),)
                + end_content
            )

            self.pump()
            self.assertEqual(channel.code, 200)
            self.assertEqual(
                channel.json_body,
                {"og:title": None, "og:description": "Content Preview"},
            )
Beispiel #23
0
    def test_oembed_format(self):
        """Test an oEmbed endpoint which requires the format in the URL."""
        self.lookups["www.hulu.com"] = [(IPv4Address, "10.1.2.3")]

        result = {
            "version": "1.0",
            "type": "rich",
            "html": "<div>Content Preview</div>",
        }
        end_content = json.dumps(result).encode("utf-8")

        channel = self.make_request(
            "GET",
            "preview_url?url=http://www.hulu.com/watch/12345",
            shorthand=False,
            await_result=False,
        )
        self.pump()

        client = self.reactor.tcpClients[0][2].buildProtocol(None)
        server = AccumulatingProtocol()
        server.makeConnection(FakeTransport(client, self.reactor))
        client.makeConnection(FakeTransport(server, self.reactor))
        client.dataReceived(
            (
                b"HTTP/1.0 200 OK\r\nContent-Length: %d\r\n"
                b'Content-Type: application/json; charset="utf8"\r\n\r\n'
            )
            % (len(end_content),)
            + end_content
        )

        self.pump()

        # The {format} should have been turned into json.
        self.assertIn(b"/api/oembed.json", server.data)
        # A URL parameter of format=json should be provided.
        self.assertIn(b"format=json", server.data)

        self.assertEqual(channel.code, 200)
        body = channel.json_body
        self.assertEqual(
            body,
            {
                "og:url": "http://www.hulu.com/watch/12345",
                "og:description": "Content Preview",
            },
        )
Beispiel #24
0
    def test_lose_connection(self):
        """
        We log the URI correctly redacted when we lose the connection.
        """

        class HangingResource(Resource):
            """
            A Resource that strategically hangs, as if it were processing an
            answer.
            """

            def render(self, request):
                return NOT_DONE_YET

        # Set up a logging handler that we can inspect afterwards
        output = StringIO()
        handler = logging.StreamHandler(output)
        logger.addHandler(handler)
        old_level = logger.level
        logger.setLevel(10)
        self.addCleanup(logger.setLevel, old_level)
        self.addCleanup(logger.removeHandler, handler)

        # Make a resource and a Site, the resource will hang and allow us to
        # time out the request while it's 'processing'
        base_resource = Resource()
        base_resource.putChild(b'', HangingResource())
        site = SynapseSite("test", "site_tag", {}, base_resource, "1.0")

        server = site.buildProtocol(None)
        client = AccumulatingProtocol()
        client.makeConnection(FakeTransport(server, self.reactor))
        server.makeConnection(FakeTransport(client, self.reactor))

        # Send a request with an access token that will get redacted
        server.dataReceived(b"GET /?access_token=bar HTTP/1.0\r\n\r\n")
        self.pump()

        # Lose the connection
        e = Failure(Exception("Failed123"))
        server.connectionLost(e)
        handler.flush()

        # Our access token is redacted and the failure reason is logged.
        self.assertIn("/?access_token=<redacted>", output.getvalue())
        self.assertIn("Failed123", output.getvalue())
Beispiel #25
0
    def handle_http_replication_attempt(self) -> SynapseRequest:
        """Asserts that a connection attempt was made to the master HS on the
        HTTP replication port, then proxies it to the master HS object to be
        handled.

        Returns:
            The request object received by master HS.
        """

        # We should have an outbound connection attempt.
        clients = self.reactor.tcpClients
        self.assertEqual(len(clients), 1)
        (host, port, client_factory, _timeout, _bindAddress) = clients.pop(0)
        self.assertEqual(host, "1.2.3.4")
        self.assertEqual(port, 8765)

        # Set up client side protocol
        client_protocol = client_factory.buildProtocol(None)

        # Set up the server side protocol
        channel = self.site.buildProtocol(None)

        # hook into the channel's request factory so that we can keep a record
        # of the requests
        requests: List[SynapseRequest] = []
        real_request_factory = channel.requestFactory

        def request_factory(*args, **kwargs):
            request = real_request_factory(*args, **kwargs)
            requests.append(request)
            return request

        channel.requestFactory = request_factory

        # Connect client to server and vice versa.
        client_to_server_transport = FakeTransport(channel, self.reactor,
                                                   client_protocol)
        client_protocol.makeConnection(client_to_server_transport)

        server_to_client_transport = FakeTransport(client_protocol,
                                                   self.reactor, channel)
        channel.makeConnection(server_to_client_transport)

        # The request will now be processed by `self.site` and the response
        # streamed back.
        self.reactor.advance(0)

        # We tear down the connection so it doesn't get reused without our
        # knowledge.
        server_to_client_transport.loseConnection()
        client_to_server_transport.loseConnection()

        # there should have been exactly one request
        self.assertEqual(len(requests), 1)

        return requests[0]
Beispiel #26
0
    def test_oembed_rich(self):
        """Test an oEmbed endpoint which returns HTML content via the 'rich' type."""
        self.lookups["publish.twitter.com"] = [(IPv4Address, "10.1.2.3")]

        result = {
            "version": "1.0",
            "type": "rich",
            # Note that this provides the author, not the title.
            "author_name": "Alice",
            "html": "<div>Content Preview</div>",
        }
        end_content = json.dumps(result).encode("utf-8")

        channel = self.make_request(
            "GET",
            "preview_url?url=http://twitter.com/matrixdotorg/status/12345",
            shorthand=False,
            await_result=False,
        )
        self.pump()

        client = self.reactor.tcpClients[0][2].buildProtocol(None)
        server = AccumulatingProtocol()
        server.makeConnection(FakeTransport(client, self.reactor))
        client.makeConnection(FakeTransport(server, self.reactor))
        client.dataReceived(
            (
                b"HTTP/1.0 200 OK\r\nContent-Length: %d\r\n"
                b'Content-Type: application/json; charset="utf8"\r\n\r\n'
            )
            % (len(end_content),)
            + end_content
        )

        self.pump()
        self.assertEqual(channel.code, 200)
        body = channel.json_body
        self.assertEqual(
            body,
            {
                "og:url": "http://twitter.com/matrixdotorg/status/12345",
                "og:title": "Alice",
                "og:description": "Content Preview",
            },
        )
Beispiel #27
0
    def test_reactor(self):
        """Apply the blacklisting reactor and ensure it properly blocks connections to particular domains and IPs."""
        agent = Agent(
            BlacklistingReactorWrapper(
                self.reactor,
                ip_whitelist=self.ip_whitelist,
                ip_blacklist=self.ip_blacklist,
            ),
        )

        # The unsafe domains and IPs should be rejected.
        for domain in (self.unsafe_domain, self.unsafe_ip):
            self.failureResultOf(
                agent.request(b"GET", b"http://" + domain), DNSLookupError
            )

        # The safe domains IPs should be accepted.
        for domain in (
            self.safe_domain,
            self.allowed_domain,
            self.safe_ip,
            self.allowed_ip,
        ):
            d = agent.request(b"GET", b"http://" + domain)

            # Grab the latest TCP connection.
            (
                host,
                port,
                client_factory,
                _timeout,
                _bindAddress,
            ) = self.reactor.tcpClients[-1]

            # Make the connection and pump data through it.
            client = client_factory.buildProtocol(None)
            server = AccumulatingProtocol()
            server.makeConnection(FakeTransport(client, self.reactor))
            client.makeConnection(FakeTransport(server, self.reactor))
            client.dataReceived(
                b"HTTP/1.0 200 OK\r\nContent-Length: 0\r\nContent-Type: text/html\r\n\r\n"
            )

            response = self.successResultOf(d)
            self.assertEqual(response.code, 200)
    def _make_connection(self, client_factory, expected_sni):
        """Builds a test server, and completes the outgoing client connection

        Returns:
            HTTPChannel: the test server
        """

        # build the test server
        server_tls_protocol = _build_test_server(get_connection_factory())

        # now, tell the client protocol factory to build the client protocol (it will be a
        # _WrappingProtocol, around a TLSMemoryBIOProtocol, around an
        # HTTP11ClientProtocol) and wire the output of said protocol up to the server via
        # a FakeTransport.
        #
        # Normally this would be done by the TCP socket code in Twisted, but we are
        # stubbing that out here.
        client_protocol = client_factory.buildProtocol(None)
        client_protocol.makeConnection(
            FakeTransport(server_tls_protocol, self.reactor, client_protocol)
        )

        # tell the server tls protocol to send its stuff back to the client, too
        server_tls_protocol.makeConnection(
            FakeTransport(client_protocol, self.reactor, server_tls_protocol)
        )

        # grab a hold of the TLS connection, in case it gets torn down
        server_tls_connection = server_tls_protocol._tlsConnection

        # fish the test server back out of the server-side TLS protocol.
        http_protocol = server_tls_protocol.wrappedProtocol

        # give the reactor a pump to get the TLS juices flowing.
        self.reactor.pump((0.1,))

        # check the SNI
        server_name = server_tls_connection.get_servername()
        self.assertEqual(
            server_name,
            expected_sni,
            "Expected SNI %s but got %s" % (expected_sni, server_name),
        )

        return http_protocol
Beispiel #29
0
    def test_client_sends_body(self):
        self.cl.post_json("testserv:8008", "foo/bar", timeout=10000, data={"a": "b"})

        self.pump()

        clients = self.reactor.tcpClients
        self.assertEqual(len(clients), 1)
        client = clients[0][2].buildProtocol(None)
        server = HTTPChannel()

        client.makeConnection(FakeTransport(server, self.reactor))
        server.makeConnection(FakeTransport(client, self.reactor))

        self.pump(0.1)

        self.assertEqual(len(server.requests), 1)
        request = server.requests[0]
        content = request.content.read()
        self.assertEqual(content, b'{"a":"b"}')
Beispiel #30
0
    def test_send_email(self):
        """Happy-path test that we can send email to a non-TLS server."""
        h = self.hs.get_send_email_handler()
        d = ensureDeferred(
            h.send_email("*****@*****.**", "test subject", "Tests",
                         "HTML content", "Text content"))
        # there should be an attempt to connect to localhost:25
        self.assertEqual(len(self.reactor.tcpClients), 1)
        (host, port, client_factory, _timeout,
         _bindAddress) = self.reactor.tcpClients[0]
        self.assertEqual(host, "localhost")
        self.assertEqual(port, 25)

        # wire it up to an SMTP server
        message_delivery = _DummyMessageDelivery()
        server_protocol = smtp.ESMTP()
        server_protocol.delivery = message_delivery
        # make sure that the server uses the test reactor to set timeouts
        server_protocol.callLater = self.reactor.callLater  # type: ignore[assignment]

        client_protocol = client_factory.buildProtocol(None)
        client_protocol.makeConnection(
            FakeTransport(server_protocol, self.reactor))
        server_protocol.makeConnection(
            FakeTransport(
                client_protocol,
                self.reactor,
                peer_address=IPv4Address("TCP", "127.0.0.1", 1234),
            ))

        # the message should now get delivered
        self.get_success(d, by=0.1)

        # check it arrived
        self.assertEqual(len(message_delivery.messages), 1)
        user, msg = message_delivery.messages.pop()
        self.assertEqual(str(user), "*****@*****.**")
        self.assertIn(b"Subject: test subject", msg)