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