Skip to content

Commit 722731d

Browse files
committed
Fix a bug with IOStream.read_until_close with a streaming_callback.
If the underlying socket was already closed the buffered data would be passed to the final callback rather than the streaming callback. Conflicts: website/sphinx/releases/next.rst
1 parent c113ac1 commit 722731d

File tree

2 files changed

+43
-1
lines changed

2 files changed

+43
-1
lines changed

tornado/iostream.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,14 @@ def read_until_close(self, callback, streaming_callback=None):
176176
a ``streaming_callback`` is not used.
177177
"""
178178
self._set_read_callback(callback)
179+
self._streaming_callback = stack_context.wrap(streaming_callback)
179180
if self.closed():
180-
self._run_callback(callback, self._consume(self._read_buffer_size))
181+
if self._streaming_callback is not None:
182+
self._run_callback(self._streaming_callback,
183+
self._consume(self._read_buffer_size))
184+
self._run_callback(self._read_callback,
185+
self._consume(self._read_buffer_size))
186+
self._streaming_callback = None
181187
self._read_callback = None
182188
return
183189
self._read_until_close = True

tornado/test/iostream_test.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,42 @@ def test_close_buffered_data(self):
296296
server.close()
297297
client.close()
298298

299+
def test_read_until_close_after_close(self):
300+
# Similar to test_delayed_close_callback, but read_until_close takes
301+
# a separate code path so test it separately.
302+
server, client = self.make_iostream_pair()
303+
client.set_close_callback(self.stop)
304+
try:
305+
server.write(b("1234"))
306+
server.close()
307+
self.wait()
308+
client.read_until_close(self.stop)
309+
data = self.wait()
310+
self.assertEqual(data, b("1234"))
311+
finally:
312+
server.close()
313+
client.close()
314+
315+
def test_streaming_read_until_close_after_close(self):
316+
# Same as the preceding test but with a streaming_callback.
317+
# All data should go through the streaming callback,
318+
# and the final read callback just gets an empty string.
319+
server, client = self.make_iostream_pair()
320+
client.set_close_callback(self.stop)
321+
try:
322+
server.write(b("1234"))
323+
server.close()
324+
self.wait()
325+
streaming_data = []
326+
client.read_until_close(self.stop,
327+
streaming_callback=streaming_data.append)
328+
data = self.wait()
329+
self.assertEqual(b(''), data)
330+
self.assertEqual(b('').join(streaming_data), b("1234"))
331+
finally:
332+
server.close()
333+
client.close()
334+
299335
def test_large_read_until(self):
300336
# Performance test: read_until used to have a quadratic component
301337
# so a read_until of 4MB would take 8 seconds; now it takes 0.25

0 commit comments

Comments
 (0)