diff --git a/synapse/app/generic_worker.py b/synapse/app/generic_worker.py
index a45c876213..a37520000a 100644
--- a/synapse/app/generic_worker.py
+++ b/synapse/app/generic_worker.py
@@ -22,7 +22,6 @@ from typing import Dict, Iterable
from typing_extensions import ContextManager
from twisted.internet import defer, reactor
-from twisted.web.resource import NoResource
import synapse
import synapse.events
@@ -41,7 +40,7 @@ from synapse.config.logger import setup_logging
from synapse.federation import send_queue
from synapse.federation.transport.server import TransportLayerServer
from synapse.handlers.presence import BasePresenceHandler, get_interested_parties
-from synapse.http.server import JsonResource
+from synapse.http.server import JsonResource, OptionsResource
from synapse.http.servlet import RestServlet, parse_json_object_from_request
from synapse.http.site import SynapseSite
from synapse.logging.context import LoggingContext
@@ -566,7 +565,7 @@ class GenericWorkerServer(HomeServer):
if name == "replication":
resources[REPLICATION_PREFIX] = ReplicationRestResource(self)
- root_resource = create_resource_tree(resources, NoResource())
+ root_resource = create_resource_tree(resources, OptionsResource())
_base.listen_tcp(
bind_addresses,
diff --git a/synapse/app/homeserver.py b/synapse/app/homeserver.py
index d7f337e586..93a5ba2100 100644
--- a/synapse/app/homeserver.py
+++ b/synapse/app/homeserver.py
@@ -31,7 +31,7 @@ from prometheus_client import Gauge
from twisted.application import service
from twisted.internet import defer, reactor
from twisted.python.failure import Failure
-from twisted.web.resource import EncodingResourceWrapper, IResource, NoResource
+from twisted.web.resource import EncodingResourceWrapper, IResource
from twisted.web.server import GzipEncoderFactory
from twisted.web.static import File
@@ -52,7 +52,11 @@ from synapse.config._base import ConfigError
from synapse.config.homeserver import HomeServerConfig
from synapse.federation.transport.server import TransportLayerServer
from synapse.http.additional_resource import AdditionalResource
-from synapse.http.server import RootRedirect
+from synapse.http.server import (
+ OptionsResource,
+ RootOptionsRedirectResource,
+ RootRedirect,
+)
from synapse.http.site import SynapseSite
from synapse.logging.context import LoggingContext
from synapse.metrics import METRICS_PREFIX, MetricsResource, RegistryProxy
@@ -121,11 +125,11 @@ class SynapseHomeServer(HomeServer):
# try to find something useful to redirect '/' to
if WEB_CLIENT_PREFIX in resources:
- root_resource = RootRedirect(WEB_CLIENT_PREFIX)
+ root_resource = RootOptionsRedirectResource(WEB_CLIENT_PREFIX)
elif STATIC_PREFIX in resources:
- root_resource = RootRedirect(STATIC_PREFIX)
+ root_resource = RootOptionsRedirectResource(STATIC_PREFIX)
else:
- root_resource = NoResource()
+ root_resource = OptionsResource()
root_resource = create_resource_tree(resources, root_resource)
diff --git a/synapse/http/server.py b/synapse/http/server.py
index 042a605198..33fcfbea6e 100644
--- a/synapse/http/server.py
+++ b/synapse/http/server.py
@@ -350,9 +350,6 @@ class JsonResource(HttpServer, resource.Resource):
register_paths, so will return (possibly via Deferred) either
None, or a tuple of (http code, response body).
"""
- if request.method == b"OPTIONS":
- return _options_handler, "options_request_handler", {}
-
request_path = request.path.decode("ascii")
# Loop through all the registered callbacks to check if the method
@@ -448,6 +445,26 @@ class RootRedirect(resource.Resource):
return resource.Resource.getChild(self, name, request)
+class OptionsResource(resource.Resource):
+ """Responds to OPTION requests for itself and all children."""
+
+ def render_OPTIONS(self, request):
+ code, response_json_object = _options_handler(request)
+
+ return respond_with_json(
+ request, code, response_json_object, send_cors=False, canonical_json=False,
+ )
+
+ def getChildWithDefault(self, path, request):
+ if request.method == b"OPTIONS":
+ return self # select ourselves as the child to render
+ return resource.Resource.getChildWithDefault(self, path, request)
+
+
+class RootOptionsRedirectResource(OptionsResource, RootRedirect):
+ pass
+
+
def respond_with_json(
request,
code,
|