1# -*- coding: utf-8 -*- 2# vi:ts=4:et 3 4import time as _time, sys 5import bottle 6try: 7 import json 8except ImportError: 9 import simplejson as json 10 11py3 = sys.version_info[0] == 3 12 13app = bottle.Bottle() 14app.debug = True 15 16@app.route('/success') 17def ok(): 18 return 'success' 19 20@app.route('/short_wait') 21def short_wait(): 22 _time.sleep(0.1) 23 return 'success' 24 25@app.route('/status/403') 26def forbidden(): 27 return bottle.HTTPResponse('forbidden', 403) 28 29@app.route('/status/404') 30def not_found(): 31 return bottle.HTTPResponse('not found', 404) 32 33@app.route('/postfields', method='post') 34def postfields(): 35 return json.dumps(dict(bottle.request.forms)) 36 37@app.route('/raw_utf8', method='post') 38def raw_utf8(): 39 data = bottle.request.body.getvalue().decode('utf8') 40 return json.dumps(data) 41 42# XXX file is not a bottle FileUpload instance, but FieldStorage? 43def xconvert_file(key, file): 44 return { 45 'key': key, 46 'name': file.name, 47 'raw_filename': file.raw_filename, 48 'headers': file.headers, 49 'content_type': file.content_type, 50 'content_length': file.content_length, 51 'data': file.read(), 52 } 53 54if hasattr(bottle, 'FileUpload'): 55 # bottle 0.12 56 def convert_file(key, file): 57 return { 58 'name': file.name, 59 # file.filename lowercases the file name 60 # https://github.com/defnull/bottle/issues/582 61 # raw_filenames is a string on python 3 62 'filename': file.raw_filename, 63 'data': file.file.read().decode(), 64 } 65else: 66 # bottle 0.11 67 def convert_file(key, file): 68 return { 69 'name': file.name, 70 'filename': file.filename, 71 'data': file.file.read().decode(), 72 } 73 74@app.route('/files', method='post') 75def files(): 76 files = [convert_file(key, bottle.request.files[key]) for key in bottle.request.files] 77 return json.dumps(files) 78 79@app.route('/header') 80def header(): 81 return bottle.request.headers.get(bottle.request.query['h'], '') 82 83# This is a hacky endpoint to test non-ascii text being given to libcurl 84# via headers. 85# HTTP RFC requires headers to be latin1-encoded. 86# Any string can be decoded as latin1; here we encode the header value 87# back into latin1 to obtain original bytestring, then decode it in utf-8. 88# Thanks to bdarnell for the idea: https://github.com/pycurl/pycurl/issues/124 89@app.route('/header_utf8') 90def header_utf8(): 91 header_value = bottle.request.headers[bottle.request.query['h']] 92 if py3: 93 # header_value is a string, headers are decoded in latin1 94 header_value = header_value.encode('latin1').decode('utf8') 95 else: 96 # header_value is a binary string, decode in utf-8 directly 97 header_value = header_value.decode('utf8') 98 return header_value 99 100@app.route('/param_utf8_hack', method='post') 101def param_utf8_hack(): 102 param = bottle.request.forms['p'] 103 if py3: 104 # python 3 decodes bytes as latin1 perhaps? 105 # apply the latin1-utf8 hack 106 param = param.encode('latin').decode('utf8') 107 return param 108 109def pause_writer(interval): 110 yield 'part1' 111 _time.sleep(interval) 112 yield 'part2' 113 114@app.route('/pause') 115def pause(): 116 return pause_writer(0.5) 117 118@app.route('/long_pause') 119def long_pause(): 120 return pause_writer(1) 121 122@app.route('/utf8_body') 123def utf8_body(): 124 # bottle encodes the body 125 return 'Дружба народов' 126 127@app.route('/invalid_utf8_body') 128def invalid_utf8_body(): 129 # bottle encodes the body 130 raise bottle.HTTPResponse(b'\xb3\xd2\xda\xcd\xd7', 200) 131 132@app.route('/set_cookie_invalid_utf8') 133def set_cookie_invalid_utf8(): 134 bottle.response.set_header('Set-Cookie', '\xb3\xd2\xda\xcd\xd7=%96%A6g%9Ay%B0%A5g%A7tm%7C%95%9A') 135 return 'cookie set' 136 137@app.route('/content_type_invalid_utf8') 138def content_type_invalid_utf8(): 139 bottle.response.set_header('Content-Type', '\xb3\xd2\xda\xcd\xd7') 140 return 'content type set' 141 142@app.route('/status_invalid_utf8') 143def status_invalid_utf8(): 144 raise bottle.HTTPResponse('status set', '555 \xb3\xd2\xda\xcd\xd7') 145