]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Fix zero-byte writes in IOStream.
authorBen Darnell <ben@bendarnell.com>
Tue, 25 Oct 2011 05:02:15 +0000 (22:02 -0700)
committerBen Darnell <ben@bendarnell.com>
Tue, 25 Oct 2011 05:02:15 +0000 (22:02 -0700)
Previously zero-byte writes would cause the CPU to run at 100% and
would never call their callback (if any).

tornado/iostream.py
tornado/test/iostream_test.py

index 6536527530a1821b0160735cf14a29d25ed8bbb3..6b02b19aed11d61a8bba08803c89c368baa110c7 100644 (file)
@@ -211,7 +211,10 @@ class IOStream(object):
         """
         assert isinstance(data, bytes_type)
         self._check_closed()
-        self._write_buffer.append(data)
+        if data:
+            # We use bool(_write_buffer) as a proxy for write_buffer_size>0,
+            # so never put empty strings in the buffer.
+            self._write_buffer.append(data)
         self._write_callback = stack_context.wrap(callback)
         self._handle_write()
         if self._write_buffer:
index f35614da97596d6ee79d778572c84697f1de734a..43b2e17bcd94e7d8998201340d451c1839a25933 100644 (file)
@@ -1,4 +1,5 @@
 from tornado import netutil
+from tornado.ioloop import IOLoop
 from tornado.iostream import IOStream
 from tornado.testing import AsyncHTTPTestCase, LogTrapTestCase, get_unused_port
 from tornado.util import b
@@ -57,6 +58,16 @@ class TestIOStream(AsyncHTTPTestCase, LogTrapTestCase):
         data = self.wait()
         self.assertEqual(data, b("200"))
 
+    def test_write_zero_bytes(self):
+        # Attempting to write zero bytes should run the callback without
+        # going into an infinite loop.
+        server, client = self.make_iostream_pair()
+        server.write(b(''), callback=self.stop)
+        self.wait()
+        # As a side effect, the stream is now listening for connection
+        # close (if it wasn't already), but is not listening for writes
+        self.assertEqual(server._state, IOLoop.READ|IOLoop.ERROR)
+
     def test_connection_refused(self):
         # When a connection is refused, the connect callback should not
         # be run.  (The kqueue IOLoop used to behave differently from the