diff --git a/rest_framework/parsers.py b/rest_framework/parsers.py index 4990971b8..529e640ea 100644 --- a/rest_framework/parsers.py +++ b/rest_framework/parsers.py @@ -10,7 +10,7 @@ from django.core.files.uploadhandler import StopFutureHandlers from django.http import QueryDict from django.http.multipartparser import MultiPartParser as DjangoMultiPartParser from django.http.multipartparser import MultiPartParserError, parse_header, ChunkIter -from rest_framework.compat import etree, six, yaml, force_text +from rest_framework.compat import etree, six, yaml, force_text, urlparse from rest_framework.exceptions import ParseError from rest_framework import renderers import json @@ -289,6 +289,17 @@ class FileUploadParser(BaseParser): try: meta = parser_context['request'].META disposition = parse_header(meta['HTTP_CONTENT_DISPOSITION'].encode('utf-8')) - return force_text(disposition[1]['filename']) + + if 'filename*' in disposition[1]: + filename_encoded = force_text(disposition[1]['filename*']) + try: + charset, filename_encoded = filename_encoded.split('\'\'', 1) + filename = urlparse.unquote(filename_encoded) + except (ValueError, LookupError): + filename = force_text(disposition[1]['filename']) + else: + filename = force_text(disposition[1]['filename']) + + return filename except (AttributeError, KeyError): pass diff --git a/rest_framework/tests/test_parsers.py b/rest_framework/tests/test_parsers.py index 8af906772..d19b46519 100644 --- a/rest_framework/tests/test_parsers.py +++ b/rest_framework/tests/test_parsers.py @@ -1,3 +1,5 @@ +#-*- coding: utf-8 -*- + from __future__ import unicode_literals from rest_framework.compat import StringIO from django import forms @@ -113,3 +115,23 @@ class TestFileUploadParser(TestCase): parser = FileUploadParser() filename = parser.get_filename(self.stream, None, self.parser_context) self.assertEqual(filename, 'file.txt') + + def test_get_encoded_filename(self): + parser = FileUploadParser() + + self.__replace_content_disposition('inline; filename*=utf-8\'\'ÀĥƦ.txt') + filename = parser.get_filename(self.stream, None, self.parser_context) + self.assertEqual(filename, 'ÀĥƦ.txt') + + self.__replace_content_disposition('inline; filename=fallback.txt; filename*=utf-8\'\'ÀĥƦ.txt') + filename = parser.get_filename(self.stream, None, self.parser_context) + self.assertEqual(filename, 'ÀĥƦ.txt') + + self.__replace_content_disposition('inline; filename=fallback.txt; filename*=utf-8--ÀĥƦ.txt') + filename = parser.get_filename(self.stream, None, self.parser_context) + self.assertEqual(filename, 'fallback.txt') + + def __replace_content_disposition(self, disposition): + self.parser_context['request'].META['HTTP_CONTENT_DISPOSITION'] = disposition + +