Fixes issue 27777: cgi.FieldStorage can't parse simple body with Content-Length and no Content-Disposition

- If content length is present, read at most len bytes.
- When reading `read_lines_to_eof` use `read` instead of `readline`.
- Use `self.__write` even when content length is present and > 1000.
This commit is contained in:
Aron Podrigal 2019-02-05 16:19:03 -06:00
parent b0689ae7f9
commit 8e491e7ba5
2 changed files with 20 additions and 13 deletions

View File

@ -667,7 +667,7 @@ class FieldStorage:
def read_single(self):
"""Internal: read an atomic part."""
if self.length >= 0:
self.read_binary()
self.read_content()
self.skip_lines()
else:
self.read_lines()
@ -675,31 +675,30 @@ class FieldStorage:
bufsize = 8*1024 # I/O buffering size for copy to file
def read_binary(self):
"""Internal: read binary data."""
self.file = self.make_file()
def read_content(self):
"""Internal: read data up until content-length len."""
if self.length > 1000:
self.file = self.make_file()
else:
self.file = self.io_object()
todo = self.length
if todo >= 0:
while todo > 0:
data = self.fp.read(min(todo, self.bufsize)) # bytes
if not isinstance(data, bytes):
raise ValueError("%s should return bytes, got %s"
% (self.fp, type(data).__name__))
self.bytes_read += len(data)
if not data:
self.done = -1
break
self.file.write(data)
self.__write(data)
todo = todo - len(data)
def read_lines(self):
"""Internal: read lines until EOF or outerboundary."""
if self._binary_file:
self.file = self.__file = BytesIO() # store data as bytes for files
else:
self.file = self.__file = StringIO() # as strings for other fields
self.file = self.__file = self.io_object()
if self.outerboundary:
self.read_lines_to_outerboundary()
elif self.length >= 0:
self.read_content()
else:
self.read_lines_to_eof()
@ -721,7 +720,7 @@ class FieldStorage:
def read_lines_to_eof(self):
"""Internal: read lines until EOF."""
while 1:
line = self.fp.readline(1<<16) # bytes
line = self.fp.read(1<<16) # bytes
self.bytes_read += len(line)
if not line:
self.done = -1
@ -830,6 +829,12 @@ class FieldStorage:
return tempfile.TemporaryFile("w+",
encoding=self.encoding, newline = '\n')
def io_object(self):
if self._binary_file:
return BytesIO() # store data as bytes for files
else:
return StringIO() # as strings for other fields
# Test/debug code
# ===============

View File

@ -0,0 +1,2 @@
Fixes a bug in :mod:`cgi` when a request has a "Content-Length" header but
without "Content-Disposition" headers.