Anonymous avatar Anonymous committed 8727dd2

the multipart parser works better with hand-crafted multipart
requests now that have extra newlines added. This fixes a bug
with setuptools uploades not handled properly (#390)

Comments (0)

Files changed (4)

 - fixed a bug with the `make_runserver` script action.
 - :meth:`MultiDict.items` and :meth:`MutiDict.iteritems` now accept an
   argument to return a pair for each value of each key.
+- the multipart parser works better with hand-crafted multipart
+  requests now that have extra newlines added.  This fixes a bug
+  with setuptools uploades not handled properly (#390)
 
 
 Version 0.5

tests/test_parsing.py

 
 
 def test_end_of_file_multipart():
-    """Test for multipart files ending unexpectedly."""
-    # this test looks innocent but it was actually timeing out in
+    """Test for multipart files ending unexpectedly"""
+    # This test looks innocent but it was actually timeing out in
     # the Werkzeug 0.5 release version (#394)
     data = (
         '--foo\r\n'
     assert not data.form
 
 
+def test_extra_newline_multipart():
+    """Test for multipart uploads with extra newlines"""
+    # this test looks innocent but it was actually timeing out in
+    # the Werkzeug 0.5 release version (#394)
+    data = (
+        '\r\n\r\n--foo\r\n'
+        'Content-Disposition: form-data; name="foo"\r\n\r\n'
+        'a string\r\n'
+        '--foo--'
+    )
+    data = Request.from_values(input_stream=StringIO(data),
+                               content_length=len(data),
+                               content_type='multipart/form-data; boundary=foo',
+                               method='POST')
+    assert not data.files
+    assert data.form['foo'] == 'a string'
+
+
 def test_nonstandard_line_endings():
     """Test nonstandard line endings of multipart form data"""
     for nl in '\n', '\r', '\r\n':

werkzeug/datastructures.py

         >>> d = MultiDict({"foo": [1, 2, 3]})
         >>> zip(d.keys(), d.listvalues()) == d.lists()
         True
-        
+
         :return: a :class:`list`
         """
         return list(self.iterlistvalues())
     iterator = chain(make_line_iter(file, buffer_size=buffer_size),
                      repeat(''))
 
+    def _find_terminator():
+        """The terminator might have some additional newlines before it.
+        There is at least one application that sends additional newlines
+        before headers (the python setuptools package).
+        """
+        for line in iterator:
+            if not line:
+                break
+            line = line.strip()
+            if line:
+                return line
+        return ''
+
     try:
-        terminator = iterator.next().strip()
+        terminator = _find_terminator()
         if terminator != next_part:
             raise ValueError('Expected boundary at start of multipart data')
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.