Commit b6bd5ddc authored by Russell Keith-Magee's avatar Russell Keith-Magee
Browse files

[1.0.X] Fixed #10571 -- Ensured that unicode POST data is correctly encoded by...

[1.0.X] Fixed #10571 -- Ensured that unicode POST data is correctly encoded by the test client. Thanks to Rick Wagner for his help identifying and fixing this problem.

Merge of r10513 from trunk.


git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.0.X@10514 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent c2a828c7
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -422,6 +422,7 @@ answer newbie questions, and generally made Django that much better:
    Vlado <vlado@labath.org>
    Milton Waddams
    Chris Wagner <cw264701@ohio.edu>
    Rick Wagner <rwagner@physics.ucsd.edu>
    wam-djangobug@wamber.net
    Wang Chun <wangchun@exoweb.net>
    Filip Wasilewski <filip.wasilewski@gmail.com>
+9 −2
Original line number Diff line number Diff line
import urllib
import sys
import os
import re
try:
    from cStringIO import StringIO
except ImportError:
@@ -21,7 +22,7 @@ from django.utils.itercompat import is_iterable

BOUNDARY = 'BoUnDaRyStRiNg'
MULTIPART_CONTENT = 'multipart/form-data; boundary=%s' % BOUNDARY

CONTENT_TYPE_RE = re.compile('.*; charset=([\w\d-]+);?')

class FakePayload(object):
    """
@@ -279,7 +280,13 @@ class Client(object):
        if content_type is MULTIPART_CONTENT:
            post_data = encode_multipart(BOUNDARY, data)
        else:
            post_data = data
            # Encode the content so that the byte representation is correct.
            match = CONTENT_TYPE_RE.match(content_type)
            if match:
                charset = match.group(1)
            else:
                charset = settings.DEFAULT_CHARSET
            post_data = smart_str(data, encoding=charset)

        r = {
            'CONTENT_LENGTH': len(post_data),
+33 −0
Original line number Diff line number Diff line
@@ -412,3 +412,36 @@ class SessionTests(TestCase):
        self.failUnless(login, 'Could not log in')
        self.client.logout()
        self.client.logout()

class UnicodePayloadTests(TestCase):
    def test_simple_unicode_payload(self):
        "A simple ASCII-only unicode JSON document can be POSTed"
        # Regression test for #10571
        json = u'{"english": "mountain pass"}'
        response = self.client.post("/test_client_regress/parse_unicode_json/", json,
                                    content_type="application/json")
        self.assertEqual(response.content, json)

    def test_unicode_payload_utf8(self):
        "A non-ASCII unicode data encoded as UTF-8 can be POSTed"
        # Regression test for #10571
        json = u'{"dog": "собака"}'
        response = self.client.post("/test_client_regress/parse_unicode_json/", json,
                                    content_type="application/json; charset=utf-8")
        self.assertEqual(response.content, json.encode('utf-8'))

    def test_unicode_payload_utf16(self):
        "A non-ASCII unicode data encoded as UTF-16 can be POSTed"
        # Regression test for #10571
        json = u'{"dog": "собака"}'
        response = self.client.post("/test_client_regress/parse_unicode_json/", json,
                                    content_type="application/json; charset=utf-16")
        self.assertEqual(response.content, json.encode('utf-16'))

    def test_unicode_payload_non_utf(self):
        "A non-ASCII unicode data as a non-UTF based encoding can be POSTed"
        #Regression test for #10571
        json = u'{"dog": "собака"}'
        response = self.client.post("/test_client_regress/parse_unicode_json/", json,
                                    content_type="application/json; charset=koi8-r")
        self.assertEqual(response.content, json.encode('koi8-r'))
+1 −0
Original line number Diff line number Diff line
@@ -10,4 +10,5 @@ urlpatterns = patterns('',
    (r'^set_session/$', views.set_session_view),
    (r'^check_session/$', views.check_session_view),
    (r'^check_unicode/$', views.return_unicode),
    (r'^parse_unicode_json/$', views.return_json_file),
)
+23 −0
Original line number Diff line number Diff line
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, HttpResponseRedirect
from django.core.exceptions import SuspiciousOperation
from django.shortcuts import render_to_response
from django.utils import simplejson
from django.utils.encoding import smart_str
from django.core.serializers.json import DjangoJSONEncoder
from django.test.client import CONTENT_TYPE_RE

def no_template_view(request):
    "A simple view that expects a GET request, and returns a rendered template"
@@ -47,3 +52,21 @@ def check_session_view(request):

def return_unicode(request):
    return render_to_response('unicode.html')

def return_json_file(request):
    "A view that parses and returns a JSON string as a file."
    match = CONTENT_TYPE_RE.match(request.META['CONTENT_TYPE'])
    if match:
        charset = match.group(1)
    else:
        charset = settings.DEFAULT_CHARSET

    # This just checks that the uploaded data is JSON
    obj_dict = simplejson.loads(request.raw_post_data.decode(charset))
    obj_json = simplejson.dumps(obj_dict, encoding=charset,
                                cls=DjangoJSONEncoder,
                                ensure_ascii=False)
    response = HttpResponse(smart_str(obj_json, encoding=charset), status=200,
                            mimetype='application/json; charset=' + charset)
    response['Content-Disposition'] = 'attachment; filename=testfile.json'
    return response