You are viewing a plain text version of this content. The canonical link for it is here.
Posted to mod_python-dev@quetz.apache.org by rm...@pobox.com on 2002/10/03 19:04:42 UTC

Bug in util.py's handling of Content-Type: multipart/*

I've found a bug in mod_python 3.0.0 beta 2. When a form is submitted
with ENCTYPE="multipart/form-data", util.py will create a Field object
for each named form element, but will also create a Field object with
name = None and value = ''. Then when publisher.py would pass the
keyword arguments to the callable object (see my previous patch that
allows for keyword arguments), that Field object would get translated to
a {None: ''} entry in the dictionary, and Python would raise a TypeError
exception: "Keywords must be strings".

I traced the bug back to util.py's FieldStorage.__init__() method. When
it parses POST requests with content type "multipart/*", each line is
read in with:

    line = req.readline()

and then the lines are stripped:

    sline = line.strip()

But the "sline = line.strip()" code was not duplicated everywhere that
"line = req.readline()" appeared. Thus, the end-of-while-loop condition
of "sline == (boundary + '--')" was never fulfilled.

Besides this, the end-of-while-loop check was in the wrong place. Having
it after the code to create a Field object was causing a last Field
object to be created based on an empty string; this meant that the "if
disp_options.has_key('name')" test was (naturally) failing, so the name
local variable would be set to None, and then a Field object would be
created with name=None. This was what was causing my keyword argument
passing to break in publisher.py.

Finally, I found one other bug in util.py: string objects don't have a
method splitfields() -- the method name is split(). So the following
line was failing:

    plist = map(lambda a: a.strip(), line.splitfields(';'))

Instead, it should be:

    plist = map(lambda a: a.strip(), line.split(';'))

I created a patch to fix all three of these errors; you'll find it at
the end of this message, after my signature.

-- 
Robin Munn
rmunn@pobox.com



--- lib/python/mod_python/orig.util.py	2002-10-03 11:24:17.000000000 -0500
+++ lib/python/mod_python/util.py	2002-10-03 11:26:00.000000000 -0500
@@ -168,6 +168,7 @@
                 sline = line.strip()
                 while line and sline != boundary:
                     line = req.readline()
+                    sline = line.strip()
 
                 while 1:
 
@@ -177,6 +178,10 @@
                     disp, disp_options = None, {}
                     headers = apache.make_table()
                     line = req.readline()
+                    sline = line.strip()
+                    if not line or sline == (boundary + "--"):
+                        break
+
                     while line and line not in ["\n", "\r\n"]:
                         h, v = line.split(":", 1)
                         headers.add(h, v)
@@ -186,6 +191,7 @@
                         elif h == "content-type":
                             ctype, type_options = parse_header(v)
                         line = req.readline()
+                        sline = line.strip()
 
                     if disp_options.has_key("name"):
                         name = disp_options["name"]
@@ -211,9 +217,6 @@
 
                     self.list.append(field)
 
-                    if not line or sline == (boundary + "--"):
-                        break
-
             else:
                 # we don't understand this content-type
                 raise apache.SERVER_RETURN, apache.HTTP_NOT_IMPLEMENTED
@@ -294,7 +297,7 @@
 
     """
     
-    plist = map(lambda a: a.strip(), line.splitfields(';'))
+    plist = map(lambda a: a.strip(), line.split(';'))
     key = plist[0].lower()
     del plist[0]
     pdict = {}