2014-09-06 02:33:47 +04:00
|
|
|
# -*- coding: utf-8 -*-
|
2014-04-14 15:02:52 +04:00
|
|
|
|
2013-02-05 00:55:35 +04:00
|
|
|
from __future__ import unicode_literals
|
2015-06-25 23:55:51 +03:00
|
|
|
|
2016-08-01 20:44:58 +03:00
|
|
|
import pytest
|
2012-09-20 16:06:27 +04:00
|
|
|
from django import forms
|
2016-08-01 20:44:58 +03:00
|
|
|
from django.core.files.uploadhandler import (
|
|
|
|
MemoryFileUploadHandler, TemporaryFileUploadHandler
|
|
|
|
)
|
2016-09-21 13:49:09 +03:00
|
|
|
from django.http.request import RawPostDataException
|
2012-09-20 16:06:27 +04:00
|
|
|
from django.test import TestCase
|
2014-12-04 05:11:42 +03:00
|
|
|
from django.utils.six.moves import StringIO
|
2015-06-25 23:55:51 +03:00
|
|
|
|
2014-12-02 16:52:46 +03:00
|
|
|
from rest_framework.exceptions import ParseError
|
2016-09-21 13:49:09 +03:00
|
|
|
from rest_framework.parsers import (
|
|
|
|
FileUploadParser, FormParser, JSONParser, MultiPartParser
|
|
|
|
)
|
|
|
|
from rest_framework.request import Request
|
|
|
|
from rest_framework.test import APIRequestFactory
|
2012-09-20 16:06:27 +04:00
|
|
|
|
|
|
|
|
|
|
|
class Form(forms.Form):
|
|
|
|
field1 = forms.CharField(max_length=3)
|
|
|
|
field2 = forms.CharField()
|
|
|
|
|
|
|
|
|
|
|
|
class TestFormParser(TestCase):
|
|
|
|
def setUp(self):
|
|
|
|
self.string = "field1=abc&field2=defghijk"
|
|
|
|
|
|
|
|
def test_parse(self):
|
|
|
|
""" Make sure the `QueryDict` works OK """
|
|
|
|
parser = FormParser()
|
|
|
|
|
|
|
|
stream = StringIO(self.string)
|
|
|
|
data = parser.parse(stream)
|
|
|
|
|
|
|
|
self.assertEqual(Form(data).is_valid(), True)
|
|
|
|
|
|
|
|
|
2013-05-02 23:39:08 +04:00
|
|
|
class TestFileUploadParser(TestCase):
|
|
|
|
def setUp(self):
|
|
|
|
class MockRequest(object):
|
|
|
|
pass
|
|
|
|
from io import BytesIO
|
|
|
|
self.stream = BytesIO(
|
|
|
|
"Test text file".encode('utf-8')
|
|
|
|
)
|
|
|
|
request = MockRequest()
|
|
|
|
request.upload_handlers = (MemoryFileUploadHandler(),)
|
|
|
|
request.META = {
|
2014-04-14 12:28:41 +04:00
|
|
|
'HTTP_CONTENT_DISPOSITION': 'Content-Disposition: inline; filename=file.txt',
|
2013-05-02 23:39:08 +04:00
|
|
|
'HTTP_CONTENT_LENGTH': 14,
|
|
|
|
}
|
2013-05-04 12:58:21 +04:00
|
|
|
self.parser_context = {'request': request, 'kwargs': {}}
|
2013-05-02 23:39:08 +04:00
|
|
|
|
|
|
|
def test_parse(self):
|
2014-12-02 16:52:46 +03:00
|
|
|
"""
|
|
|
|
Parse raw file upload.
|
|
|
|
"""
|
2013-05-02 23:39:08 +04:00
|
|
|
parser = FileUploadParser()
|
2013-05-04 12:58:21 +04:00
|
|
|
self.stream.seek(0)
|
|
|
|
data_and_files = parser.parse(self.stream, None, self.parser_context)
|
2013-05-02 23:39:08 +04:00
|
|
|
file_obj = data_and_files.files['file']
|
|
|
|
self.assertEqual(file_obj._size, 14)
|
2013-05-04 12:58:21 +04:00
|
|
|
|
2014-12-02 16:52:46 +03:00
|
|
|
def test_parse_missing_filename(self):
|
|
|
|
"""
|
|
|
|
Parse raw file upload when filename is missing.
|
|
|
|
"""
|
|
|
|
parser = FileUploadParser()
|
|
|
|
self.stream.seek(0)
|
|
|
|
self.parser_context['request'].META['HTTP_CONTENT_DISPOSITION'] = ''
|
2016-08-01 20:44:58 +03:00
|
|
|
with pytest.raises(ParseError) as excinfo:
|
2014-12-02 16:52:46 +03:00
|
|
|
parser.parse(self.stream, None, self.parser_context)
|
2016-08-01 20:44:58 +03:00
|
|
|
assert str(excinfo.value) == 'Missing filename. Request should include a Content-Disposition header with a filename parameter.'
|
2014-12-02 16:52:46 +03:00
|
|
|
|
|
|
|
def test_parse_missing_filename_multiple_upload_handlers(self):
|
|
|
|
"""
|
|
|
|
Parse raw file upload with multiple handlers when filename is missing.
|
|
|
|
Regression test for #2109.
|
|
|
|
"""
|
|
|
|
parser = FileUploadParser()
|
|
|
|
self.stream.seek(0)
|
|
|
|
self.parser_context['request'].upload_handlers = (
|
|
|
|
MemoryFileUploadHandler(),
|
|
|
|
MemoryFileUploadHandler()
|
|
|
|
)
|
|
|
|
self.parser_context['request'].META['HTTP_CONTENT_DISPOSITION'] = ''
|
2016-08-01 20:44:58 +03:00
|
|
|
with pytest.raises(ParseError) as excinfo:
|
2014-12-02 16:52:46 +03:00
|
|
|
parser.parse(self.stream, None, self.parser_context)
|
2016-08-01 20:44:58 +03:00
|
|
|
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.'
|
2014-12-02 16:52:46 +03:00
|
|
|
|
2013-05-04 12:58:21 +04:00
|
|
|
def test_get_filename(self):
|
|
|
|
parser = FileUploadParser()
|
|
|
|
filename = parser.get_filename(self.stream, None, self.parser_context)
|
2014-04-14 13:04:18 +04:00
|
|
|
self.assertEqual(filename, 'file.txt')
|
2014-04-14 14:25:30 +04:00
|
|
|
|
|
|
|
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')
|
|
|
|
|
2014-09-06 02:22:43 +04:00
|
|
|
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')
|
|
|
|
|
2014-04-14 14:25:30 +04:00
|
|
|
def __replace_content_disposition(self, disposition):
|
|
|
|
self.parser_context['request'].META['HTTP_CONTENT_DISPOSITION'] = disposition
|
2016-09-21 13:49:09 +03:00
|
|
|
|
|
|
|
|
|
|
|
class TestPOSTAccessed(TestCase):
|
|
|
|
def setUp(self):
|
|
|
|
self.factory = APIRequestFactory()
|
|
|
|
|
|
|
|
def test_post_accessed_in_post_method(self):
|
|
|
|
django_request = self.factory.post('/', {'foo': 'bar'})
|
|
|
|
request = Request(django_request, parsers=[FormParser(), MultiPartParser()])
|
|
|
|
django_request.POST
|
|
|
|
assert request.POST == {'foo': ['bar']}
|
|
|
|
assert request.data == {'foo': ['bar']}
|
|
|
|
|
|
|
|
def test_post_accessed_in_post_method_with_json_parser(self):
|
|
|
|
django_request = self.factory.post('/', {'foo': 'bar'})
|
|
|
|
request = Request(django_request, parsers=[JSONParser()])
|
|
|
|
django_request.POST
|
|
|
|
assert request.POST == {}
|
|
|
|
assert request.data == {}
|
|
|
|
|
|
|
|
def test_post_accessed_in_put_method(self):
|
|
|
|
django_request = self.factory.put('/', {'foo': 'bar'})
|
|
|
|
request = Request(django_request, parsers=[FormParser(), MultiPartParser()])
|
|
|
|
django_request.POST
|
|
|
|
assert request.POST == {'foo': ['bar']}
|
|
|
|
assert request.data == {'foo': ['bar']}
|
|
|
|
|
|
|
|
def test_request_read_before_parsing(self):
|
|
|
|
django_request = self.factory.put('/', {'foo': 'bar'})
|
|
|
|
request = Request(django_request, parsers=[FormParser(), MultiPartParser()])
|
|
|
|
django_request.read()
|
|
|
|
with pytest.raises(RawPostDataException):
|
|
|
|
request.POST
|
|
|
|
with pytest.raises(RawPostDataException):
|
|
|
|
request.POST
|
|
|
|
request.data
|