diff --git a/rest_framework/request.py b/rest_framework/request.py index ac15defc2..3ce931817 100644 --- a/rest_framework/request.py +++ b/rest_framework/request.py @@ -227,16 +227,14 @@ class Request(object): self._method = self._data[self._METHOD_PARAM].upper() self._data.pop(self._METHOD_PARAM) - # Content overloading - modify the content type, and re-parse. + # Content overloading - modify the content type, and force re-parse. if (self._CONTENT_PARAM and self._CONTENTTYPE_PARAM and self._CONTENT_PARAM in self._data and self._CONTENTTYPE_PARAM in self._data): self._content_type = self._data[self._CONTENTTYPE_PARAM] self._stream = StringIO(self._data[self._CONTENT_PARAM]) - self._data.pop(self._CONTENTTYPE_PARAM) - self._data.pop(self._CONTENT_PARAM) - self._data, self._files = self._parse() + self._data, self._files = (Empty, Empty) def _parse(self): """ @@ -250,7 +248,7 @@ class Request(object): parser = self.negotiator.select_parser(self.parsers, self.content_type) if not parser: - raise exceptions.UnsupportedMediaType(self._content_type) + raise exceptions.UnsupportedMediaType(self.content_type) parsed = parser.parse(self.stream, meta=self.META, upload_handlers=self.upload_handlers) diff --git a/rest_framework/tests/request.py b/rest_framework/tests/request.py index f5c63f110..7b24b0369 100644 --- a/rest_framework/tests/request.py +++ b/rest_framework/tests/request.py @@ -4,6 +4,7 @@ Tests for content parsing, and form-overloaded content parsing. from django.conf.urls.defaults import patterns from django.contrib.auth.models import User from django.test import TestCase, Client +from django.utils import simplejson as json from rest_framework import status from rest_framework.authentication import SessionAuthentication @@ -12,9 +13,11 @@ from rest_framework.parsers import ( FormParser, MultiPartParser, PlainTextParser, + JSONParser ) from rest_framework.request import Request from rest_framework.response import Response +from rest_framework.settings import api_settings from rest_framework.views import APIView @@ -36,7 +39,7 @@ class TestMethodOverloading(TestCase): POST requests can be overloaded to another method by setting a reserved form field """ - request = Request(factory.post('/', {Request._METHOD_PARAM: 'DELETE'})) + request = Request(factory.post('/', {api_settings.FORM_METHOD_OVERRIDE: 'DELETE'})) self.assertEqual(request.method, 'DELETE') @@ -117,15 +120,16 @@ class TestContentParsing(TestCase): """ Ensure request.DATA returns content for overloaded POST request. """ - content = 'qwerty' - content_type = 'text/plain' - data = { - Request._CONTENT_PARAM: content, - Request._CONTENTTYPE_PARAM: content_type + json_data = {'foobar': 'qwerty'} + content = json.dumps(json_data) + content_type = 'application/json' + form_data = { + api_settings.FORM_CONTENT_OVERRIDE: content, + api_settings.FORM_CONTENTTYPE_OVERRIDE: content_type } - request = Request(factory.post('/', data)) - request.parsers = (PlainTextParser(), ) - self.assertEqual(request.DATA, content) + request = Request(factory.post('/', form_data)) + request.parsers = (JSONParser(), ) + self.assertEqual(request.DATA, json_data) # def test_accessing_post_after_data_form(self): # """ diff --git a/rest_framework/tests/views.py b/rest_framework/tests/views.py index cd1f73c30..61b288c68 100644 --- a/rest_framework/tests/views.py +++ b/rest_framework/tests/views.py @@ -1,128 +1,83 @@ -# from django.core.urlresolvers import reverse -# from django.conf.urls.defaults import patterns, url, include -# from django.http import HttpResponse -# from django.test import TestCase -# from django.utils import simplejson as json +from django.test import TestCase +from django.test.client import RequestFactory +from rest_framework import status +from rest_framework.decorators import api_view +from rest_framework.response import Response +from rest_framework.settings import api_settings +from rest_framework.views import APIView -# from rest_framework.views import View +factory = RequestFactory() -# class MockView(View): -# """This is a basic mock view""" -# pass +class BasicView(APIView): + def get(self, request, *args, **kwargs): + return Response({'method': 'GET'}) + + def post(self, request, *args, **kwargs): + return Response({'method': 'POST', 'data': request.DATA}) -# class MockViewFinal(View): -# """View with final() override""" - -# def final(self, request, response, *args, **kwargs): -# return HttpResponse('{"test": "passed"}', content_type="application/json") +@api_view(['GET', 'POST']) +def basic_view(request): + if request.method == 'GET': + return {'method': 'GET'} + elif request.method == 'POST': + return {'method': 'POST', 'data': request.DATA} -# # class ResourceMockView(View): -# # """This is a resource-based mock view""" +class ClassBasedViewIntegrationTests(TestCase): + def setUp(self): + self.view = BasicView.as_view() -# # class MockForm(forms.Form): -# # foo = forms.BooleanField(required=False) -# # bar = forms.IntegerField(help_text='Must be an integer.') -# # baz = forms.CharField(max_length=32) + def test_400_parse_error(self): + request = factory.post('/', 'f00bar', content_type='application/json') + response = self.view(request) + expected = { + 'detail': u'JSON parse error - No JSON object could be decoded' + } + self.assertEquals(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEquals(response.data, expected) -# # form = MockForm + def test_400_parse_error_tunneled_content(self): + content = 'f00bar' + content_type = 'application/json' + form_data = { + api_settings.FORM_CONTENT_OVERRIDE: content, + api_settings.FORM_CONTENTTYPE_OVERRIDE: content_type + } + request = factory.post('/', form_data) + response = self.view(request) + expected = { + 'detail': u'JSON parse error - No JSON object could be decoded' + } + self.assertEquals(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEquals(response.data, expected) -# # class MockResource(ModelResource): -# # """This is a mock model-based resource""" +class FunctionBasedViewIntegrationTests(TestCase): + def setUp(self): + self.view = basic_view -# # class MockResourceModel(models.Model): -# # foo = models.BooleanField() -# # bar = models.IntegerField(help_text='Must be an integer.') -# # baz = models.CharField(max_length=32, help_text='Free text. Max length 32 chars.') + def test_400_parse_error(self): + request = factory.post('/', 'f00bar', content_type='application/json') + response = self.view(request) + expected = { + 'detail': u'JSON parse error - No JSON object could be decoded' + } + self.assertEquals(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEquals(response.data, expected) -# # model = MockResourceModel -# # fields = ('foo', 'bar', 'baz') - -# urlpatterns = patterns('', -# url(r'^mock/$', MockView.as_view()), -# url(r'^mock/final/$', MockViewFinal.as_view()), -# # url(r'^resourcemock/$', ResourceMockView.as_view()), -# # url(r'^model/$', ListOrCreateModelView.as_view(resource=MockResource)), -# # url(r'^model/(?P[^/]+)/$', InstanceModelView.as_view(resource=MockResource)), -# url(r'^restframework/', include('rest_framework.urls', namespace='rest_framework')), -# ) - - -# class BaseViewTests(TestCase): -# """Test the base view class of rest_framework""" -# urls = 'rest_framework.tests.views' - -# def test_view_call_final(self): -# response = self.client.options('/mock/final/') -# self.assertEqual(response['Content-Type'].split(';')[0], "application/json") -# data = json.loads(response.content) -# self.assertEqual(data['test'], 'passed') - -# def test_options_method_simple_view(self): -# response = self.client.options('/mock/') -# self._verify_options_response(response, -# name='Mock', -# description='This is a basic mock view') - -# def test_options_method_resource_view(self): -# response = self.client.options('/resourcemock/') -# self._verify_options_response(response, -# name='Resource Mock', -# description='This is a resource-based mock view', -# fields={'foo': 'BooleanField', -# 'bar': 'IntegerField', -# 'baz': 'CharField', -# }) - -# def test_options_method_model_resource_list_view(self): -# response = self.client.options('/model/') -# self._verify_options_response(response, -# name='Mock List', -# description='This is a mock model-based resource', -# fields={'foo': 'BooleanField', -# 'bar': 'IntegerField', -# 'baz': 'CharField', -# }) - -# def test_options_method_model_resource_detail_view(self): -# response = self.client.options('/model/0/') -# self._verify_options_response(response, -# name='Mock Instance', -# description='This is a mock model-based resource', -# fields={'foo': 'BooleanField', -# 'bar': 'IntegerField', -# 'baz': 'CharField', -# }) - -# def _verify_options_response(self, response, name, description, fields=None, status=200, -# mime_type='application/json'): -# self.assertEqual(response.status_code, status) -# self.assertEqual(response['Content-Type'].split(';')[0], mime_type) -# data = json.loads(response.content) -# self.assertTrue('application/json' in data['renders']) -# self.assertEqual(name, data['name']) -# self.assertEqual(description, data['description']) -# if fields is None: -# self.assertFalse(hasattr(data, 'fields')) -# else: -# self.assertEqual(data['fields'], fields) - - -# class ExtraViewsTests(TestCase): -# """Test the extra views rest_framework provides""" -# urls = 'rest_framework.tests.views' - -# def test_login_view(self): -# """Ensure the login view exists""" -# response = self.client.get(reverse('rest_framework:login')) -# self.assertEqual(response.status_code, 200) -# self.assertEqual(response['Content-Type'].split(';')[0], 'text/html') - -# def test_logout_view(self): -# """Ensure the logout view exists""" -# response = self.client.get(reverse('rest_framework:logout')) -# self.assertEqual(response.status_code, 200) -# self.assertEqual(response['Content-Type'].split(';')[0], 'text/html') + def test_400_parse_error_tunneled_content(self): + content = 'f00bar' + content_type = 'application/json' + form_data = { + api_settings.FORM_CONTENT_OVERRIDE: content, + api_settings.FORM_CONTENTTYPE_OVERRIDE: content_type + } + request = factory.post('/', form_data) + response = self.view(request) + expected = { + 'detail': u'JSON parse error - No JSON object could be decoded' + } + self.assertEquals(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEquals(response.data, expected)