[Python-Dev] Proposed patch to cgi.py for 2.1 -- please review!

Guido van Rossum guido@digicool.com
Wed, 11 Apr 2001 21:46:21 -0500


I'd like some feedback on the patch below to cgi.py.  For background,
read SF bug #231249:

  http://sourceforge.net/tracker/?func=detail&aid=231249&group_id=5470&atid=105470

The problem is that when a POST request is received with a
Content-type of multipart/form-data, an anonymous temporary file is
created and kept open for each part -- whether or not it is a
file-upload!  For forms with many fields, this can use up more file
descriptors than the server is allowed to have.  There's no way to
tell whether a particular part is a file or not; the filename are
optional and the input field type is not available here.  My solution
uses a StringIO and transparently switches to a temporary file object
when a part grows larger than 1000 characters.

Question: does this look like it could break anything?  I know the cgi
module is used a lot so any change in semantics, however subtle, could
potentially cause problems for some poor soul out there...

(It could break code if someone tries to use the fileno() on a field
object's file attribute.)

--Guido van Rossum (home page: http://www.python.org/~guido/)

Index: cgi.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/cgi.py,v
retrieving revision 1.63
diff -c -r1.63 cgi.py
*** cgi.py	2001/03/19 13:40:44	1.63
--- cgi.py	2001/04/11 20:18:20
***************
*** 633,644 ****
  
      def read_lines(self):
          """Internal: read lines until EOF or outerboundary."""
!         self.file = self.make_file('')
          if self.outerboundary:
              self.read_lines_to_outerboundary()
          else:
              self.read_lines_to_eof()
  
      def read_lines_to_eof(self):
          """Internal: read lines until EOF."""
          while 1:
--- 633,652 ----
  
      def read_lines(self):
          """Internal: read lines until EOF or outerboundary."""
!         self.file = self.__file = StringIO()
          if self.outerboundary:
              self.read_lines_to_outerboundary()
          else:
              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):
          """Internal: read lines until EOF."""
          while 1:
***************
*** 646,652 ****
              if not line:
                  self.done = -1
                  break
!             self.file.write(line)
  
      def read_lines_to_outerboundary(self):
          """Internal: read lines until outerboundary."""
--- 654,660 ----
              if not line:
                  self.done = -1
                  break
!             self.__write(line)
  
      def read_lines_to_outerboundary(self):
          """Internal: read lines until outerboundary."""
***************
*** 674,680 ****
                  line = line[:-1]
              else:
                  delim = ""
!             self.file.write(odelim + line)
  
      def skip_lines(self):
          """Internal: skip lines until outer boundary if defined."""
--- 682,688 ----
                  line = line[:-1]
              else:
                  delim = ""
!             self.__write(odelim + line)
  
      def skip_lines(self):
          """Internal: skip lines until outer boundary if defined."""