Merge pull request #1838 from jbittel/fix-encoded-filename-rfc6266

Support RFC6266 encoded filenames
This commit is contained in:
Tom Christie 2014-09-06 07:13:12 +01:00
commit 5bbfef36f4
2 changed files with 42 additions and 2 deletions

View File

@ -11,7 +11,7 @@ from django.http import QueryDict
from django.http.multipartparser import MultiPartParser as DjangoMultiPartParser from django.http.multipartparser import MultiPartParser as DjangoMultiPartParser
from django.http.multipartparser import MultiPartParserError, parse_header, ChunkIter from django.http.multipartparser import MultiPartParserError, parse_header, ChunkIter
from django.utils import six from django.utils import six
from rest_framework.compat import etree, yaml, force_text from rest_framework.compat import etree, yaml, force_text, urlparse
from rest_framework.exceptions import ParseError from rest_framework.exceptions import ParseError
from rest_framework import renderers from rest_framework import renderers
import json import json
@ -290,6 +290,22 @@ class FileUploadParser(BaseParser):
try: try:
meta = parser_context['request'].META meta = parser_context['request'].META
disposition = parse_header(meta['HTTP_CONTENT_DISPOSITION'].encode('utf-8')) disposition = parse_header(meta['HTTP_CONTENT_DISPOSITION'].encode('utf-8'))
return force_text(disposition[1]['filename']) filename_parm = disposition[1]
if 'filename*' in filename_parm:
return self.get_encoded_filename(filename_parm)
return force_text(filename_parm['filename'])
except (AttributeError, KeyError): except (AttributeError, KeyError):
pass pass
def get_encoded_filename(self, filename_parm):
"""
Handle encoded filenames per RFC6266. See also:
http://tools.ietf.org/html/rfc2231#section-4
"""
encoded_filename = force_text(filename_parm['filename*'])
try:
charset, lang, filename = encoded_filename.split('\'', 2)
filename = urlparse.unquote(filename)
except (ValueError, LookupError):
filename = force_text(filename_parm['filename'])
return filename

View File

@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from rest_framework.compat import StringIO from rest_framework.compat import StringIO
from django import forms from django import forms
@ -113,3 +115,25 @@ class TestFileUploadParser(TestCase):
parser = FileUploadParser() parser = FileUploadParser()
filename = parser.get_filename(self.stream, None, self.parser_context) filename = parser.get_filename(self.stream, None, self.parser_context)
self.assertEqual(filename, 'file.txt') 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\'en-us\'ÀĥƦ.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