From 6cb775c0a13b067aad34688565603f13bff09127 Mon Sep 17 00:00:00 2001 From: Ben Darnell Date: Sat, 14 May 2011 20:52:42 -0700 Subject: [PATCH] Fix handling of closed connections with epoll. This fixes a problem with simple_httpclient and servers that close the connection after sending the response. --- tornado/iostream.py | 5 ++++- tornado/test/iostream_test.py | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/tornado/iostream.py b/tornado/iostream.py index c75e89237..812d5f6dc 100644 --- a/tornado/iostream.py +++ b/tornado/iostream.py @@ -209,7 +209,10 @@ class IOStream(object): if not self.socket: return if events & self.io_loop.ERROR: - self.close() + # We may have queued up a user callback in _handle_read or + # _handle_write, so don't close the IOStream until those + # callbacks have had a chance to run. + self.io_loop.add_callback(self.close) return state = self.io_loop.ERROR if self.reading(): diff --git a/tornado/test/iostream_test.py b/tornado/test/iostream_test.py index 835e19b74..f7d462da7 100644 --- a/tornado/test/iostream_test.py +++ b/tornado/test/iostream_test.py @@ -47,3 +47,12 @@ class TestIOStream(AsyncHTTPTestCase, LogTrapTestCase): self.wait() self.assertFalse(self.connect_called) + def test_connection_closed(self): + # When a server sends a response and then closes the connection, + # the client must be allowed to read the data before the IOStream + # closes itself. Epoll reports closed connections with a separate + # EPOLLRDHUP event delivered at the same time as the read event, + # while kqueue reports them as a second read/write event with an EOF + # flag. + response = self.fetch("/", headers={"Connection": "close"}) + response.rethrow() -- 2.47.3