|
@@ -16,10 +16,11 @@
|
|
|
|
|
|
import cgi
|
|
|
import collections
|
|
|
+import http.client
|
|
|
import logging
|
|
|
-
|
|
|
-from six import PY3
|
|
|
-from six.moves import http_client, urllib
|
|
|
+import types
|
|
|
+import urllib
|
|
|
+from io import BytesIO
|
|
|
|
|
|
from canonicaljson import encode_canonical_json, encode_pretty_printed_json, json
|
|
|
|
|
@@ -41,11 +42,6 @@ from synapse.api.errors import (
|
|
|
from synapse.util.caches import intern_dict
|
|
|
from synapse.util.logcontext import preserve_fn
|
|
|
|
|
|
-if PY3:
|
|
|
- from io import BytesIO
|
|
|
-else:
|
|
|
- from cStringIO import StringIO as BytesIO
|
|
|
-
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
HTML_ERROR_TEMPLATE = """<!DOCTYPE html>
|
|
@@ -75,10 +71,9 @@ def wrap_json_request_handler(h):
|
|
|
deferred fails with any other type of error we send a 500 reponse.
|
|
|
"""
|
|
|
|
|
|
- @defer.inlineCallbacks
|
|
|
- def wrapped_request_handler(self, request):
|
|
|
+ async def wrapped_request_handler(self, request):
|
|
|
try:
|
|
|
- yield h(self, request)
|
|
|
+ await h(self, request)
|
|
|
except SynapseError as e:
|
|
|
code = e.code
|
|
|
logger.info("%s SynapseError: %s - %s", request, code, e.msg)
|
|
@@ -142,10 +137,12 @@ def wrap_html_request_handler(h):
|
|
|
where "request" must be a SynapseRequest.
|
|
|
"""
|
|
|
|
|
|
- def wrapped_request_handler(self, request):
|
|
|
- d = defer.maybeDeferred(h, self, request)
|
|
|
- d.addErrback(_return_html_error, request)
|
|
|
- return d
|
|
|
+ async def wrapped_request_handler(self, request):
|
|
|
+ try:
|
|
|
+ return await h(self, request)
|
|
|
+ except Exception:
|
|
|
+ f = failure.Failure()
|
|
|
+ return _return_html_error(f, request)
|
|
|
|
|
|
return wrap_async_request_handler(wrapped_request_handler)
|
|
|
|
|
@@ -171,7 +168,7 @@ def _return_html_error(f, request):
|
|
|
exc_info=(f.type, f.value, f.getTracebackObject()),
|
|
|
)
|
|
|
else:
|
|
|
- code = http_client.INTERNAL_SERVER_ERROR
|
|
|
+ code = http.client.INTERNAL_SERVER_ERROR
|
|
|
msg = "Internal server error"
|
|
|
|
|
|
logger.error(
|
|
@@ -201,10 +198,9 @@ def wrap_async_request_handler(h):
|
|
|
logged until the deferred completes.
|
|
|
"""
|
|
|
|
|
|
- @defer.inlineCallbacks
|
|
|
- def wrapped_async_request_handler(self, request):
|
|
|
+ async def wrapped_async_request_handler(self, request):
|
|
|
with request.processing():
|
|
|
- yield h(self, request)
|
|
|
+ await h(self, request)
|
|
|
|
|
|
# we need to preserve_fn here, because the synchronous render method won't yield for
|
|
|
# us (obviously)
|
|
@@ -270,12 +266,11 @@ class JsonResource(HttpServer, resource.Resource):
|
|
|
def render(self, request):
|
|
|
""" This gets called by twisted every time someone sends us a request.
|
|
|
"""
|
|
|
- self._async_render(request)
|
|
|
+ defer.ensureDeferred(self._async_render(request))
|
|
|
return NOT_DONE_YET
|
|
|
|
|
|
@wrap_json_request_handler
|
|
|
- @defer.inlineCallbacks
|
|
|
- def _async_render(self, request):
|
|
|
+ async def _async_render(self, request):
|
|
|
""" This gets called from render() every time someone sends us a request.
|
|
|
This checks if anyone has registered a callback for that method and
|
|
|
path.
|
|
@@ -292,26 +287,19 @@ class JsonResource(HttpServer, resource.Resource):
|
|
|
# Now trigger the callback. If it returns a response, we send it
|
|
|
# here. If it throws an exception, that is handled by the wrapper
|
|
|
# installed by @request_handler.
|
|
|
-
|
|
|
- def _unquote(s):
|
|
|
- if PY3:
|
|
|
- # On Python 3, unquote is unicode -> unicode
|
|
|
- return urllib.parse.unquote(s)
|
|
|
- else:
|
|
|
- # On Python 2, unquote is bytes -> bytes We need to encode the
|
|
|
- # URL again (as it was decoded by _get_handler_for request), as
|
|
|
- # ASCII because it's a URL, and then decode it to get the UTF-8
|
|
|
- # characters that were quoted.
|
|
|
- return urllib.parse.unquote(s.encode("ascii")).decode("utf8")
|
|
|
-
|
|
|
kwargs = intern_dict(
|
|
|
{
|
|
|
- name: _unquote(value) if value else value
|
|
|
+ name: urllib.parse.unquote(value) if value else value
|
|
|
for name, value in group_dict.items()
|
|
|
}
|
|
|
)
|
|
|
|
|
|
- callback_return = yield callback(request, **kwargs)
|
|
|
+ callback_return = callback(request, **kwargs)
|
|
|
+
|
|
|
+ # Is it synchronous? We'll allow this for now.
|
|
|
+ if isinstance(callback_return, (defer.Deferred, types.CoroutineType)):
|
|
|
+ callback_return = await callback_return
|
|
|
+
|
|
|
if callback_return is not None:
|
|
|
code, response = callback_return
|
|
|
self._send_response(request, code, response)
|
|
@@ -360,6 +348,23 @@ class JsonResource(HttpServer, resource.Resource):
|
|
|
)
|
|
|
|
|
|
|
|
|
+class DirectServeResource(resource.Resource):
|
|
|
+ def render(self, request):
|
|
|
+ """
|
|
|
+ Render the request, using an asynchronous render handler if it exists.
|
|
|
+ """
|
|
|
+ render_callback_name = "_async_render_" + request.method.decode("ascii")
|
|
|
+
|
|
|
+ if hasattr(self, render_callback_name):
|
|
|
+ # Call the handler
|
|
|
+ callback = getattr(self, render_callback_name)
|
|
|
+ defer.ensureDeferred(callback(request))
|
|
|
+
|
|
|
+ return NOT_DONE_YET
|
|
|
+ else:
|
|
|
+ super().render(request)
|
|
|
+
|
|
|
+
|
|
|
def _options_handler(request):
|
|
|
"""Request handler for OPTIONS requests
|
|
|
|