sock.close()
def handle_stream(self, stream, address):
- """Override to handle a new `.IOStream` from an incoming connection."""
+ """Override to handle a new `.IOStream` from an incoming connection.
+
+ This method may be a coroutine; if so any exceptions it raises
+ asynchronously will be logged. Accepting of incoming connections
+ will not be blocked by this coroutine.
+
+ If this `TCPServer` is configured for SSL, ``handle_stream``
+ may be called before the SSL handshake has completed. Use
+ `.SSLIOStream.wait_for_handshake` if you need to verify the client's
+ certificate or use NPN/ALPN.
+
+ .. versionchanged:: 4.2
+ Added the option for this method to be a coroutine.
+ """
raise NotImplementedError()
def _handle_connection(self, connection, address):
stream = IOStream(connection, io_loop=self.io_loop,
max_buffer_size=self.max_buffer_size,
read_chunk_size=self.read_chunk_size)
- self.handle_stream(stream, address)
+ future = self.handle_stream(stream, address)
+ if future is not None:
+ self.io_loop.add_future(future, lambda f: f.result())
except Exception:
app_log.error("Error in connection callback", exc_info=True)
'tornado.test.simple_httpclient_test',
'tornado.test.stack_context_test',
'tornado.test.tcpclient_test',
+ 'tornado.test.tcpserver_test',
'tornado.test.template_test',
'tornado.test.testing_test',
'tornado.test.twisted_test',
--- /dev/null
+import socket
+
+from tornado import gen
+from tornado.iostream import IOStream
+from tornado.log import app_log
+from tornado.stack_context import NullContext
+from tornado.tcpserver import TCPServer
+from tornado.testing import AsyncTestCase, ExpectLog, bind_unused_port, gen_test
+
+
+class TCPServerTest(AsyncTestCase):
+ @gen_test
+ def test_handle_stream_coroutine_logging(self):
+ # handle_stream may be a coroutine and any exception in its
+ # Future will be logged.
+ class TestServer(TCPServer):
+ @gen.coroutine
+ def handle_stream(self, stream, address):
+ yield gen.moment
+ stream.close()
+ 1/0
+
+ server = client = None
+ try:
+ sock, port = bind_unused_port()
+ with NullContext():
+ server = TestServer()
+ server.add_socket(sock)
+ client = IOStream(socket.socket())
+ with ExpectLog(app_log, "Exception in callback"):
+ yield client.connect(('localhost', port))
+ yield client.read_until_close()
+ yield gen.moment
+ finally:
+ if server is not None:
+ server.stop()
+ if client is not None:
+ client.close()