1# -*- coding: utf-8 -*-
2# (c) 2007 Philip Jenvey; written for Paste (http://pythonpaste.org)
3# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
4import cgi
5from paste.fixture import TestApp
6from paste.wsgiwrappers import WSGIRequest, WSGIResponse
7import six
8
9class AssertApp(object):
10    def __init__(self, assertfunc):
11        self.assertfunc = assertfunc
12
13    def __call__(self, environ, start_response):
14        start_response('200 OK', [('Content-type','text/plain')])
15        self.assertfunc(environ)
16        return ['Passed']
17
18no_encoding = object()
19def valid_name(name, encoding=no_encoding, post=False):
20    def assert_valid_name(environ):
21        if encoding is not no_encoding:
22            WSGIRequest.defaults._push_object(dict(content_type='text/html',
23                                                   charset=encoding))
24        try:
25            request = WSGIRequest(environ)
26            if post:
27                params = request.POST
28            else:
29                params = request.GET
30            assert params['name'] == name
31            assert request.params['name'] == name
32        finally:
33            if encoding is not no_encoding:
34                WSGIRequest.defaults._pop_object()
35    return assert_valid_name
36
37def test_wsgirequest_charset():
38    # Jose, 'José'
39    app = TestApp(AssertApp(assertfunc=valid_name(u'José', encoding='UTF-8')))
40    res = app.get('/?name=Jos%C3%A9')
41
42    # Tanaka, '田中'
43    app = TestApp(AssertApp(assertfunc=valid_name(u'田中', encoding='UTF-8')))
44    res = app.get('/?name=%E7%94%B0%E4%B8%AD')
45
46    # Nippon (Japan), '日本'
47    app = TestApp(AssertApp(assertfunc=valid_name(u'日本', encoding='UTF-8',
48                                                  post=True)))
49    res = app.post('/', params=dict(name='日本'))
50
51    # WSGIRequest will determine the charset from the Content-Type header when
52    # unicode is expected.
53    # No encoding specified: not expecting unicode
54    app = TestApp(AssertApp(assertfunc=valid_name('日本', post=True)))
55    content_type = 'application/x-www-form-urlencoded; charset=%s'
56    res = app.post('/', params=dict(name='日本'),
57                   headers={'content-type': content_type % 'UTF-8'})
58
59    # Encoding specified: expect unicode. Shiftjis is the default encoding, but
60    # params become UTF-8 because the browser specified so
61    app = TestApp(AssertApp(assertfunc=valid_name(u'日本', post=True,
62                                                  encoding='shiftjis')))
63    res = app.post('/', params=dict(name='日本'),
64                   headers={'content-type': content_type % 'UTF-8'})
65
66    # Browser did not specify: parse params as the fallback shiftjis
67    app = TestApp(AssertApp(assertfunc=valid_name(u'日本', post=True,
68                                                  encoding='shiftjis')))
69    res = app.post('/', params=dict(name=u'日本'.encode('shiftjis')))
70
71def test_wsgirequest_charset_fileupload():
72    def handle_fileupload(environ, start_response):
73        start_response('200 OK', [('Content-type','text/plain')])
74        request = WSGIRequest(environ)
75
76        assert len(request.POST) == 1
77        assert isinstance(request.POST.keys()[0], str)
78        fs = request.POST['thefile']
79        assert isinstance(fs, cgi.FieldStorage)
80        assert isinstance(fs.filename, str)
81        assert fs.filename == '寿司.txt'
82        assert fs.value == b'Sushi'
83
84        request.charset = 'UTF-8'
85        assert len(request.POST) == 1
86        assert isinstance(request.POST.keys()[0], str)
87        fs = request.POST['thefile']
88        assert isinstance(fs, cgi.FieldStorage)
89        assert isinstance(fs.filename, six.text_type)
90        assert fs.filename == u'寿司.txt'
91        assert fs.value == b'Sushi'
92
93        request.charset = None
94        assert fs.value == b'Sushi'
95        return []
96
97    app = TestApp(handle_fileupload)
98    res = app.post('/', upload_files=[('thefile', '寿司.txt', b'Sushi')])
99
100def test_wsgiresponse_charset():
101    response = WSGIResponse(mimetype='text/html; charset=UTF-8')
102    assert response.content_type == 'text/html'
103    assert response.charset == 'UTF-8'
104    response.write(u'test')
105    response.write(u'test2')
106    response.write('test3')
107    status, headers, content = response.wsgi_response()
108    for data in content:
109        assert isinstance(data, six.binary_type)
110
111    WSGIResponse.defaults._push_object(dict(content_type='text/html',
112                                            charset='iso-8859-1'))
113    try:
114        response = WSGIResponse()
115        response.write(u'test')
116        response.write(u'test2')
117        response.write('test3')
118        status, headers, content = response.wsgi_response()
119        for data in content:
120            assert isinstance(data, six.binary_type)
121    finally:
122        WSGIResponse.defaults._pop_object()
123
124    # WSGIResponse will allow unicode to pass through when no charset is
125    # set
126    WSGIResponse.defaults._push_object(dict(content_type='text/html',
127                                            charset=None))
128    try:
129        response = WSGIResponse(u'test')
130        response.write(u'test1')
131        status, headers, content = response.wsgi_response()
132        for data in content:
133            assert isinstance(data, six.text_type)
134    finally:
135        WSGIResponse.defaults._pop_object()
136
137    WSGIResponse.defaults._push_object(dict(content_type='text/html',
138                                            charset=''))
139    try:
140        response = WSGIResponse(u'test')
141        response.write(u'test1')
142        status, headers, content = response.wsgi_response()
143        for data in content:
144            assert isinstance(data, six.text_type)
145    finally:
146        WSGIResponse.defaults._pop_object()
147