summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/http/multipartparser.py1
-rw-r--r--django/test/client.py51
-rw-r--r--tests/regressiontests/file_uploads/tests.py31
-rw-r--r--tests/regressiontests/file_uploads/urls.py1
-rw-r--r--tests/regressiontests/file_uploads/views.py12
5 files changed, 72 insertions, 24 deletions
diff --git a/django/http/multipartparser.py b/django/http/multipartparser.py
index 8bed5681cf..fc48aa9e7b 100644
--- a/django/http/multipartparser.py
+++ b/django/http/multipartparser.py
@@ -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]
diff --git a/django/test/client.py b/django/test/client.py
index 87731043a7..47c12a4ca1 100644
--- a/django/test/client.py
+++ b/django/test/client.py
@@ -90,32 +90,34 @@ 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):
- for item in 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),
'',
to_str(item)
])
- else:
- lines.extend([
- '--' + boundary,
- 'Content-Disposition: form-data; name="%s"' % to_str(key),
- '',
- to_str(value)
- ])
+ else:
+ lines.extend([
+ '--' + boundary,
+ 'Content-Disposition: form-data; name="%s"' % to_str(key),
+ '',
+ to_str(value)
+ ])
lines.extend([
'--' + boundary + '--',
@@ -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.
diff --git a/tests/regressiontests/file_uploads/tests.py b/tests/regressiontests/file_uploads/tests.py
index 8992298470..8a61966240 100644
--- a/tests/regressiontests/file_uploads/tests.py
+++ b/tests/regressiontests/file_uploads/tests.py
@@ -147,12 +147,35 @@ class FileUploadTests(TestCase):
def test_broken_custom_upload_handler(self):
f = tempfile.NamedTemporaryFile()
f.write('a' * (2 ** 21))
-
+
# AttributeError: You cannot alter upload handlers after the upload has been processed.
self.assertRaises(
AttributeError,
self.client.post,
- '/file_uploads/quota/broken/',
+ '/file_uploads/quota/broken/',
{'f': open(f.name)}
- )
- \ No newline at end of file
+ )
+
+ 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)
diff --git a/tests/regressiontests/file_uploads/urls.py b/tests/regressiontests/file_uploads/urls.py
index 529bee312d..cc4cc80fdd 100644
--- a/tests/regressiontests/file_uploads/urls.py
+++ b/tests/regressiontests/file_uploads/urls.py
@@ -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),
)
diff --git a/tests/regressiontests/file_uploads/views.py b/tests/regressiontests/file_uploads/views.py
index 833cf90531..dfa877da3a 100644
--- a/tests/regressiontests/file_uploads/views.py
+++ b/tests/regressiontests/file_uploads/views.py
@@ -67,4 +67,14 @@ def file_upload_quota_broken(request):
"""
response = file_upload_echo(request)
request.upload_handlers.insert(0, QuotaUploadHandler())
- return response \ No newline at end of file
+ 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))