1
2 import gzip
3 import sys
4
5 import cherrypy
6 from cherrypy._cpcompat import BytesIO, IncompleteRead, ntob, ntou
7
8 europoundUnicode = ntou('\x80\xa3')
9 sing = ntou("\u6bdb\u6cfd\u4e1c: Sing, Little Birdie?", 'escape')
10 sing8 = sing.encode('utf-8')
11 sing16 = sing.encode('utf-16')
12
13
14 from cherrypy.test import helper
15
16
18
24 index.exposed = True
25
26 def mao_zedong(self):
27 return sing
28 mao_zedong.exposed = True
29
30 def utf8(self):
31 return sing8
32 utf8.exposed = True
33 utf8._cp_config = {'tools.encode.encoding': 'utf-8'}
34
35 def cookies_and_headers(self):
36
37
38
39 cherrypy.response.cookie['candy'] = 'bar'
40 cherrypy.response.cookie['candy']['domain'] = 'cherrypy.org'
41 cherrypy.response.headers['Some-Header'] = 'My d\xc3\xb6g has fleas'
42 return 'Any content'
43 cookies_and_headers.exposed = True
44
45 def reqparams(self, *args, **kwargs):
46 return ntob(', ').join([": ".join((k, v)).encode('utf8')
47 for k, v in cherrypy.request.params.items()])
48 reqparams.exposed = True
49
50 def nontext(self, *args, **kwargs):
51 cherrypy.response.headers['Content-Type'] = 'application/binary'
52 return '\x00\x01\x02\x03'
53 nontext.exposed = True
54 nontext._cp_config = {'tools.encode.text_only': False,
55 'tools.encode.add_charset': True,
56 }
57
58 class GZIP:
59 def index(self):
60 yield "Hello, world"
61 index.exposed = True
62
63 def noshow(self):
64
65
66 raise IndexError()
67 yield "Here be dragons"
68 noshow.exposed = True
69
70 noshow._cp_config = {'tools.encode.on': False}
71
72 def noshow_stream(self):
73
74
75 raise IndexError()
76 yield "Here be dragons"
77 noshow_stream.exposed = True
78 noshow_stream._cp_config = {'response.stream': True}
79
80 class Decode:
81 def extra_charset(self, *args, **kwargs):
82 return ', '.join([": ".join((k, v))
83 for k, v in cherrypy.request.params.items()])
84 extra_charset.exposed = True
85 extra_charset._cp_config = {
86 'tools.decode.on': True,
87 'tools.decode.default_encoding': ['utf-16'],
88 }
89
90 def force_charset(self, *args, **kwargs):
91 return ', '.join([": ".join((k, v))
92 for k, v in cherrypy.request.params.items()])
93 force_charset.exposed = True
94 force_charset._cp_config = {
95 'tools.decode.on': True,
96 'tools.decode.encoding': 'utf-16',
97 }
98
99 root = Root()
100 root.gzip = GZIP()
101 root.decode = Decode()
102 cherrypy.tree.mount(root, config={'/gzip': {'tools.gzip.on': True}})
103 setup_server = staticmethod(setup_server)
104
123
125
126 europoundUtf8 = europoundUnicode.encode('utf-8')
127 body=ntob("param=") + europoundUtf8
128 self.getPage('/', method='POST',
129 headers=[("Content-Type", "application/x-www-form-urlencoded"),
130 ("Content-Length", str(len(body))),
131 ],
132 body=body),
133 self.assertBody(europoundUtf8)
134
135
136
137 body = ntob("q=\xc2\xa3")
138 self.getPage('/reqparams', method='POST',
139 headers=[("Content-Type", "application/x-www-form-urlencoded"),
140 ("Content-Length", str(len(body))),
141 ],
142 body=body),
143 self.assertBody(ntob("q: \xc2\xa3"))
144
145
146 body = ntob("\xff\xfeq\x00=\xff\xfe\xa3\x00")
147 self.getPage('/reqparams', method='POST',
148 headers=[("Content-Type", "application/x-www-form-urlencoded;charset=utf-16"),
149 ("Content-Length", str(len(body))),
150 ],
151 body=body),
152 self.assertBody(ntob("q: \xc2\xa3"))
153
154
155
156
157 body = ntob("\xff\xfeq\x00=\xff\xfe\xa3\x00")
158 self.getPage('/reqparams', method='POST',
159 headers=[("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"),
160 ("Content-Length", str(len(body))),
161 ],
162 body=body),
163 self.assertStatus(400)
164 self.assertErrorPage(400,
165 "The request entity could not be decoded. The following charsets "
166 "were attempted: ['utf-8']")
167
201
203
204
205 body=ntob('\r\n'.join(['--X',
206 'Content-Type: text/plain;charset=utf-16',
207 'Content-Disposition: form-data; name="text"',
208 '',
209 '\xff\xfea\x00b\x00\x1c c\x00',
210 '--X',
211 'Content-Type: text/plain;charset=utf-16',
212 'Content-Disposition: form-data; name="submit"',
213 '',
214 '\xff\xfeC\x00r\x00e\x00a\x00t\x00e\x00',
215 '--X--']))
216 self.getPage('/reqparams', method='POST',
217 headers=[("Content-Type", "multipart/form-data;boundary=X"),
218 ("Content-Length", str(len(body))),
219 ],
220 body=body),
221 self.assertBody(ntob("text: ab\xe2\x80\x9cc, submit: Create"))
222
224
225
226 body=ntob('\r\n'.join(['--X',
227 'Content-Disposition: form-data; name="text"',
228 '',
229 '\xe2\x80\x9c',
230 '--X',
231 'Content-Disposition: form-data; name="submit"',
232 '',
233 'Create',
234 '--X--']))
235 self.getPage('/reqparams', method='POST',
236 headers=[("Content-Type", "multipart/form-data;boundary=X"),
237 ("Content-Length", str(len(body))),
238 ],
239 body=body),
240 self.assertBody(ntob("text: \xe2\x80\x9c, submit: Create"))
241
243
244
245 body=ntob('\r\n'.join(['--X',
246 'Content-Disposition: form-data; name="text"',
247 '',
248 '\xff\xfea\x00b\x00\x1c c\x00',
249 '--X',
250 'Content-Disposition: form-data; name="submit"',
251 '',
252 '\xff\xfeC\x00r\x00e\x00a\x00t\x00e\x00',
253 '--X--']))
254 self.getPage('/reqparams', method='POST',
255 headers=[("Content-Type", "multipart/form-data;boundary=X"),
256 ("Content-Length", str(len(body))),
257 ],
258 body=body),
259 self.assertStatus(400)
260 self.assertErrorPage(400,
261 "The request entity could not be decoded. The following charsets "
262 "were attempted: ['us-ascii', 'utf-8']")
263
264 - def test_nontext(self):
265 self.getPage('/nontext')
266 self.assertHeader('Content-Type', 'application/binary;charset=utf-8')
267 self.assertBody('\x00\x01\x02\x03')
268
270
271 self.getPage('/mao_zedong')
272 self.assertBody(sing8)
273
274
275 self.getPage('/mao_zedong', [('Accept-Charset', 'utf-16')])
276 self.assertHeader('Content-Type', 'text/html;charset=utf-16')
277 self.assertBody(sing16)
278
279
280
281 self.getPage('/mao_zedong', [('Accept-Charset',
282 'iso-8859-1;q=1, utf-16;q=0.5')])
283 self.assertBody(sing16)
284
285
286 self.getPage('/mao_zedong', [('Accept-Charset', '*;q=1, utf-7;q=.2')])
287 self.assertBody(sing8)
288
289
290 self.getPage('/mao_zedong', [('Accept-Charset', 'iso-8859-1, *;q=0')])
291 self.assertStatus("406 Not Acceptable")
292 self.assertInBody("Your client sent this Accept-Charset header: "
293 "iso-8859-1, *;q=0. We tried these charsets: "
294 "iso-8859-1.")
295
296
297 self.getPage('/mao_zedong', [('Accept-Charset',
298 'us-ascii, ISO-8859-1, x-mac-ce')])
299 self.assertStatus("406 Not Acceptable")
300 self.assertInBody("Your client sent this Accept-Charset header: "
301 "us-ascii, ISO-8859-1, x-mac-ce. We tried these "
302 "charsets: ISO-8859-1, us-ascii, x-mac-ce.")
303
304
305 self.getPage('/utf8')
306 self.assertBody(sing8)
307 self.getPage('/utf8', [('Accept-Charset', 'us-ascii, ISO-8859-1')])
308 self.assertStatus("406 Not Acceptable")
309
311 zbuf = BytesIO()
312 zfile = gzip.GzipFile(mode='wb', fileobj=zbuf, compresslevel=9)
313 zfile.write(ntob("Hello, world"))
314 zfile.close()
315
316 self.getPage('/gzip/', headers=[("Accept-Encoding", "gzip")])
317 self.assertInBody(zbuf.getvalue()[:3])
318 self.assertHeader("Vary", "Accept-Encoding")
319 self.assertHeader("Content-Encoding", "gzip")
320
321
322 self.getPage('/gzip/', headers=[("Accept-Encoding", "identity")])
323 self.assertHeader("Vary", "Accept-Encoding")
324 self.assertNoHeader("Content-Encoding")
325 self.assertBody("Hello, world")
326
327 self.getPage('/gzip/', headers=[("Accept-Encoding", "gzip;q=0")])
328 self.assertHeader("Vary", "Accept-Encoding")
329 self.assertNoHeader("Content-Encoding")
330 self.assertBody("Hello, world")
331
332 self.getPage('/gzip/', headers=[("Accept-Encoding", "*;q=0")])
333 self.assertStatus(406)
334 self.assertNoHeader("Content-Encoding")
335 self.assertErrorPage(406, "identity, gzip")
336
337
338 self.getPage('/gzip/noshow', headers=[("Accept-Encoding", "gzip")])
339 self.assertNoHeader('Content-Encoding')
340 self.assertStatus(500)
341 self.assertErrorPage(500, pattern="IndexError\n")
342
343
344
345
346
347 if (cherrypy.server.protocol_version == "HTTP/1.0" or
348 getattr(cherrypy.server, "using_apache", False)):
349 self.getPage('/gzip/noshow_stream',
350 headers=[("Accept-Encoding", "gzip")])
351 self.assertHeader('Content-Encoding', 'gzip')
352 self.assertInBody('\x1f\x8b\x08\x00')
353 else:
354
355
356 self.assertRaises((ValueError, IncompleteRead), self.getPage,
357 '/gzip/noshow_stream',
358 headers=[("Accept-Encoding", "gzip")])
359
363