From: Ben Darnell Date: Sun, 26 Jun 2011 19:27:54 +0000 (-0700) Subject: Add read_until_close method to IOStream and use it in SimpleAsyncHTTPClient. X-Git-Tag: v2.1.0~148 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b881ec495c4b0753511ccb96493af47102c9979b;p=thirdparty%2Ftornado.git Add read_until_close method to IOStream and use it in SimpleAsyncHTTPClient. --- diff --git a/tornado/iostream.py b/tornado/iostream.py index cebd6f417..fdb1e28d3 100644 --- a/tornado/iostream.py +++ b/tornado/iostream.py @@ -90,6 +90,7 @@ class IOStream(object): self._write_buffer_frozen = False self._read_delimiter = None self._read_bytes = None + self._read_until_close = False self._read_callback = None self._write_callback = None self._close_callback = None @@ -152,6 +153,19 @@ class IOStream(object): break self._add_io_state(self.io_loop.READ) + def read_until_close(self, callback): + """Reads all data from the socket until it is closed. + + Subject to ``max_buffer_size`` limit from `IOStream` constructor. + """ + assert not self._read_callback, "Already reading" + if self.closed(): + self._run_callback(callback, self._consume(self._read_buffer_size)) + return + self._read_until_close = True + self._read_callback = stack_context.wrap(callback) + self._add_io_state(self.io_loop.READ) + def write(self, data, callback=None): """Write the given data to this stream. @@ -173,6 +187,12 @@ class IOStream(object): def close(self): """Close this stream.""" if self.socket is not None: + if self._read_until_close: + callback = self._read_callback + self._read_callback = None + self._read_until_close = False + self._run_callback(callback, + self._consume(self._read_buffer_size)) self.io_loop.remove_handler(self.socket.fileno()) self.socket.close() self.socket = None diff --git a/tornado/simple_httpclient.py b/tornado/simple_httpclient.py index a8b90af1a..5d0886790 100644 --- a/tornado/simple_httpclient.py +++ b/tornado/simple_httpclient.py @@ -299,8 +299,7 @@ class _HTTPConnection(object): self.stream.read_bytes(int(self.headers["Content-Length"]), self._on_body) else: - raise Exception("No Content-length or chunked encoding, " - "don't know how to read %s", self.request.url) + self.stream.read_until_close(self._on_body) def _on_body(self, data): if self._timeout is not None: diff --git a/tornado/test/iostream_test.py b/tornado/test/iostream_test.py index f7d462da7..72df5f0a0 100644 --- a/tornado/test/iostream_test.py +++ b/tornado/test/iostream_test.py @@ -56,3 +56,14 @@ class TestIOStream(AsyncHTTPTestCase, LogTrapTestCase): # flag. response = self.fetch("/", headers={"Connection": "close"}) response.rethrow() + + def test_read_until_close(self): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) + s.connect(("localhost", self.get_http_port())) + stream = IOStream(s, io_loop=self.io_loop) + stream.write(b("GET / HTTP/1.0\r\n\r\n")) + + stream.read_until_close(self.stop) + data = self.wait() + self.assertTrue(data.startswith(b("HTTP/1.0 200"))) + self.assertTrue(data.endswith(b("Hello"))) diff --git a/website/sphinx/releases/next.rst b/website/sphinx/releases/next.rst index 787aad3c8..b3ac42a20 100644 --- a/website/sphinx/releases/next.rst +++ b/website/sphinx/releases/next.rst @@ -4,10 +4,16 @@ What's new in the next release of Tornado In progress ----------- +New features +~~~~~~~~~~~~ + +* New method `tornado.iostream.IOStream.read_until_close` + Bug fixes ~~~~~~~~~ * `HTTPServer`: fixed exception at startup when ``socket.AI_ADDRCONFIG`` is not available, as on Windows XP * `tornado.websocket`: now works on Python 3 - +* `SimpleAsyncHTTPClient`: now works with HTTP 1.0 servers that don't send + a Content-Length header