mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-02-02 20:54:42 +03:00
Codebase improvements on FileUploadParser
* Added docstrings. * Added `FileUploadParser.get_filename` to make it easier to override. * Added url kwargs filename detection step. * Updated tests corresponding to these changes.
This commit is contained in:
parent
318fdaabe5
commit
e36e4f48ad
|
@ -215,16 +215,19 @@ class FileUploadParser(BaseParser):
|
||||||
media_type = '*/*'
|
media_type = '*/*'
|
||||||
|
|
||||||
def parse(self, stream, media_type=None, parser_context=None):
|
def parse(self, stream, media_type=None, parser_context=None):
|
||||||
|
"""
|
||||||
|
Returns a DataAndFiles object.
|
||||||
|
|
||||||
|
`.data` will be None (we expect request body to be a file content).
|
||||||
|
`.files` will be a `QueryDict` containing one 'file' elemnt - a parsed file.
|
||||||
|
"""
|
||||||
|
|
||||||
parser_context = parser_context or {}
|
parser_context = parser_context or {}
|
||||||
request = parser_context['request']
|
request = parser_context['request']
|
||||||
encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
|
encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
|
||||||
meta = request.META
|
meta = request.META
|
||||||
|
upload_handlers = request.upload_handlers
|
||||||
try:
|
filename = self.get_filename(stream, media_type, parser_context)
|
||||||
disposition = parse_header(meta['HTTP_CONTENT_DISPOSITION'])
|
|
||||||
filename = disposition[1]['filename']
|
|
||||||
except KeyError:
|
|
||||||
filename = None
|
|
||||||
|
|
||||||
content_type = meta.get('HTTP_CONTENT_TYPE', meta.get('CONTENT_TYPE', ''))
|
content_type = meta.get('HTTP_CONTENT_TYPE', meta.get('CONTENT_TYPE', ''))
|
||||||
try:
|
try:
|
||||||
|
@ -233,28 +236,28 @@ class FileUploadParser(BaseParser):
|
||||||
content_length = None
|
content_length = None
|
||||||
|
|
||||||
# See if the handler will want to take care of the parsing.
|
# See if the handler will want to take care of the parsing.
|
||||||
for handler in request.upload_handlers:
|
for handler in upload_handlers:
|
||||||
result = handler.handle_raw_input(None,
|
result = handler.handle_raw_input(None,
|
||||||
meta,
|
meta,
|
||||||
content_length,
|
content_length,
|
||||||
None,
|
None,
|
||||||
encoding)
|
encoding)
|
||||||
if result is not None:
|
if result is not None:
|
||||||
return DataAndFiles(result[0], {'file': result[1]})
|
return DataAndFiles(None, {'file': result[1]})
|
||||||
|
|
||||||
possible_sizes = [x.chunk_size for x in request.upload_handlers if x.chunk_size]
|
possible_sizes = [x.chunk_size for x in upload_handlers if x.chunk_size]
|
||||||
chunk_size = min([2**31-4] + possible_sizes)
|
chunk_size = min([2**31-4] + possible_sizes)
|
||||||
chunks = ChunkIter(stream, chunk_size)
|
chunks = ChunkIter(stream, chunk_size)
|
||||||
counters = [0] * len(request.upload_handlers)
|
counters = [0] * len(upload_handlers)
|
||||||
|
|
||||||
for handler in request.upload_handlers:
|
for handler in upload_handlers:
|
||||||
try:
|
try:
|
||||||
handler.new_file(None, filename, content_type, content_length, encoding)
|
handler.new_file(None, filename, content_type, content_length, encoding)
|
||||||
except StopFutureHandlers:
|
except StopFutureHandlers:
|
||||||
break
|
break
|
||||||
|
|
||||||
for chunk in chunks:
|
for chunk in chunks:
|
||||||
for i, handler in enumerate(request.upload_handlers):
|
for i, handler in enumerate(upload_handlers):
|
||||||
chunk_length = len(chunk)
|
chunk_length = len(chunk)
|
||||||
chunk = handler.receive_data_chunk(chunk, counters[i])
|
chunk = handler.receive_data_chunk(chunk, counters[i])
|
||||||
counters[i] += chunk_length
|
counters[i] += chunk_length
|
||||||
|
@ -262,7 +265,23 @@ class FileUploadParser(BaseParser):
|
||||||
# If the chunk received by the handler is None, then don't continue.
|
# If the chunk received by the handler is None, then don't continue.
|
||||||
break
|
break
|
||||||
|
|
||||||
for i, handler in enumerate(request.upload_handlers):
|
for i, handler in enumerate(upload_handlers):
|
||||||
file_obj = handler.file_complete(counters[i])
|
file_obj = handler.file_complete(counters[i])
|
||||||
if file_obj:
|
if file_obj:
|
||||||
return DataAndFiles(None, {'file': file_obj})
|
return DataAndFiles(None, {'file': file_obj})
|
||||||
|
|
||||||
|
def get_filename(self, stream, media_type, parser_context):
|
||||||
|
"""
|
||||||
|
Detects the uploaded file name. First searches a 'filename' url kwarg.
|
||||||
|
Then tries to parse Content-Disposition header.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return parser_context['kwargs']['filename']
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
meta = parser_context['request'].META
|
||||||
|
disposition = parse_header(meta['HTTP_CONTENT_DISPOSITION'])
|
||||||
|
return disposition[1]['filename']
|
||||||
|
except (AttributeError, KeyError):
|
||||||
|
pass
|
||||||
|
|
|
@ -99,11 +99,17 @@ class TestFileUploadParser(TestCase):
|
||||||
'HTTP_CONTENT_DISPOSITION': 'Content-Disposition: inline; filename=file.txt'.encode('utf-8'),
|
'HTTP_CONTENT_DISPOSITION': 'Content-Disposition: inline; filename=file.txt'.encode('utf-8'),
|
||||||
'HTTP_CONTENT_LENGTH': 14,
|
'HTTP_CONTENT_LENGTH': 14,
|
||||||
}
|
}
|
||||||
self.parser_context = {'request': request}
|
self.parser_context = {'request': request, 'kwargs': {}}
|
||||||
|
|
||||||
def test_parse(self):
|
def test_parse(self):
|
||||||
""" Make sure the `QueryDict` works OK """
|
""" Make sure the `QueryDict` works OK """
|
||||||
parser = FileUploadParser()
|
parser = FileUploadParser()
|
||||||
data_and_files = parser.parse(self.stream, parser_context=self.parser_context)
|
self.stream.seek(0)
|
||||||
|
data_and_files = parser.parse(self.stream, None, self.parser_context)
|
||||||
file_obj = data_and_files.files['file']
|
file_obj = data_and_files.files['file']
|
||||||
self.assertEqual(file_obj._size, 14)
|
self.assertEqual(file_obj._size, 14)
|
||||||
|
|
||||||
|
def test_get_filename(self):
|
||||||
|
parser = FileUploadParser()
|
||||||
|
filename = parser.get_filename(self.stream, None, self.parser_context)
|
||||||
|
self.assertEqual(filename, 'file.txt'.encode('utf-8'))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user