Fixed #15018 -- Corrected the handling of LimitedStream under one edge case involving size restricted buffers and newlines. Thanks to xjdrew for the report, and aaugustin for the patch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@15222 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Russell Keith-Magee 2011-01-16 07:31:35 +00:00
parent 1ca9e95d4e
commit b4f0921463
2 changed files with 29 additions and 2 deletions

View File

@ -96,9 +96,10 @@ class LimitedStream(object):
return result return result
def readline(self, size=None): def readline(self, size=None):
while '\n' not in self.buffer or \ while '\n' not in self.buffer and \
(size is not None and len(self.buffer) < size): (size is None or len(self.buffer) < size):
if size: if size:
# since size is not None here, len(self.buffer) < size
chunk = self._read_limited(size - len(self.buffer)) chunk = self._read_limited(size - len(self.buffer))
else: else:
chunk = self._read_limited() chunk = self._read_limited()

View File

@ -102,15 +102,21 @@ class RequestsTests(unittest.TestCase):
# Read all of a limited stream # Read all of a limited stream
stream = LimitedStream(StringIO('test'), 2) stream = LimitedStream(StringIO('test'), 2)
self.assertEqual(stream.read(), 'te') self.assertEqual(stream.read(), 'te')
# Reading again returns nothing.
self.assertEqual(stream.read(), '')
# Read a number of characters greater than the stream has to offer # Read a number of characters greater than the stream has to offer
stream = LimitedStream(StringIO('test'), 2) stream = LimitedStream(StringIO('test'), 2)
self.assertEqual(stream.read(5), 'te') self.assertEqual(stream.read(5), 'te')
# Reading again returns nothing.
self.assertEqual(stream.readline(5), '')
# Read sequentially from a stream # Read sequentially from a stream
stream = LimitedStream(StringIO('12345678'), 8) stream = LimitedStream(StringIO('12345678'), 8)
self.assertEqual(stream.read(5), '12345') self.assertEqual(stream.read(5), '12345')
self.assertEqual(stream.read(5), '678') self.assertEqual(stream.read(5), '678')
# Reading again returns nothing.
self.assertEqual(stream.readline(5), '')
# Read lines from a stream # Read lines from a stream
stream = LimitedStream(StringIO('1234\n5678\nabcd\nefgh\nijkl'), 24) stream = LimitedStream(StringIO('1234\n5678\nabcd\nefgh\nijkl'), 24)
@ -129,6 +135,26 @@ class RequestsTests(unittest.TestCase):
# Read everything else. # Read everything else.
self.assertEqual(stream.readline(), 'ijkl') self.assertEqual(stream.readline(), 'ijkl')
# Regression for #15018
# If a stream contains a newline, but the provided length
# is less than the number of provided characters, the newline
# doesn't reset the available character count
stream = LimitedStream(StringIO('1234\nabcdef'), 9)
self.assertEqual(stream.readline(10), '1234\n')
self.assertEqual(stream.readline(3), 'abc')
# Now expire the available characters
self.assertEqual(stream.readline(3), 'd')
# Reading again returns nothing.
self.assertEqual(stream.readline(2), '')
# Same test, but with read, not readline.
stream = LimitedStream(StringIO('1234\nabcdef'), 9)
self.assertEqual(stream.read(6), '1234\na')
self.assertEqual(stream.read(2), 'bc')
self.assertEqual(stream.read(2), 'd')
self.assertEqual(stream.read(2), '')
self.assertEqual(stream.read(), '')
def test_stream(self): def test_stream(self):
request = WSGIRequest({'REQUEST_METHOD': 'POST', 'wsgi.input': StringIO('name=value')}) request = WSGIRequest({'REQUEST_METHOD': 'POST', 'wsgi.input': StringIO('name=value')})
self.assertEqual(request.read(), 'name=value') self.assertEqual(request.read(), 'name=value')