Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add an optional timeout for keep-alive HTTP connections.

  • Loading branch information...
commit 468d37c7e54d38c468d7e49284930662c378a321 1 parent 95b7073
@flodiebold flodiebold authored
Showing with 37 additions and 3 deletions.
  1. +35 −3 tornado/httpserver.py
  2. +2 −0  tornado/websocket.py
View
38 tornado/httpserver.py
@@ -76,6 +76,9 @@ def handle_request(request):
ensure the connection is closed on every request no matter what HTTP
version the client is using.
+ If connection_timeout is set, HTTP keep-alive connections will be closed
+ after that many seconds of inactivity.
+
If ``xheaders`` is ``True``, we support the ``X-Real-Ip`` and ``X-Scheme``
headers, which override the remote IP and HTTP scheme for all requests.
These headers are useful when running Tornado behind a reverse proxy or
@@ -132,16 +135,18 @@ def handle_request(request):
"""
def __init__(self, request_callback, no_keep_alive=False, io_loop=None,
- xheaders=False, ssl_options=None, **kwargs):
+ xheaders=False, ssl_options=None, connection_timeout=-1,
+ **kwargs):
self.request_callback = request_callback
self.no_keep_alive = no_keep_alive
+ self.connection_timeout = connection_timeout
self.xheaders = xheaders
TCPServer.__init__(self, io_loop=io_loop, ssl_options=ssl_options,
**kwargs)
def handle_stream(self, stream, address):
HTTPConnection(stream, address, self.request_callback,
- self.no_keep_alive, self.xheaders)
+ self.no_keep_alive, self.xheaders, self.connection_timeout)
class _BadRequestException(Exception):
"""Exception class for malformed HTTP requests."""
@@ -154,7 +159,7 @@ class HTTPConnection(object):
until the HTTP conection is closed.
"""
def __init__(self, stream, address, request_callback, no_keep_alive=False,
- xheaders=False):
+ xheaders=False, connection_timeout=-1):
self.stream = stream
if self.stream.socket.family not in (socket.AF_INET, socket.AF_INET6):
# Unix (or other) socket; fake the remote address
@@ -162,6 +167,7 @@ def __init__(self, stream, address, request_callback, no_keep_alive=False,
self.address = address
self.request_callback = request_callback
self.no_keep_alive = no_keep_alive
+ self.connection_timeout = connection_timeout
self.xheaders = xheaders
self._request = None
self._request_finished = False
@@ -170,6 +176,28 @@ def __init__(self, stream, address, request_callback, no_keep_alive=False,
self._header_callback = stack_context.wrap(self._on_headers)
self.stream.read_until(b("\r\n\r\n"), self._header_callback)
self._write_callback = None
+ self._timeout_handle = None
+ self.reset_connection_timeout()
+
+ def reset_connection_timeout(self):
+ if self.connection_timeout == -1:
+ return
+ self.remove_connection_timeout()
+ self._timeout_handle = self.stream.io_loop.add_timeout(
+ time.time() + self.connection_timeout, self._handle_timeout)
+
+ def remove_connection_timeout(self):
+ if self._timeout_handle:
+ self.stream.io_loop.remove_timeout(self._timeout_handle)
+
+ def _handle_timeout(self):
+ if self.stream.closed():
+ return
+
+ if self.stream.writing():
+ self.reset_connection_timeout()
+ else:
+ self.stream.close()
def write(self, chunk, callback=None):
"""Writes a chunk of output to the stream."""
@@ -210,10 +238,13 @@ def _finish_request(self):
if disconnect:
self.stream.close()
return
+ else:
+ self.reset_connection_timeout()
self.stream.read_until(b("\r\n\r\n"), self._header_callback)
def _on_headers(self, data):
try:
+ self.reset_connection_timeout()
data = native_str(data.decode('latin1'))
eol = data.find("\r\n")
start_line = data[:eol]
@@ -246,6 +277,7 @@ def _on_headers(self, data):
return
def _on_request_body(self, data):
+ self.reset_connection_timeout()
self._request.body = data
content_type = self._request.headers.get("Content-Type", "")
if self._request.method in ("POST", "PUT"):
View
2  tornado/websocket.py
@@ -79,6 +79,8 @@ def _execute(self, transforms, *args, **kwargs):
self.open_args = args
self.open_kwargs = kwargs
+ self.request.connection.remove_connection_timeout()
+
if (self.request.headers.get("Sec-WebSocket-Version") == "8" or
self.request.headers.get("Sec-WebSocket-Version") == "7"):
self.ws_connection = WebSocketProtocol8(self)
Please sign in to comment.
Something went wrong with that request. Please try again.