class ContentLengthHandler(RequestHandler):
- @asynchronous
def get(self):
- self.stream = self.request.connection.detach()
+ self.stream = self.detach()
IOLoop.current().spawn_callback(self.write_response)
@gen.coroutine
class NoContentLengthHandler(RequestHandler):
- @asynchronous
def get(self):
if self.request.version.startswith('HTTP/1'):
# Emulate the old HTTP/1.0 behavior of returning a body with no
# content-length. Tornado handles content-length at the framework
# level so we have to go around it.
- stream = self.request.connection.detach()
+ stream = self.detach()
stream.write(b"HTTP/1.0 200 OK\r\n\r\n"
b"hello")
stream.close()
self.on_finish()
self._break_cycles()
+ def detach(self):
+ """Take control of the underlying stream.
+
+ Returns the underlying `.IOStream` object and stops all
+ further HTTP processing. Intended for implementing protocols
+ like websockets that tunnel over an HTTP handshake.
+
+ This method is only supported when HTTP/1.1 is used.
+
+ .. versionadded:: 5.1
+ """
+ self._finished = True
+ return self.request.connection.detach()
+
def _break_cycles(self):
# Break up a reference cycle between this handler and the
# _ui_module closures to allow for faster GC on CPython.
self.stream = None
self._on_close_called = False
- @tornado.web.asynchronous
def get(self, *args, **kwargs):
self.open_args = args
self.open_kwargs = kwargs
self, compression_options=self.get_compression_options())
def _attach_stream(self):
- self.stream = self.request.connection.detach()
+ self.stream = self.detach()
self.stream.set_close_callback(self.on_connection_close)
# disable non-WS methods
for method in ["write", "redirect", "set_header", "set_cookie",