Solve SF bug #231249: cgi.py opens too many (temporary) files.

class FieldStorage: this patch changes read_lines() and co. to use a
StringIO() instead of a real file.  The write() calls are redirected
to a private method that replaces it with a real, external file only
when it gets too big (> 1000 bytes).

This avoids problems in forms using the multipart/form-data encoding
with many fields.  The original code created a temporary file for
*every* field (not just for file upload fields), thereby sometimes
exceeding the open file limit of some systems.

Note that the simpler solution "use a real file only for file uploads"
can't be used because the form field parser has no way to tell which
fields correspond to file uploads.

It's *possible* but extremely unlikely that this would break someone's
code; they would have to be stepping way outside the documented
interface for FieldStorage and use f.file.fileno(), or depend on
overriding make_file() to return a file-like object with additional
known properties.
This commit is contained in:
Guido van Rossum 2001-06-29 13:06:06 +00:00
parent be4f0a7748
commit 52b8c29ca7
1 changed files with 12 additions and 4 deletions

View File

@ -28,7 +28,7 @@ written in Python.
# responsible for its maintenance. # responsible for its maintenance.
# #
__version__ = "2.5" __version__ = "2.6"
# Imports # Imports
@ -633,12 +633,20 @@ class FieldStorage:
def read_lines(self): def read_lines(self):
"""Internal: read lines until EOF or outerboundary.""" """Internal: read lines until EOF or outerboundary."""
self.file = self.make_file('') self.file = self.__file = StringIO()
if self.outerboundary: if self.outerboundary:
self.read_lines_to_outerboundary() self.read_lines_to_outerboundary()
else: else:
self.read_lines_to_eof() self.read_lines_to_eof()
def __write(self, line):
if self.__file is not None:
if self.__file.tell() + len(line) > 1000:
self.file = self.make_file('')
self.file.write(self.__file.getvalue())
self.__file = None
self.file.write(line)
def read_lines_to_eof(self): def read_lines_to_eof(self):
"""Internal: read lines until EOF.""" """Internal: read lines until EOF."""
while 1: while 1:
@ -646,7 +654,7 @@ class FieldStorage:
if not line: if not line:
self.done = -1 self.done = -1
break break
self.file.write(line) self.__write(line)
def read_lines_to_outerboundary(self): def read_lines_to_outerboundary(self):
"""Internal: read lines until outerboundary.""" """Internal: read lines until outerboundary."""
@ -674,7 +682,7 @@ class FieldStorage:
line = line[:-1] line = line[:-1]
else: else:
delim = "" delim = ""
self.file.write(odelim + line) self.__write(odelim + line)
def skip_lines(self): def skip_lines(self):
"""Internal: skip lines until outer boundary if defined.""" """Internal: skip lines until outer boundary if defined."""