Decoupled test client encoding tests from JSON handling

Using JSON as non-UTF-8 content is controversial, and the RFC 7159
discourages it.
Thanks Tim Graham for the review.
This commit is contained in:
Claude Paroz 2017-03-08 20:07:09 +01:00
parent c577d8a498
commit 29592eef19
3 changed files with 26 additions and 36 deletions

View File

@ -1268,35 +1268,32 @@ class QueryStringTests(SimpleTestCase):
@override_settings(ROOT_URLCONF='test_client_regress.urls') @override_settings(ROOT_URLCONF='test_client_regress.urls')
class UnicodePayloadTests(SimpleTestCase): class PayloadEncodingTests(SimpleTestCase):
"""Regression tests for #10571."""
def test_simple_unicode_payload(self): def test_simple_payload(self):
"A simple ASCII-only JSON document can be POSTed" """A simple ASCII-only text can be POSTed."""
# Regression test for #10571 text = 'English: mountain pass'
json_str = '{"english": "mountain pass"}' response = self.client.post('/parse_encoded_text/', text, content_type='text/plain')
response = self.client.post("/parse_unicode_json/", json_str, content_type="application/json") self.assertEqual(response.content, text.encode())
self.assertEqual(response.content, json_str.encode())
def test_unicode_payload_utf8(self): def test_utf8_payload(self):
"A non-ASCII unicode data encoded as UTF-8 can be POSTed" """Non-ASCII data encoded as UTF-8 can be POSTed."""
# Regression test for #10571 text = 'dog: собака'
json_str = '{"dog": "собака"}' response = self.client.post('/parse_encoded_text/', text, content_type='text/plain; charset=utf-8')
response = self.client.post("/parse_unicode_json/", json_str, content_type="application/json; charset=utf-8") self.assertEqual(response.content, text.encode())
self.assertEqual(response.content, json_str.encode())
def test_unicode_payload_utf16(self): def test_utf16_payload(self):
"A non-ASCII unicode data encoded as UTF-16 can be POSTed" """Non-ASCII data encoded as UTF-16 can be POSTed."""
# Regression test for #10571 text = 'dog: собака'
json_str = '{"dog": "собака"}' response = self.client.post('/parse_encoded_text/', text, content_type='text/plain; charset=utf-16')
response = self.client.post("/parse_unicode_json/", json_str, content_type="application/json; charset=utf-16") self.assertEqual(response.content, text.encode('utf-16'))
self.assertEqual(response.content, json_str.encode('utf-16'))
def test_unicode_payload_non_utf(self): def test_non_utf_payload(self):
"A non-ASCII unicode data as a non-UTF based encoding can be POSTed" """Non-ASCII data as a non-UTF based encoding can be POSTed."""
# Regression test for #10571 text = 'dog: собака'
json_str = '{"dog": "собака"}' response = self.client.post('/parse_encoded_text/', text, content_type='text/plain; charset=koi8-r')
response = self.client.post("/parse_unicode_json/", json_str, content_type="application/json; charset=koi8-r") self.assertEqual(response.content, text.encode('koi8-r'))
self.assertEqual(response.content, json_str.encode('koi8-r'))
class DummyFile: class DummyFile:

View File

@ -31,7 +31,7 @@ urlpatterns = [
url(r'^check_unicode/$', views.return_unicode), url(r'^check_unicode/$', views.return_unicode),
url(r'^check_binary/$', views.return_undecodable_binary), url(r'^check_binary/$', views.return_undecodable_binary),
url(r'^json_response/$', views.return_json_response), url(r'^json_response/$', views.return_json_response),
url(r'^parse_unicode_json/$', views.return_json_file), url(r'^parse_encoded_text/$', views.return_text_file),
url(r'^check_headers/$', views.check_headers), url(r'^check_headers/$', views.check_headers),
url(r'^check_headers_redirect/$', RedirectView.as_view(url='/check_headers/')), url(r'^check_headers_redirect/$', RedirectView.as_view(url='/check_headers/')),
url(r'^body/$', views.body), url(r'^body/$', views.body),

View File

@ -1,9 +1,7 @@
import json
from urllib.parse import urlencode from urllib.parse import urlencode
from django.conf import settings from django.conf import settings
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.core.serializers.json import DjangoJSONEncoder
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
from django.shortcuts import render from django.shortcuts import render
from django.template.loader import render_to_string from django.template.loader import render_to_string
@ -111,20 +109,15 @@ def return_json_response(request):
return JsonResponse({'key': 'value'}, **kwargs) return JsonResponse({'key': 'value'}, **kwargs)
def return_json_file(request): def return_text_file(request):
"A view that parses and returns a JSON string as a file." "A view that parses and returns text as a file."
match = CONTENT_TYPE_RE.match(request.META['CONTENT_TYPE']) match = CONTENT_TYPE_RE.match(request.META['CONTENT_TYPE'])
if match: if match:
charset = match.group(1) charset = match.group(1)
else: else:
charset = settings.DEFAULT_CHARSET charset = settings.DEFAULT_CHARSET
# This just checks that the uploaded data is JSON response = HttpResponse(request.body, status=200, content_type='text/plain; charset=%s' % charset)
obj_dict = json.loads(request.body.decode(charset))
obj_json = json.dumps(obj_dict, cls=DjangoJSONEncoder, ensure_ascii=False)
response = HttpResponse(obj_json.encode(charset), status=200,
content_type='application/json; charset=%s' % charset)
response['Content-Disposition'] = 'attachment; filename=testfile.json'
return response return response