Commit 9dabd1f8 authored by Jacob Kaplan-Moss's avatar Jacob Kaplan-Moss
Browse files

Fixed #7651: uploading multiple files with the same name now work. Also, in...

Fixed #7651: uploading multiple files with the same name now work. Also, in order to test the problem the test client now handles uploading multiple files at once. Patch from Mike Axiak.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@7858 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 72544950
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -136,6 +136,7 @@ class MultiPartParser(object):
                    # since we cannot be sure a file is complete until
                    # we hit the next boundary/part of the multipart content.
                    self.handle_file_complete(old_field_name, counters)
                    old_field_name = None

                try:
                    disposition = meta_data['content-disposition'][1]
+32 −19
Original line number Diff line number Diff line
@@ -90,19 +90,21 @@ def encode_multipart(boundary, data):
    """
    lines = []
    to_str = lambda s: smart_str(s, settings.DEFAULT_CHARSET)

    # Not by any means perfect, but good enough for our purposes.
    is_file = lambda thing: hasattr(thing, "read") and callable(thing.read)

    # Each bit of the multipart form data could be either a form value or a
    # file, or a *list* of form values and/or files. Remember that HTTP field
    # names can be duplicated!
    for (key, value) in data.items():
        if isinstance(value, file):
            lines.extend([
                '--' + boundary,
                'Content-Disposition: form-data; name="%s"; filename="%s"' \
                    % (to_str(key), to_str(os.path.basename(value.name))),
                'Content-Type: application/octet-stream',
                '',
                value.read()
            ])
        else:
            if not isinstance(value, basestring) and is_iterable(value):
        if is_file(value):
            lines.extend(encode_file(boundary, key, value))
        elif not isinstance(value, basestring) and is_iterable(value):
            for item in value:
                if is_file(item):
                    lines.extend(encode_file(boundary, key, item))
                else:
                    lines.extend([
                        '--' + boundary,
                        'Content-Disposition: form-data; name="%s"' % to_str(key),
@@ -123,6 +125,17 @@ def encode_multipart(boundary, data):
    ])
    return '\r\n'.join(lines)

def encode_file(boundary, key, file):
    to_str = lambda s: smart_str(s, settings.DEFAULT_CHARSET)
    return [
        '--' + boundary,
        'Content-Disposition: form-data; name="%s"; filename="%s"' \
            % (to_str(key), to_str(os.path.basename(file.name))),
        'Content-Type: application/octet-stream',
        '',
        file.read()
    ]
    
class Client:
    """
    A class that can act as a client for testing purposes.
+27 −4
Original line number Diff line number Diff line
@@ -156,3 +156,26 @@ class FileUploadTests(TestCase):
            {'f': open(f.name)}
        )

    def test_fileupload_getlist(self):
        file1 = tempfile.NamedTemporaryFile()
        file1.write('a' * (2 ** 23))

        file2 = tempfile.NamedTemporaryFile()
        file2.write('a' * (2 * 2 ** 18))

        file2a = tempfile.NamedTemporaryFile()
        file2a.write('a' * (5 * 2 ** 20))

        response = self.client.post('/file_uploads/getlist_count/', {
            'file1': open(file1.name),
            'field1': u'test',
            'field2': u'test3',
            'field3': u'test5',
            'field4': u'test6',
            'field5': u'test7',
            'file2': (open(file2.name), open(file2a.name))
        })
        got = simplejson.loads(response.content)

        self.assertEqual(got.get('file1'), 1)
        self.assertEqual(got.get('file2'), 2)
+1 −0
Original line number Diff line number Diff line
@@ -7,4 +7,5 @@ urlpatterns = patterns('',
    (r'^echo/$',            views.file_upload_echo),
    (r'^quota/$',           views.file_upload_quota),
    (r'^quota/broken/$',    views.file_upload_quota_broken),
    (r'^getlist_count/$',   views.file_upload_getlist_count),
)
+11 −1
Original line number Diff line number Diff line
@@ -68,3 +68,13 @@ def file_upload_quota_broken(request):
    response = file_upload_echo(request)
    request.upload_handlers.insert(0, QuotaUploadHandler())
    return response

def file_upload_getlist_count(request):
    """
    Check the .getlist() function to ensure we receive the correct number of files.
    """
    file_counts = {}

    for key in request.FILES.keys():
        file_counts[key] = len(request.FILES.getlist(key))
    return HttpResponse(simplejson.dumps(file_counts))