diff --git a/synapse/app/homeserver.py b/synapse/app/homeserver.py index 79c7a8558d..4228bac673 100755 --- a/synapse/app/homeserver.py +++ b/synapse/app/homeserver.py @@ -87,16 +87,10 @@ class SynapseHomeServer(HomeServer): return MatrixFederationHttpClient(self) def build_resource_for_client(self): - res = ClientV1RestResource(self) - if self.config.gzip_responses: - res = gz_wrap(res) - return res + return ClientV1RestResource(self) def build_resource_for_client_v2_alpha(self): - res = ClientV2AlphaRestResource(self) - if self.config.gzip_responses: - res = gz_wrap(res) - return res + return ClientV2AlphaRestResource(self) def build_resource_for_federation(self): return JsonResource(self) @@ -145,49 +139,102 @@ class SynapseHomeServer(HomeServer): **self.db_config.get("args", {}) ) - def start_listening(self): - config = self.get_config() + def _listener_http(self, config, listener_config): + port = listener_config["port"] + bind_address = listener_config.get("bind_address", "") + tls = listener_config.get("tls", False) - if not config.no_tls and config.bind_port is not None: + if tls and config.no_tls: + return + + metrics_resource = self.get_resource_for_metrics() + + resources = {} + for res in listener_config["resources"]: + for name in res["names"]: + if name == "client": + if res["compress"]: + client_v1 = gz_wrap(self.get_resource_for_client()) + client_v2 = gz_wrap(self.get_resource_for_client_v2_alpha()) + else: + client_v1 = self.get_resource_for_client() + client_v2 = self.get_resource_for_client_v2_alpha() + + resources.update({ + CLIENT_PREFIX: client_v1, + CLIENT_V2_ALPHA_PREFIX: client_v2, + }) + + if name == "federation": + resources.update({ + FEDERATION_PREFIX: self.get_resource_for_federation(), + }) + + if name in ["static", "client"]: + resources.update({ + STATIC_PREFIX: self.get_resource_for_static_content(), + }) + + if name in ["media", "federation", "client"]: + resources.update({ + MEDIA_PREFIX: self.get_resource_for_media_repository(), + CONTENT_REPO_PREFIX: self.get_resource_for_content_repo(), + }) + + if name in ["keys", "federation"]: + resources.update({ + SERVER_KEY_PREFIX: self.get_resource_for_server_key(), + SERVER_KEY_V2_PREFIX: self.get_resource_for_server_key_v2(), + }) + + if name == "webclient": + resources[WEB_CLIENT_PREFIX] = self.get_resource_for_web_client() + + if name == "metrics" and metrics_resource: + resources[METRICS_PREFIX] = metrics_resource + + root_resource = create_resource_tree(resources) + if tls: reactor.listenSSL( - config.bind_port, + port, SynapseSite( "synapse.access.https", config, - self.root_resource, + root_resource, ), self.tls_context_factory, - interface=config.bind_host + interface=bind_address ) - logger.info("Synapse now listening on port %d", config.bind_port) - - if config.unsecure_port is not None: + else: reactor.listenTCP( - config.unsecure_port, + port, SynapseSite( - "synapse.access.http", + "synapse.access.https", config, - self.root_resource, + root_resource, ), - interface=config.bind_host + interface=bind_address ) - logger.info("Synapse now listening on port %d", config.unsecure_port) + logger.info("Synapse now listening on port %d", port) - metrics_resource = self.get_resource_for_metrics() - if metrics_resource and config.metrics_port is not None: - reactor.listenTCP( - config.metrics_port, - SynapseSite( - "synapse.access.metrics", - config, - metrics_resource, - ), - interface=config.metrics_bind_host, - ) - logger.info( - "Metrics now running on %s port %d", - config.metrics_bind_host, config.metrics_port, - ) + def start_listening(self): + config = self.get_config() + + for listener in config.listeners: + if listener["type"] == "http": + self._listener_http(config, listener) + elif listener["type"] == "manhole": + f = twisted.manhole.telnet.ShellFactory() + f.username = "matrix" + f.password = "rabbithole" + f.namespace['hs'] = self + reactor.listenTCP( + listener["port"], + f, + interface=listener.get("bind_address", '127.0.0.1') + ) + else: + logger.warn("Unrecognized listener type: %s", listener["type"]) def run_startup_checks(self, db_conn, database_engine): all_users_native = are_all_users_on_domain( @@ -322,11 +369,6 @@ def setup(config_options): events.USE_FROZEN_DICTS = config.use_frozen_dicts - if re.search(":[0-9]+$", config.server_name): - domain_with_port = config.server_name - else: - domain_with_port = "%s:%s" % (config.server_name, config.bind_port) - tls_context_factory = context_factory.ServerContextFactory(config) database_engine = create_engine(config.database_config["name"]) @@ -334,7 +376,6 @@ def setup(config_options): hs = SynapseHomeServer( config.server_name, - domain_with_port=domain_with_port, upload_dir=os.path.abspath("uploads"), db_config=config.database_config, tls_context_factory=tls_context_factory, @@ -344,29 +385,6 @@ def setup(config_options): database_engine=database_engine, ) - resources = { - CLIENT_PREFIX: hs.get_resource_for_client(), - CLIENT_V2_ALPHA_PREFIX: hs.get_resource_for_client_v2_alpha(), - FEDERATION_PREFIX: hs.get_resource_for_federation(), - CONTENT_REPO_PREFIX: hs.get_resource_for_content_repo(), - SERVER_KEY_PREFIX: hs.get_resource_for_server_key(), - SERVER_KEY_V2_PREFIX: hs.get_resource_for_server_key_v2(), - MEDIA_PREFIX: hs.get_resource_for_media_repository(), - STATIC_PREFIX: hs.get_resource_for_static_content(), - } - - if config.web_client: - resources[WEB_CLIENT_PREFIX] = hs.get_resource_for_web_client() - - metrics_resource = hs.get_resource_for_metrics() - if config.metrics_port is None and metrics_resource is not None: - resources[METRICS_PREFIX] = metrics_resource - - hs.root_resource = create_resource_tree( - resources, - redirect_root_to_web_client=True, - ) - logger.info("Preparing database: %r...", config.database_config) try: diff --git a/synapse/config/server.py b/synapse/config/server.py index 022ebcea94..26017c7efa 100644 --- a/synapse/config/server.py +++ b/synapse/config/server.py @@ -20,26 +20,73 @@ class ServerConfig(Config): def read_config(self, config): self.server_name = config["server_name"] - self.bind_port = config["bind_port"] - self.bind_host = config["bind_host"] - self.unsecure_port = config["unsecure_port"] self.manhole = config.get("manhole") self.pid_file = self.abspath(config.get("pid_file")) self.web_client = config["web_client"] self.soft_file_limit = config["soft_file_limit"] self.daemonize = config.get("daemonize") self.use_frozen_dicts = config.get("use_frozen_dicts", True) - self.gzip_responses = config["gzip_responses"] + + self.listeners = config.get("listeners", []) + + bind_port = config.get("bind_port") + if bind_port: + self.listeners = [] + bind_host = config.get("bind_host", "") + gzip_responses = config.get("gzip_responses", True) + + self.listeners.append({ + "port": bind_port, + "bind_address": bind_host, + "tls": True, + "type": "http", + "resources": [ + { + "names": ["client", "webclient"], + "compress": gzip_responses, + }, + { + "names": ["federation"], + "compress": False, + } + ] + }) + + unsecure_port = config.get("unsecure_port", bind_port - 400) + if unsecure_port: + self.listeners.append({ + "port": unsecure_port, + "bind_address": bind_host, + "tls": False, + "type": "http", + "resources": [ + { + "names": ["client", "webclient"], + "compress": gzip_responses, + }, + { + "names": ["federation"], + "compress": False, + } + ] + }) # Attempt to guess the content_addr for the v0 content repostitory content_addr = config.get("content_addr") if not content_addr: + for listener in self.listeners: + if listener["type"] == "http" and not listener.get("tls", False): + unsecure_port = listener["port"] + break + else: + raise RuntimeError("Could not determine 'content_addr'") + host = self.server_name if ':' not in host: - host = "%s:%d" % (host, self.unsecure_port) + host = "%s:%d" % (host, unsecure_port) else: host = host.split(':')[0] - host = "%s:%d" % (host, self.unsecure_port) + host = "%s:%d" % (host, unsecure_port) content_addr = "http://%s" % (host,) self.content_addr = content_addr @@ -61,9 +108,17 @@ class ServerConfig(Config): # e.g. matrix.org, localhost:8080, etc. server_name: "%(server_name)s" + # The port to listen for HTTPS requests on. + # For when matrix traffic is sent directly to synapse. + # bind_port: %(bind_port)s + + # The port to listen for HTTP requests on. + # For when matrix traffic passes through loadbalancer that unwraps TLS. + # unsecure_port: %(unsecure_port)s + # Local interface to listen on. # The empty string will cause synapse to listen on all interfaces. - bind_host: "" + # bind_host: "" # When running as a daemon, the file to store the pid in pid_file: %(pid_file)s @@ -83,31 +138,30 @@ class ServerConfig(Config): # Should synapse compress HTTP responses to clients that support it? # This should be disabled if running synapse behind a load balancer # that can do automatic compression. - gzip_responses: True + # gzip_responses: True listeners: - # For when matrix traffic is sent directly to synapse. - secure: - # The type of - type: http_resource + - port: %(unsecure_port)s + tls: false + bind_address: '' + type: http - # The port to listen for HTTPS requests on. - port: %(bind_port)s - - # Is this a TLS socket? - tls: true - - # Local interface to listen on. - # The empty string will cause synapse to listen on all interfaces. - bind_address: "" - - # For when matrix traffic passes through loadbalancer that unwraps TLS. - unsecure: - port: %(unsecure_port)s - tls: false - bind_address: "" + resources: + - names: [client, webclient] + compress: true + - names: [federation] + compress: false + - port: %(bind_port)s + tls: true + bind_address: '' + type: http + resources: + - names: [client, webclient] + compress: true + - names: [federation] + compress: false """ % locals() def read_arguments(self, args):