Showing with 42 additions and 13 deletions.
  1. +42 −13 bottle.py
55 changes: 42 additions & 13 deletions bottle.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from __future__ import with_statement

__author__ = 'Marcel Hellkamp'
__version__ = '0.12.19'
__version__ = '0.12.20'
__license__ = 'MIT'

# The gevent server adapter needs to patch some modules before they are imported
Expand Down Expand Up @@ -848,17 +848,19 @@ def default_error_handler(self, res):
return tob(template(ERROR_PAGE_TEMPLATE, e=res))

def _handle(self, environ):
path = environ['bottle.raw_path'] = environ['PATH_INFO']
if py3k:
try:
environ['PATH_INFO'] = path.encode('latin1').decode('utf8')
except UnicodeError:
return HTTPError(400, 'Invalid path string. Expected UTF-8')

try:

environ['bottle.app'] = self
request.bind(environ)
response.bind()

path = environ['bottle.raw_path'] = environ['PATH_INFO']
if py3k:
try:
environ['PATH_INFO'] = path.encode('latin1').decode('utf8')
except UnicodeError:
return HTTPError(400, 'Invalid path string. Expected UTF-8')

try:
self.trigger_hook('before_request')
route, args = self.router.match(environ)
Expand Down Expand Up @@ -1239,11 +1241,11 @@ def POST(self):
self['_cgi.FieldStorage'] = data #http://bugs.python.org/issue18394#msg207958
data = data.list or []
for item in data:
if item.filename:
if item.filename is None:
post[item.name] = item.value
else:
post[item.name] = FileUpload(item.file, item.name,
item.filename, item.headers)
else:
post[item.name] = item.value
return post

@property
Expand Down Expand Up @@ -2689,6 +2691,7 @@ def auth_basic(check, realm="private", text="Access denied"):
''' Callback decorator to require HTTP auth (basic).
TODO: Add route(check_auth=...) parameter. '''
def decorator(func):
@functools.wraps(func)
def wrapper(*a, **ka):
user, password = request.auth or (None, None)
if user is None or not check(user, password):
Expand Down Expand Up @@ -2792,7 +2795,11 @@ class server_cls(server_cls):

class CherryPyServer(ServerAdapter):
def run(self, handler): # pragma: no cover
from cherrypy import wsgiserver
depr(0, 13, "The wsgi server part of cherrypy was split into a new "
"project called 'cheroot'.", "Use the 'cheroot' server "
"adapter instead of cherrypy.")
from cherrypy import wsgiserver # This will fail for CherryPy >= 9

self.options['bind_addr'] = (self.host, self.port)
self.options['wsgi_app'] = handler

Expand All @@ -2815,6 +2822,25 @@ def run(self, handler): # pragma: no cover
server.stop()


class CherootServer(ServerAdapter):
def run(self, handler): # pragma: no cover
from cheroot import wsgi
from cheroot.ssl import builtin
self.options['bind_addr'] = (self.host, self.port)
self.options['wsgi_app'] = handler
certfile = self.options.pop('certfile', None)
keyfile = self.options.pop('keyfile', None)
chainfile = self.options.pop('chainfile', None)
server = wsgi.Server(**self.options)
if certfile and keyfile:
server.ssl_adapter = builtin.BuiltinSSLAdapter(
certfile, keyfile, chainfile)
try:
server.start()
finally:
server.stop()


class WaitressServer(ServerAdapter):
def run(self, handler):
from waitress import serve
Expand Down Expand Up @@ -2982,7 +3008,9 @@ def run(self, handler):

class AutoServer(ServerAdapter):
""" Untested. """
adapters = [WaitressServer, PasteServer, TwistedServer, CherryPyServer, WSGIRefServer]
adapters = [WaitressServer, PasteServer, TwistedServer, CherryPyServer,
CherootServer, WSGIRefServer]

def run(self, handler):
for sa in self.adapters:
try:
Expand All @@ -2996,6 +3024,7 @@ def run(self, handler):
'wsgiref': WSGIRefServer,
'waitress': WaitressServer,
'cherrypy': CherryPyServer,
'cheroot': CherootServer,
'paste': PasteServer,
'fapws3': FapwsServer,
'tornado': TornadoServer,
Expand Down