diff options
author | Richard van der Hoff <richard@matrix.org> | 2018-08-14 16:13:17 +0100 |
---|---|---|
committer | Richard van der Hoff <richard@matrix.org> | 2018-08-15 15:04:16 +0100 |
commit | afcd655ab67611e3bbac3bc992574baa464bc030 (patch) | |
tree | af5746c92e5596ff56ff65f021ef30a4834c36b3 | |
parent | Merge pull request #3687 from matrix-org/neilj/admin_email (diff) | |
download | synapse-afcd655ab67611e3bbac3bc992574baa464bc030.tar.xz |
Use a producer to stream back responses
The problem with dumping all of the json response into the Request object at once is that doing so starts the timeout for the next request to be received: so if it takes longer than 60s to stream back the response to the client, the client never gets it. The correct solution is to use a Producer; then the timeout is only started once all of the content is sent over the TCP connection.
-rw-r--r-- | synapse/http/server.py | 17 |
1 files changed, 13 insertions, 4 deletions
diff --git a/synapse/http/server.py b/synapse/http/server.py index 6dacb31037..5733abb5dc 100644 --- a/synapse/http/server.py +++ b/synapse/http/server.py @@ -27,6 +27,7 @@ from twisted.internet import defer from twisted.python import failure from twisted.web import resource, server from twisted.web.server import NOT_DONE_YET +from twisted.web.static import NoRangeStaticProducer from twisted.web.util import redirectTo import synapse.events @@ -42,6 +43,11 @@ from synapse.util.caches import intern_dict from synapse.util.logcontext import LoggingContext, PreserveLoggingContext from synapse.util.metrics import Measure +if PY3: + from io import BytesIO +else: + from cStringIO import StringIO as BytesIO + logger = logging.getLogger(__name__) HTML_ERROR_TEMPLATE = """<!DOCTYPE html> @@ -413,8 +419,7 @@ def respond_with_json(request, code, json_object, send_cors=False, return if pretty_print: - json_bytes = (encode_pretty_printed_json(json_object) + "\n" - ).encode("utf-8") + json_bytes = encode_pretty_printed_json(json_object) + b"\n" else: if canonical_json or synapse.events.USE_FROZEN_DICTS: # canonicaljson already encodes to bytes @@ -450,8 +455,12 @@ def respond_with_json_bytes(request, code, json_bytes, send_cors=False, if send_cors: set_cors_headers(request) - request.write(json_bytes) - finish_request(request) + # todo: we can almost certainly avoid this copy and encode the json straight into + # the bytesIO, but it would involve faffing around with string->bytes wrappers. + bytes_io = BytesIO(json_bytes) + + producer = NoRangeStaticProducer(request, bytes_io) + producer.start() return NOT_DONE_YET |