Repository: encode/django-rest-framework

Issue:
Test large files
I filled #3374 time ago and it was closed. Probably it wasn't very well explained, but it showed a non consistent behaviour.

Today I wrote this test that shows that large files and small files don't have the same behaviour. I couldn't fix it. My knowledge of DRF is limitated. This test, probably, will help to fix the error.

I think that fixing this test would fix #3374 and probably it would help with #3610.



Discussion:

Resolving patch:
diff --git a/rest_framework/parsers.py b/rest_framework/parsers.py
--- a/rest_framework/parsers.py
+++ b/rest_framework/parsers.py
@@ -118,6 +118,10 @@ class FileUploadParser(BaseParser):
     Parser for file upload data.
     """
     media_type = '*/*'
+    errors = {
+        'unhandled': 'FileUpload parse error - none of upload handlers can handle the stream',
+        'no_filename': 'Missing filename. Request should include a Content-Disposition header with a filename parameter.',
+    }
 
     def parse(self, stream, media_type=None, parser_context=None):
         """
@@ -134,6 +138,9 @@ def parse(self, stream, media_type=None, parser_context=None):
         upload_handlers = request.upload_handlers
         filename = self.get_filename(stream, media_type, parser_context)
 
+        if not filename:
+            raise ParseError(self.errors['no_filename'])
+
         # Note that this code is extracted from Django's handling of
         # file uploads in MultiPartParser.
         content_type = meta.get('HTTP_CONTENT_TYPE',
@@ -146,7 +153,7 @@ def parse(self, stream, media_type=None, parser_context=None):
 
         # See if the handler will want to take care of the parsing.
         for handler in upload_handlers:
-            result = handler.handle_raw_input(None,
+            result = handler.handle_raw_input(stream,
                                               meta,
                                               content_length,
                                               None,
@@ -178,10 +185,10 @@ def parse(self, stream, media_type=None, parser_context=None):
 
         for index, handler in enumerate(upload_handlers):
             file_obj = handler.file_complete(counters[index])
-            if file_obj:
+            if file_obj is not None:
                 return DataAndFiles({}, {'file': file_obj})
-        raise ParseError("FileUpload parse error - "
-                         "none of upload handlers can handle the stream")
+
+        raise ParseError(self.errors['unhandled'])
 
     def get_filename(self, stream, media_type, parser_context):
         """


Test patch:
diff --git a/tests/test_parsers.py b/tests/test_parsers.py
--- a/tests/test_parsers.py
+++ b/tests/test_parsers.py
@@ -2,8 +2,11 @@
 
 from __future__ import unicode_literals
 
+import pytest
 from django import forms
-from django.core.files.uploadhandler import MemoryFileUploadHandler
+from django.core.files.uploadhandler import (
+    MemoryFileUploadHandler, TemporaryFileUploadHandler
+)
 from django.test import TestCase
 from django.utils.six.moves import StringIO
 
@@ -63,8 +66,9 @@ def test_parse_missing_filename(self):
         parser = FileUploadParser()
         self.stream.seek(0)
         self.parser_context['request'].META['HTTP_CONTENT_DISPOSITION'] = ''
-        with self.assertRaises(ParseError):
+        with pytest.raises(ParseError) as excinfo:
             parser.parse(self.stream, None, self.parser_context)
+        assert str(excinfo.value) == 'Missing filename. Request should include a Content-Disposition header with a filename parameter.'
 
     def test_parse_missing_filename_multiple_upload_handlers(self):
         """
@@ -78,8 +82,23 @@ def test_parse_missing_filename_multiple_upload_handlers(self):
             MemoryFileUploadHandler()
         )
         self.parser_context['request'].META['HTTP_CONTENT_DISPOSITION'] = ''
-        with self.assertRaises(ParseError):
+        with pytest.raises(ParseError) as excinfo:
             parser.parse(self.stream, None, self.parser_context)
+        assert str(excinfo.value) == 'Missing filename. Request should include a Content-Disposition header with a filename parameter.'
+
+    def test_parse_missing_filename_large_file(self):
+        """
+        Parse raw file upload when filename is missing with TemporaryFileUploadHandler.
+        """
+        parser = FileUploadParser()
+        self.stream.seek(0)
+        self.parser_context['request'].upload_handlers = (
+            TemporaryFileUploadHandler(),
+        )
+        self.parser_context['request'].META['HTTP_CONTENT_DISPOSITION'] = ''
+        with pytest.raises(ParseError) as excinfo:
+            parser.parse(self.stream, None, self.parser_context)
+        assert str(excinfo.value) == 'Missing filename. Request should include a Content-Disposition header with a filename parameter.'
 
     def test_get_filename(self):
         parser = FileUploadParser()