Add gpio script for ap mode
[networtool-web.git] / package / bottle.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 """
4 Bottle is a fast and simple micro-framework for small web applications. It
5 offers request dispatching (Routes) with URL parameter support, templates,
6 a built-in HTTP Server and adapters for many third party WSGI/HTTP-server and
7 template engines - all in a single file and with no dependencies other than the
8 Python Standard Library.
9
10 Homepage and documentation: http://bottlepy.org/
11
12 Copyright (c) 2017, Marcel Hellkamp.
13 License: MIT (see LICENSE for details)
14 """
15
16 import sys
17
18 __author__ = 'Marcel Hellkamp'
19 __version__ = '0.13-dev'
20 __license__ = 'MIT'
21
22 ###############################################################################
23 # Command-line interface ######################################################
24 ###############################################################################
25 # INFO: Some server adapters need to monkey-patch std-lib modules before they
26 # are imported. This is why some of the command-line handling is done here, but
27 # the actual call to _main() is at the end of the file.
28
29
30 def _cli_parse(args):  # pragma: no coverage
31     from argparse import ArgumentParser
32
33     parser = ArgumentParser(prog=args[0], usage="%(prog)s [options] package.module:app")
34     opt = parser.add_argument
35     opt("--version", action="store_true", help="show version number.")
36     opt("-b", "--bind", metavar="ADDRESS", help="bind socket to ADDRESS.")
37     opt("-s", "--server", default='wsgiref', help="use SERVER as backend.")
38     opt("-p", "--plugin", action="append", help="install additional plugin/s.")
39     opt("-c", "--conf", action="append", metavar="FILE",
40         help="load config values from FILE.")
41     opt("-C", "--param", action="append", metavar="NAME=VALUE",
42         help="override config values.")
43     opt("--debug", action="store_true", help="start server in debug mode.")
44     opt("--reload", action="store_true", help="auto-reload on file changes.")
45     opt('app', help='WSGI app entry point.', nargs='?')
46
47     cli_args = parser.parse_args(args[1:])
48
49     return cli_args, parser
50
51
52 def _cli_patch(cli_args):  # pragma: no coverage
53     parsed_args, _ = _cli_parse(cli_args)
54     opts = parsed_args
55     if opts.server:
56         if opts.server.startswith('gevent'):
57             import gevent.monkey
58             gevent.monkey.patch_all()
59         elif opts.server.startswith('eventlet'):
60             import eventlet
61             eventlet.monkey_patch()
62
63
64 if __name__ == '__main__':
65     _cli_patch(sys.argv)
66
67 ###############################################################################
68 # Imports and Python 2/3 unification ##########################################
69 ###############################################################################
70
71
72 import base64, cgi, email.utils, functools, hmac, imp, itertools, mimetypes,\
73         os, re, tempfile, threading, time, warnings, weakref, hashlib
74
75 from types import FunctionType
76 from datetime import date as datedate, datetime, timedelta
77 from tempfile import TemporaryFile
78 from traceback import format_exc, print_exc
79 from unicodedata import normalize
80
81 try:
82     from ujson import dumps as json_dumps, loads as json_lds
83 except ImportError:
84     from json import dumps as json_dumps, loads as json_lds
85
86 # inspect.getargspec was removed in Python 3.6, use
87 # Signature-based version where we can (Python 3.3+)
88 try:
89     from inspect import signature
90     def getargspec(func):
91         params = signature(func).parameters
92         args, varargs, keywords, defaults = [], None, None, []
93         for name, param in params.items():
94             if param.kind == param.VAR_POSITIONAL:
95                 varargs = name
96             elif param.kind == param.VAR_KEYWORD:
97                 keywords = name
98             else:
99                 args.append(name)
100                 if param.default is not param.empty:
101                     defaults.append(param.default)
102         return (args, varargs, keywords, tuple(defaults) or None)
103 except ImportError:
104     try:
105         from inspect import getfullargspec
106         def getargspec(func):
107             spec = getfullargspec(func)
108             kwargs = makelist(spec[0]) + makelist(spec.kwonlyargs)
109             return kwargs, spec[1], spec[2], spec[3]
110     except ImportError:
111         from inspect import getargspec
112
113 py3k = sys.version_info.major > 2
114
115
116 # Workaround for the "print is a keyword/function" Python 2/3 dilemma
117 # and a fallback for mod_wsgi (resticts stdout/err attribute access)
118 try:
119     _stdout, _stderr = sys.stdout.write, sys.stderr.write
120 except IOError:
121     _stdout = lambda x: sys.stdout.write(x)
122     _stderr = lambda x: sys.stderr.write(x)
123
124 # Lots of stdlib and builtin differences.
125 if py3k:
126     import http.client as httplib
127     import _thread as thread
128     from urllib.parse import urljoin, SplitResult as UrlSplitResult
129     from urllib.parse import urlencode, quote as urlquote, unquote as urlunquote
130     urlunquote = functools.partial(urlunquote, encoding='latin1')
131     from http.cookies import SimpleCookie, Morsel, CookieError
132     from collections import MutableMapping as DictMixin
133     import pickle
134     from io import BytesIO
135     import configparser
136
137     basestring = str
138     unicode = str
139     json_loads = lambda s: json_lds(touni(s))
140     callable = lambda x: hasattr(x, '__call__')
141     imap = map
142
143     def _raise(*a):
144         raise a[0](a[1]).with_traceback(a[2])
145 else:  # 2.x
146     import httplib
147     import thread
148     from urlparse import urljoin, SplitResult as UrlSplitResult
149     from urllib import urlencode, quote as urlquote, unquote as urlunquote
150     from Cookie import SimpleCookie, Morsel, CookieError
151     from itertools import imap
152     import cPickle as pickle
153     from StringIO import StringIO as BytesIO
154     import ConfigParser as configparser
155     from collections import MutableMapping as DictMixin
156     unicode = unicode
157     json_loads = json_lds
158     exec(compile('def _raise(*a): raise a[0], a[1], a[2]', '<py3fix>', 'exec'))
159
160 # Some helpers for string/byte handling
161 def tob(s, enc='utf8'):
162     if isinstance(s, unicode):
163         return s.encode(enc)
164     return b'' if s is None else bytes(s)
165
166
167 def touni(s, enc='utf8', err='strict'):
168     if isinstance(s, bytes):
169         return s.decode(enc, err)
170     return unicode("" if s is None else s)
171
172
173 tonat = touni if py3k else tob
174
175 # 3.2 fixes cgi.FieldStorage to accept bytes (which makes a lot of sense).
176
177
178 # A bug in functools causes it to break if the wrapper is an instance method
179 def update_wrapper(wrapper, wrapped, *a, **ka):
180     try:
181         functools.update_wrapper(wrapper, wrapped, *a, **ka)
182     except AttributeError:
183         pass
184
185 # These helpers are used at module level and need to be defined first.
186 # And yes, I know PEP-8, but sometimes a lower-case classname makes more sense.
187
188
189 def depr(major, minor, cause, fix):
190     text = "Warning: Use of deprecated feature or API. (Deprecated in Bottle-%d.%d)\n"\
191            "Cause: %s\n"\
192            "Fix: %s\n" % (major, minor, cause, fix)
193     if DEBUG == 'strict':
194         raise DeprecationWarning(text)
195     warnings.warn(text, DeprecationWarning, stacklevel=3)
196     return DeprecationWarning(text)
197
198
199 def makelist(data):  # This is just too handy
200     if isinstance(data, (tuple, list, set, dict)):
201         return list(data)
202     elif data:
203         return [data]
204     else:
205         return []
206
207
208 class DictProperty(object):
209     """ Property that maps to a key in a local dict-like attribute. """
210
211     def __init__(self, attr, key=None, read_only=False):
212         self.attr, self.key, self.read_only = attr, key, read_only
213
214     def __call__(self, func):
215         functools.update_wrapper(self, func, updated=[])
216         self.getter, self.key = func, self.key or func.__name__
217         return self
218
219     def __get__(self, obj, cls):
220         if obj is None: return self
221         key, storage = self.key, getattr(obj, self.attr)
222         if key not in storage: storage[key] = self.getter(obj)
223         return storage[key]
224
225     def __set__(self, obj, value):
226         if self.read_only: raise AttributeError("Read-Only property.")
227         getattr(obj, self.attr)[self.key] = value
228
229     def __delete__(self, obj):
230         if self.read_only: raise AttributeError("Read-Only property.")
231         del getattr(obj, self.attr)[self.key]
232
233
234 class cached_property(object):
235     """ A property that is only computed once per instance and then replaces
236         itself with an ordinary attribute. Deleting the attribute resets the
237         property. """
238
239     def __init__(self, func):
240         update_wrapper(self, func)
241         self.func = func
242
243     def __get__(self, obj, cls):
244         if obj is None: return self
245         value = obj.__dict__[self.func.__name__] = self.func(obj)
246         return value
247
248
249 class lazy_attribute(object):
250     """ A property that caches itself to the class object. """
251
252     def __init__(self, func):
253         functools.update_wrapper(self, func, updated=[])
254         self.getter = func
255
256     def __get__(self, obj, cls):
257         value = self.getter(cls)
258         setattr(cls, self.__name__, value)
259         return value
260
261 ###############################################################################
262 # Exceptions and Events #######################################################
263 ###############################################################################
264
265
266 class BottleException(Exception):
267     """ A base class for exceptions used by bottle. """
268     pass
269
270 ###############################################################################
271 # Routing ######################################################################
272 ###############################################################################
273
274
275 class RouteError(BottleException):
276     """ This is a base class for all routing related exceptions """
277
278
279 class RouteReset(BottleException):
280     """ If raised by a plugin or request handler, the route is reset and all
281         plugins are re-applied. """
282
283
284 class RouterUnknownModeError(RouteError):
285
286     pass
287
288
289 class RouteSyntaxError(RouteError):
290     """ The route parser found something not supported by this router. """
291
292
293 class RouteBuildError(RouteError):
294     """ The route could not be built. """
295
296
297 def _re_flatten(p):
298     """ Turn all capturing groups in a regular expression pattern into
299         non-capturing groups. """
300     if '(' not in p:
301         return p
302     return re.sub(r'(\\*)(\(\?P<[^>]+>|\((?!\?))', lambda m: m.group(0) if
303                   len(m.group(1)) % 2 else m.group(1) + '(?:', p)
304
305
306 class Router(object):
307     """ A Router is an ordered collection of route->target pairs. It is used to
308         efficiently match WSGI requests against a number of routes and return
309         the first target that satisfies the request. The target may be anything,
310         usually a string, ID or callable object. A route consists of a path-rule
311         and a HTTP method.
312
313         The path-rule is either a static path (e.g. `/contact`) or a dynamic
314         path that contains wildcards (e.g. `/wiki/<page>`). The wildcard syntax
315         and details on the matching order are described in docs:`routing`.
316     """
317
318     default_pattern = '[^/]+'
319     default_filter = 're'
320
321     #: The current CPython regexp implementation does not allow more
322     #: than 99 matching groups per regular expression.
323     _MAX_GROUPS_PER_PATTERN = 99
324
325     def __init__(self, strict=False):
326         self.rules = []  # All rules in order
327         self._groups = {}  # index of regexes to find them in dyna_routes
328         self.builder = {}  # Data structure for the url builder
329         self.static = {}  # Search structure for static routes
330         self.dyna_routes = {}
331         self.dyna_regexes = {}  # Search structure for dynamic routes
332         #: If true, static routes are no longer checked first.
333         self.strict_order = strict
334         self.filters = {
335             're': lambda conf: (_re_flatten(conf or self.default_pattern),
336                                 None, None),
337             'int': lambda conf: (r'-?\d+', int, lambda x: str(int(x))),
338             'float': lambda conf: (r'-?[\d.]+', float, lambda x: str(float(x))),
339             'path': lambda conf: (r'.+?', None, None)
340         }
341
342     def add_filter(self, name, func):
343         """ Add a filter. The provided function is called with the configuration
344         string as parameter and must return a (regexp, to_python, to_url) tuple.
345         The first element is a string, the last two are callables or None. """
346         self.filters[name] = func
347
348     rule_syntax = re.compile('(\\\\*)'
349         '(?:(?::([a-zA-Z_][a-zA-Z_0-9]*)?()(?:#(.*?)#)?)'
350           '|(?:<([a-zA-Z_][a-zA-Z_0-9]*)?(?::([a-zA-Z_]*)'
351             '(?::((?:\\\\.|[^\\\\>]+)+)?)?)?>))')
352
353     def _itertokens(self, rule):
354         offset, prefix = 0, ''
355         for match in self.rule_syntax.finditer(rule):
356             prefix += rule[offset:match.start()]
357             g = match.groups()
358             if g[2] is not None:
359                 depr(0, 13, "Use of old route syntax.",
360                             "Use <name> instead of :name in routes.")
361             if len(g[0]) % 2:  # Escaped wildcard
362                 prefix += match.group(0)[len(g[0]):]
363                 offset = match.end()
364                 continue
365             if prefix:
366                 yield prefix, None, None
367             name, filtr, conf = g[4:7] if g[2] is None else g[1:4]
368             yield name, filtr or 'default', conf or None
369             offset, prefix = match.end(), ''
370         if offset <= len(rule) or prefix:
371             yield prefix + rule[offset:], None, None
372
373     def add(self, rule, method, target, name=None):
374         """ Add a new rule or replace the target for an existing rule. """
375         anons = 0  # Number of anonymous wildcards found
376         keys = []  # Names of keys
377         pattern = ''  # Regular expression pattern with named groups
378         filters = []  # Lists of wildcard input filters
379         builder = []  # Data structure for the URL builder
380         is_static = True
381
382         for key, mode, conf in self._itertokens(rule):
383             if mode:
384                 is_static = False
385                 if mode == 'default': mode = self.default_filter
386                 mask, in_filter, out_filter = self.filters[mode](conf)
387                 if not key:
388                     pattern += '(?:%s)' % mask
389                     key = 'anon%d' % anons
390                     anons += 1
391                 else:
392                     pattern += '(?P<%s>%s)' % (key, mask)
393                     keys.append(key)
394                 if in_filter: filters.append((key, in_filter))
395                 builder.append((key, out_filter or str))
396             elif key:
397                 pattern += re.escape(key)
398                 builder.append((None, key))
399
400         self.builder[rule] = builder
401         if name: self.builder[name] = builder
402
403         if is_static and not self.strict_order:
404             self.static.setdefault(method, {})
405             self.static[method][self.build(rule)] = (target, None)
406             return
407
408         try:
409             re_pattern = re.compile('^(%s)$' % pattern)
410             re_match = re_pattern.match
411         except re.error as e:
412             raise RouteSyntaxError("Could not add Route: %s (%s)" % (rule, e))
413
414         if filters:
415
416             def getargs(path):
417                 url_args = re_match(path).groupdict()
418                 for name, wildcard_filter in filters:
419                     try:
420                         url_args[name] = wildcard_filter(url_args[name])
421                     except ValueError:
422                         raise HTTPError(400, 'Path has wrong format.')
423                 return url_args
424         elif re_pattern.groupindex:
425
426             def getargs(path):
427                 return re_match(path).groupdict()
428         else:
429             getargs = None
430
431         flatpat = _re_flatten(pattern)
432         whole_rule = (rule, flatpat, target, getargs)
433
434         if (flatpat, method) in self._groups:
435             if DEBUG:
436                 msg = 'Route <%s %s> overwrites a previously defined route'
437                 warnings.warn(msg % (method, rule), RuntimeWarning)
438             self.dyna_routes[method][
439                 self._groups[flatpat, method]] = whole_rule
440         else:
441             self.dyna_routes.setdefault(method, []).append(whole_rule)
442             self._groups[flatpat, method] = len(self.dyna_routes[method]) - 1
443
444         self._compile(method)
445
446     def _compile(self, method):
447         all_rules = self.dyna_routes[method]
448         comborules = self.dyna_regexes[method] = []
449         maxgroups = self._MAX_GROUPS_PER_PATTERN
450         for x in range(0, len(all_rules), maxgroups):
451             some = all_rules[x:x + maxgroups]
452             combined = (flatpat for (_, flatpat, _, _) in some)
453             combined = '|'.join('(^%s$)' % flatpat for flatpat in combined)
454             combined = re.compile(combined).match
455             rules = [(target, getargs) for (_, _, target, getargs) in some]
456             comborules.append((combined, rules))
457
458     def build(self, _name, *anons, **query):
459         """ Build an URL by filling the wildcards in a rule. """
460         builder = self.builder.get(_name)
461         if not builder:
462             raise RouteBuildError("No route with that name.", _name)
463         try:
464             for i, value in enumerate(anons):
465                 query['anon%d' % i] = value
466             url = ''.join([f(query.pop(n)) if n else f for (n, f) in builder])
467             return url if not query else url + '?' + urlencode(query)
468         except KeyError as E:
469             raise RouteBuildError('Missing URL argument: %r' % E.args[0])
470
471     def match(self, environ):
472         """ Return a (target, url_args) tuple or raise HTTPError(400/404/405). """
473         verb = environ['REQUEST_METHOD'].upper()
474         path = environ['PATH_INFO'] or '/'
475
476         if verb == 'HEAD':
477             methods = ['PROXY', verb, 'GET', 'ANY']
478         else:
479             methods = ['PROXY', verb, 'ANY']
480
481         for method in methods:
482             if method in self.static and path in self.static[method]:
483                 target, getargs = self.static[method][path]
484                 return target, getargs(path) if getargs else {}
485             elif method in self.dyna_regexes:
486                 for combined, rules in self.dyna_regexes[method]:
487                     match = combined(path)
488                     if match:
489                         target, getargs = rules[match.lastindex - 1]
490                         return target, getargs(path) if getargs else {}
491
492         # No matching route found. Collect alternative methods for 405 response
493         allowed = set([])
494         nocheck = set(methods)
495         for method in set(self.static) - nocheck:
496             if path in self.static[method]:
497                 allowed.add(method)
498         for method in set(self.dyna_regexes) - allowed - nocheck:
499             for combined, rules in self.dyna_regexes[method]:
500                 match = combined(path)
501                 if match:
502                     allowed.add(method)
503         if allowed:
504             allow_header = ",".join(sorted(allowed))
505             raise HTTPError(405, "Method not allowed.", Allow=allow_header)
506
507         # No matching route and no alternative method found. We give up
508         raise HTTPError(404, "Not found: " + repr(path))
509
510
511 class Route(object):
512     """ This class wraps a route callback along with route specific metadata and
513         configuration and applies Plugins on demand. It is also responsible for
514         turing an URL path rule into a regular expression usable by the Router.
515     """
516
517     def __init__(self, app, rule, method, callback,
518                  name=None,
519                  plugins=None,
520                  skiplist=None, **config):
521         #: The application this route is installed to.
522         self.app = app
523         #: The path-rule string (e.g. ``/wiki/<page>``).
524         self.rule = rule
525         #: The HTTP method as a string (e.g. ``GET``).
526         self.method = method
527         #: The original callback with no plugins applied. Useful for introspection.
528         self.callback = callback
529         #: The name of the route (if specified) or ``None``.
530         self.name = name or None
531         #: A list of route-specific plugins (see :meth:`Bottle.route`).
532         self.plugins = plugins or []
533         #: A list of plugins to not apply to this route (see :meth:`Bottle.route`).
534         self.skiplist = skiplist or []
535         #: Additional keyword arguments passed to the :meth:`Bottle.route`
536         #: decorator are stored in this dictionary. Used for route-specific
537         #: plugin configuration and meta-data.
538         self.config = app.config._make_overlay()
539         self.config.load_dict(config)
540
541     @cached_property
542     def call(self):
543         """ The route callback with all plugins applied. This property is
544             created on demand and then cached to speed up subsequent requests."""
545         return self._make_callback()
546
547     def reset(self):
548         """ Forget any cached values. The next time :attr:`call` is accessed,
549             all plugins are re-applied. """
550         self.__dict__.pop('call', None)
551
552     def prepare(self):
553         """ Do all on-demand work immediately (useful for debugging)."""
554         self.call
555
556     def all_plugins(self):
557         """ Yield all Plugins affecting this route. """
558         unique = set()
559         for p in reversed(self.app.plugins + self.plugins):
560             if True in self.skiplist: break
561             name = getattr(p, 'name', False)
562             if name and (name in self.skiplist or name in unique): continue
563             if p in self.skiplist or type(p) in self.skiplist: continue
564             if name: unique.add(name)
565             yield p
566
567     def _make_callback(self):
568         callback = self.callback
569         for plugin in self.all_plugins():
570             try:
571                 if hasattr(plugin, 'apply'):
572                     callback = plugin.apply(callback, self)
573                 else:
574                     callback = plugin(callback)
575             except RouteReset:  # Try again with changed configuration.
576                 return self._make_callback()
577             if not callback is self.callback:
578                 update_wrapper(callback, self.callback)
579         return callback
580
581     def get_undecorated_callback(self):
582         """ Return the callback. If the callback is a decorated function, try to
583             recover the original function. """
584         func = self.callback
585         func = getattr(func, '__func__' if py3k else 'im_func', func)
586         closure_attr = '__closure__' if py3k else 'func_closure'
587         while hasattr(func, closure_attr) and getattr(func, closure_attr):
588             attributes = getattr(func, closure_attr)
589             func = attributes[0].cell_contents
590
591             # in case of decorators with multiple arguments
592             if not isinstance(func, FunctionType):
593                 # pick first FunctionType instance from multiple arguments
594                 func = filter(lambda x: isinstance(x, FunctionType),
595                               map(lambda x: x.cell_contents, attributes))
596                 func = list(func)[0]  # py3 support
597         return func
598
599     def get_callback_args(self):
600         """ Return a list of argument names the callback (most likely) accepts
601             as keyword arguments. If the callback is a decorated function, try
602             to recover the original function before inspection. """
603         return getargspec(self.get_undecorated_callback())[0]
604
605     def get_config(self, key, default=None):
606         """ Lookup a config field and return its value, first checking the
607             route.config, then route.app.config."""
608         depr(0, 13, "Route.get_config() is deprectated.",
609                     "The Route.config property already includes values from the"
610                     " application config for missing keys. Access it directly.")
611         return self.config.get(key, default)
612
613     def __repr__(self):
614         cb = self.get_undecorated_callback()
615         return '<%s %r %r>' % (self.method, self.rule, cb)
616
617 ###############################################################################
618 # Application Object ###########################################################
619 ###############################################################################
620
621
622 class Bottle(object):
623     """ Each Bottle object represents a single, distinct web application and
624         consists of routes, callbacks, plugins, resources and configuration.
625         Instances are callable WSGI applications.
626
627         :param catchall: If true (default), handle all exceptions. Turn off to
628                          let debugging middleware handle exceptions.
629     """
630
631     @lazy_attribute
632     def _global_config(cls):
633         cfg = ConfigDict()
634         cfg.meta_set('catchall', 'validate', bool)
635         return cfg
636
637     def __init__(self, **kwargs):
638         #: A :class:`ConfigDict` for app specific configuration.
639         self.config = self._global_config._make_overlay()
640         self.config._add_change_listener(
641             functools.partial(self.trigger_hook, 'config'))
642
643         self.config.update({
644             "catchall": True
645         })
646
647         if kwargs.get('catchall') is False:
648             depr(0, 13, "Bottle(catchall) keyword argument.",
649                         "The 'catchall' setting is now part of the app "
650                         "configuration. Fix: `app.config['catchall'] = False`")
651             self.config['catchall'] = False
652         if kwargs.get('autojson') is False:
653             depr(0, 13, "Bottle(autojson) keyword argument.",
654                  "The 'autojson' setting is now part of the app "
655                  "configuration. Fix: `app.config['json.enable'] = False`")
656             self.config['json.disable'] = True
657
658         self._mounts = []
659
660         #: A :class:`ResourceManager` for application files
661         self.resources = ResourceManager()
662
663         self.routes = []  # List of installed :class:`Route` instances.
664         self.router = Router()  # Maps requests to :class:`Route` instances.
665         self.error_handler = {}
666
667         # Core plugins
668         self.plugins = []  # List of installed plugins.
669         self.install(JSONPlugin())
670         self.install(TemplatePlugin())
671
672     #: If true, most exceptions are caught and returned as :exc:`HTTPError`
673     catchall = DictProperty('config', 'catchall')
674
675     __hook_names = 'before_request', 'after_request', 'app_reset', 'config'
676     __hook_reversed = {'after_request'}
677
678     @cached_property
679     def _hooks(self):
680         return dict((name, []) for name in self.__hook_names)
681
682     def add_hook(self, name, func):
683         """ Attach a callback to a hook. Three hooks are currently implemented:
684
685             before_request
686                 Executed once before each request. The request context is
687                 available, but no routing has happened yet.
688             after_request
689                 Executed once after each request regardless of its outcome.
690             app_reset
691                 Called whenever :meth:`Bottle.reset` is called.
692         """
693         if name in self.__hook_reversed:
694             self._hooks[name].insert(0, func)
695         else:
696             self._hooks[name].append(func)
697
698     def remove_hook(self, name, func):
699         """ Remove a callback from a hook. """
700         if name in self._hooks and func in self._hooks[name]:
701             self._hooks[name].remove(func)
702             return True
703
704     def trigger_hook(self, __name, *args, **kwargs):
705         """ Trigger a hook and return a list of results. """
706         return [hook(*args, **kwargs) for hook in self._hooks[__name][:]]
707
708     def hook(self, name):
709         """ Return a decorator that attaches a callback to a hook. See
710             :meth:`add_hook` for details."""
711
712         def decorator(func):
713             self.add_hook(name, func)
714             return func
715
716         return decorator
717
718     def _mount_wsgi(self, prefix, app, **options):
719         segments = [p for p in prefix.split('/') if p]
720         if not segments:
721             raise ValueError('WSGI applications cannot be mounted to "/".')
722         path_depth = len(segments)
723
724         def mountpoint_wrapper():
725             try:
726                 request.path_shift(path_depth)
727                 rs = HTTPResponse([])
728
729                 def start_response(status, headerlist, exc_info=None):
730                     if exc_info:
731                         _raise(*exc_info)
732                     rs.status = status
733                     for name, value in headerlist:
734                         rs.add_header(name, value)
735                     return rs.body.append
736
737                 body = app(request.environ, start_response)
738                 rs.body = itertools.chain(rs.body, body) if rs.body else body
739                 return rs
740             finally:
741                 request.path_shift(-path_depth)
742
743         options.setdefault('skip', True)
744         options.setdefault('method', 'PROXY')
745         options.setdefault('mountpoint', {'prefix': prefix, 'target': app})
746         options['callback'] = mountpoint_wrapper
747
748         self.route('/%s/<:re:.*>' % '/'.join(segments), **options)
749         if not prefix.endswith('/'):
750             self.route('/' + '/'.join(segments), **options)
751
752     def _mount_app(self, prefix, app, **options):
753         if app in self._mounts or '_mount.app' in app.config:
754             depr(0, 13, "Application mounted multiple times. Falling back to WSGI mount.",
755                  "Clone application before mounting to a different location.")
756             return self._mount_wsgi(prefix, app, **options)
757
758         if options:
759             depr(0, 13, "Unsupported mount options. Falling back to WSGI mount.",
760                  "Do not specify any route options when mounting bottle application.")
761             return self._mount_wsgi(prefix, app, **options)
762
763         if not prefix.endswith("/"):
764             depr(0, 13, "Prefix must end in '/'. Falling back to WSGI mount.",
765                  "Consider adding an explicit redirect from '/prefix' to '/prefix/' in the parent application.")
766             return self._mount_wsgi(prefix, app, **options)
767
768         self._mounts.append(app)
769         app.config['_mount.prefix'] = prefix
770         app.config['_mount.app'] = self
771         for route in app.routes:
772             route.rule = prefix + route.rule.lstrip('/')
773             self.add_route(route)
774
775     def mount(self, prefix, app, **options):
776         """ Mount an application (:class:`Bottle` or plain WSGI) to a specific
777             URL prefix. Example::
778
779                 parent_app.mount('/prefix/', child_app)
780
781             :param prefix: path prefix or `mount-point`.
782             :param app: an instance of :class:`Bottle` or a WSGI application.
783
784             Plugins from the parent application are not applied to the routes
785             of the mounted child application. If you need plugins in the child
786             application, install them separately.
787
788             While it is possible to use path wildcards within the prefix path
789             (:class:`Bottle` childs only), it is highly discouraged.
790
791             The prefix path must end with a slash. If you want to access the
792             root of the child application via `/prefix` in addition to
793             `/prefix/`, consider adding a route with a 307 redirect to the
794             parent application.
795         """
796
797         if not prefix.startswith('/'):
798             raise ValueError("Prefix must start with '/'")
799
800         if isinstance(app, Bottle):
801             return self._mount_app(prefix, app, **options)
802         else:
803             return self._mount_wsgi(prefix, app, **options)
804
805     def merge(self, routes):
806         """ Merge the routes of another :class:`Bottle` application or a list of
807             :class:`Route` objects into this application. The routes keep their
808             'owner', meaning that the :data:`Route.app` attribute is not
809             changed. """
810         if isinstance(routes, Bottle):
811             routes = routes.routes
812         for route in routes:
813             self.add_route(route)
814
815     def install(self, plugin):
816         """ Add a plugin to the list of plugins and prepare it for being
817             applied to all routes of this application. A plugin may be a simple
818             decorator or an object that implements the :class:`Plugin` API.
819         """
820         if hasattr(plugin, 'setup'): plugin.setup(self)
821         if not callable(plugin) and not hasattr(plugin, 'apply'):
822             raise TypeError("Plugins must be callable or implement .apply()")
823         self.plugins.append(plugin)
824         self.reset()
825         return plugin
826
827     def uninstall(self, plugin):
828         """ Uninstall plugins. Pass an instance to remove a specific plugin, a type
829             object to remove all plugins that match that type, a string to remove
830             all plugins with a matching ``name`` attribute or ``True`` to remove all
831             plugins. Return the list of removed plugins. """
832         removed, remove = [], plugin
833         for i, plugin in list(enumerate(self.plugins))[::-1]:
834             if remove is True or remove is plugin or remove is type(plugin) \
835             or getattr(plugin, 'name', True) == remove:
836                 removed.append(plugin)
837                 del self.plugins[i]
838                 if hasattr(plugin, 'close'): plugin.close()
839         if removed: self.reset()
840         return removed
841
842     def reset(self, route=None):
843         """ Reset all routes (force plugins to be re-applied) and clear all
844             caches. If an ID or route object is given, only that specific route
845             is affected. """
846         if route is None: routes = self.routes
847         elif isinstance(route, Route): routes = [route]
848         else: routes = [self.routes[route]]
849         for route in routes:
850             route.reset()
851         if DEBUG:
852             for route in routes:
853                 route.prepare()
854         self.trigger_hook('app_reset')
855
856     def close(self):
857         """ Close the application and all installed plugins. """
858         for plugin in self.plugins:
859             if hasattr(plugin, 'close'): plugin.close()
860
861     def run(self, **kwargs):
862         """ Calls :func:`run` with the same parameters. """
863         run(self, **kwargs)
864
865     def match(self, environ):
866         """ Search for a matching route and return a (:class:`Route` , urlargs)
867             tuple. The second value is a dictionary with parameters extracted
868             from the URL. Raise :exc:`HTTPError` (404/405) on a non-match."""
869         return self.router.match(environ)
870
871     def get_url(self, routename, **kargs):
872         """ Return a string that matches a named route """
873         scriptname = request.environ.get('SCRIPT_NAME', '').strip('/') + '/'
874         location = self.router.build(routename, **kargs).lstrip('/')
875         return urljoin(urljoin('/', scriptname), location)
876
877     def add_route(self, route):
878         """ Add a route object, but do not change the :data:`Route.app`
879             attribute."""
880         self.routes.append(route)
881         self.router.add(route.rule, route.method, route, name=route.name)
882         if DEBUG: route.prepare()
883
884     def route(self,
885               path=None,
886               method='GET',
887               callback=None,
888               name=None,
889               apply=None,
890               skip=None, **config):
891         """ A decorator to bind a function to a request URL. Example::
892
893                 @app.route('/hello/<name>')
894                 def hello(name):
895                     return 'Hello %s' % name
896
897             The ``<name>`` part is a wildcard. See :class:`Router` for syntax
898             details.
899
900             :param path: Request path or a list of paths to listen to. If no
901               path is specified, it is automatically generated from the
902               signature of the function.
903             :param method: HTTP method (`GET`, `POST`, `PUT`, ...) or a list of
904               methods to listen to. (default: `GET`)
905             :param callback: An optional shortcut to avoid the decorator
906               syntax. ``route(..., callback=func)`` equals ``route(...)(func)``
907             :param name: The name for this route. (default: None)
908             :param apply: A decorator or plugin or a list of plugins. These are
909               applied to the route callback in addition to installed plugins.
910             :param skip: A list of plugins, plugin classes or names. Matching
911               plugins are not installed to this route. ``True`` skips all.
912
913             Any additional keyword arguments are stored as route-specific
914             configuration and passed to plugins (see :meth:`Plugin.apply`).
915         """
916         if callable(path): path, callback = None, path
917         plugins = makelist(apply)
918         skiplist = makelist(skip)
919
920         def decorator(callback):
921             if isinstance(callback, basestring): callback = load(callback)
922             for rule in makelist(path) or yieldroutes(callback):
923                 for verb in makelist(method):
924                     verb = verb.upper()
925                     route = Route(self, rule, verb, callback,
926                                   name=name,
927                                   plugins=plugins,
928                                   skiplist=skiplist, **config)
929                     self.add_route(route)
930             return callback
931
932         return decorator(callback) if callback else decorator
933
934     def get(self, path=None, method='GET', **options):
935         """ Equals :meth:`route`. """
936         return self.route(path, method, **options)
937
938     def post(self, path=None, method='POST', **options):
939         """ Equals :meth:`route` with a ``POST`` method parameter. """
940         return self.route(path, method, **options)
941
942     def put(self, path=None, method='PUT', **options):
943         """ Equals :meth:`route` with a ``PUT`` method parameter. """
944         return self.route(path, method, **options)
945
946     def delete(self, path=None, method='DELETE', **options):
947         """ Equals :meth:`route` with a ``DELETE`` method parameter. """
948         return self.route(path, method, **options)
949
950     def patch(self, path=None, method='PATCH', **options):
951         """ Equals :meth:`route` with a ``PATCH`` method parameter. """
952         return self.route(path, method, **options)
953
954     def error(self, code=500, callback=None):
955         """ Register an output handler for a HTTP error code. Can
956             be used as a decorator or called directly ::
957
958                 def error_handler_500(error):
959                     return 'error_handler_500'
960
961                 app.error(code=500, callback=error_handler_500)
962
963                 @app.error(404)
964                 def error_handler_404(error):
965                     return 'error_handler_404'
966
967         """
968
969         def decorator(callback):
970             if isinstance(callback, basestring): callback = load(callback)
971             self.error_handler[int(code)] = callback
972             return callback
973
974         return decorator(callback) if callback else decorator
975
976     def default_error_handler(self, res):
977         return tob(template(ERROR_PAGE_TEMPLATE, e=res, template_settings=dict(name='__ERROR_PAGE_TEMPLATE')))
978
979     def _handle(self, environ):
980         path = environ['bottle.raw_path'] = environ['PATH_INFO']
981         if py3k:
982             environ['PATH_INFO'] = path.encode('latin1').decode('utf8', 'ignore')
983
984         environ['bottle.app'] = self
985         request.bind(environ)
986         response.bind()
987
988         try:
989             while True: # Remove in 0.14 together with RouteReset
990                 out = None
991                 try:
992                     self.trigger_hook('before_request')
993                     route, args = self.router.match(environ)
994                     environ['route.handle'] = route
995                     environ['bottle.route'] = route
996                     environ['route.url_args'] = args
997                     out = route.call(**args)
998                     break
999                 except HTTPResponse as E:
1000                     out = E
1001                     break
1002                 except RouteReset:
1003                     depr(0, 13, "RouteReset exception deprecated",
1004                                 "Call route.call() after route.reset() and "
1005                                 "return the result.")
1006                     route.reset()
1007                     continue
1008                 finally:
1009                     if isinstance(out, HTTPResponse):
1010                         out.apply(response)
1011                     try:
1012                         self.trigger_hook('after_request')
1013                     except HTTPResponse as E:
1014                         out = E
1015                         out.apply(response)
1016         except (KeyboardInterrupt, SystemExit, MemoryError):
1017             raise
1018         except Exception as E:
1019             if not self.catchall: raise
1020             stacktrace = format_exc()
1021             environ['wsgi.errors'].write(stacktrace)
1022             environ['wsgi.errors'].flush()
1023             out = HTTPError(500, "Internal Server Error", E, stacktrace)
1024             out.apply(response)
1025
1026         return out
1027
1028     def _cast(self, out, peek=None):
1029         """ Try to convert the parameter into something WSGI compatible and set
1030         correct HTTP headers when possible.
1031         Support: False, str, unicode, dict, HTTPResponse, HTTPError, file-like,
1032         iterable of strings and iterable of unicodes
1033         """
1034
1035         # Empty output is done here
1036         if not out:
1037             if 'Content-Length' not in response:
1038                 response['Content-Length'] = 0
1039             return []
1040         # Join lists of byte or unicode strings. Mixed lists are NOT supported
1041         if isinstance(out, (tuple, list))\
1042         and isinstance(out[0], (bytes, unicode)):
1043             out = out[0][0:0].join(out)  # b'abc'[0:0] -> b''
1044         # Encode unicode strings
1045         if isinstance(out, unicode):
1046             out = out.encode(response.charset)
1047         # Byte Strings are just returned
1048         if isinstance(out, bytes):
1049             if 'Content-Length' not in response:
1050                 response['Content-Length'] = len(out)
1051             return [out]
1052         # HTTPError or HTTPException (recursive, because they may wrap anything)
1053         # TODO: Handle these explicitly in handle() or make them iterable.
1054         if isinstance(out, HTTPError):
1055             out.apply(response)
1056             out = self.error_handler.get(out.status_code,
1057                                          self.default_error_handler)(out)
1058             return self._cast(out)
1059         if isinstance(out, HTTPResponse):
1060             out.apply(response)
1061             return self._cast(out.body)
1062
1063         # File-like objects.
1064         if hasattr(out, 'read'):
1065             if 'wsgi.file_wrapper' in request.environ:
1066                 return request.environ['wsgi.file_wrapper'](out)
1067             elif hasattr(out, 'close') or not hasattr(out, '__iter__'):
1068                 return WSGIFileWrapper(out)
1069
1070         # Handle Iterables. We peek into them to detect their inner type.
1071         try:
1072             iout = iter(out)
1073             first = next(iout)
1074             while not first:
1075                 first = next(iout)
1076         except StopIteration:
1077             return self._cast('')
1078         except HTTPResponse as E:
1079             first = E
1080         except (KeyboardInterrupt, SystemExit, MemoryError):
1081             raise
1082         except Exception as error:
1083             if not self.catchall: raise
1084             first = HTTPError(500, 'Unhandled exception', error, format_exc())
1085
1086         # These are the inner types allowed in iterator or generator objects.
1087         if isinstance(first, HTTPResponse):
1088             return self._cast(first)
1089         elif isinstance(first, bytes):
1090             new_iter = itertools.chain([first], iout)
1091         elif isinstance(first, unicode):
1092             encoder = lambda x: x.encode(response.charset)
1093             new_iter = imap(encoder, itertools.chain([first], iout))
1094         else:
1095             msg = 'Unsupported response type: %s' % type(first)
1096             return self._cast(HTTPError(500, msg))
1097         if hasattr(out, 'close'):
1098             new_iter = _closeiter(new_iter, out.close)
1099         return new_iter
1100
1101     def wsgi(self, environ, start_response):
1102         """ The bottle WSGI-interface. """
1103         try:
1104             out = self._cast(self._handle(environ))
1105             # rfc2616 section 4.3
1106             if response._status_code in (100, 101, 204, 304)\
1107             or environ['REQUEST_METHOD'] == 'HEAD':
1108                 if hasattr(out, 'close'): out.close()
1109                 out = []
1110             start_response(response._status_line, response.headerlist)
1111             return out
1112         except (KeyboardInterrupt, SystemExit, MemoryError):
1113             raise
1114         except Exception as E:
1115             if not self.catchall: raise
1116             err = '<h1>Critical error while processing request: %s</h1>' \
1117                   % html_escape(environ.get('PATH_INFO', '/'))
1118             if DEBUG:
1119                 err += '<h2>Error:</h2>\n<pre>\n%s\n</pre>\n' \
1120                        '<h2>Traceback:</h2>\n<pre>\n%s\n</pre>\n' \
1121                        % (html_escape(repr(E)), html_escape(format_exc()))
1122             environ['wsgi.errors'].write(err)
1123             environ['wsgi.errors'].flush()
1124             headers = [('Content-Type', 'text/html; charset=UTF-8')]
1125             start_response('500 INTERNAL SERVER ERROR', headers, sys.exc_info())
1126             return [tob(err)]
1127
1128     def __call__(self, environ, start_response):
1129         """ Each instance of :class:'Bottle' is a WSGI application. """
1130         return self.wsgi(environ, start_response)
1131
1132     def __enter__(self):
1133         """ Use this application as default for all module-level shortcuts. """
1134         default_app.push(self)
1135         return self
1136
1137     def __exit__(self, exc_type, exc_value, traceback):
1138         default_app.pop()
1139
1140     def __setattr__(self, name, value):
1141         if name in self.__dict__:
1142             raise AttributeError("Attribute %s already defined. Plugin conflict?" % name)
1143         self.__dict__[name] = value
1144
1145
1146 ###############################################################################
1147 # HTTP and WSGI Tools ##########################################################
1148 ###############################################################################
1149
1150
1151 class BaseRequest(object):
1152     """ A wrapper for WSGI environment dictionaries that adds a lot of
1153         convenient access methods and properties. Most of them are read-only.
1154
1155         Adding new attributes to a request actually adds them to the environ
1156         dictionary (as 'bottle.request.ext.<name>'). This is the recommended
1157         way to store and access request-specific data.
1158     """
1159
1160     __slots__ = ('environ', )
1161
1162     #: Maximum size of memory buffer for :attr:`body` in bytes.
1163     MEMFILE_MAX = 102400
1164
1165     def __init__(self, environ=None):
1166         """ Wrap a WSGI environ dictionary. """
1167         #: The wrapped WSGI environ dictionary. This is the only real attribute.
1168         #: All other attributes actually are read-only properties.
1169         self.environ = {} if environ is None else environ
1170         self.environ['bottle.request'] = self
1171
1172     @DictProperty('environ', 'bottle.app', read_only=True)
1173     def app(self):
1174         """ Bottle application handling this request. """
1175         raise RuntimeError('This request is not connected to an application.')
1176
1177     @DictProperty('environ', 'bottle.route', read_only=True)
1178     def route(self):
1179         """ The bottle :class:`Route` object that matches this request. """
1180         raise RuntimeError('This request is not connected to a route.')
1181
1182     @DictProperty('environ', 'route.url_args', read_only=True)
1183     def url_args(self):
1184         """ The arguments extracted from the URL. """
1185         raise RuntimeError('This request is not connected to a route.')
1186
1187     @property
1188     def path(self):
1189         """ The value of ``PATH_INFO`` with exactly one prefixed slash (to fix
1190             broken clients and avoid the "empty path" edge case). """
1191         return '/' + self.environ.get('PATH_INFO', '').lstrip('/')
1192
1193     @property
1194     def method(self):
1195         """ The ``REQUEST_METHOD`` value as an uppercase string. """
1196         return self.environ.get('REQUEST_METHOD', 'GET').upper()
1197
1198     @DictProperty('environ', 'bottle.request.headers', read_only=True)
1199     def headers(self):
1200         """ A :class:`WSGIHeaderDict` that provides case-insensitive access to
1201             HTTP request headers. """
1202         return WSGIHeaderDict(self.environ)
1203
1204     def get_header(self, name, default=None):
1205         """ Return the value of a request header, or a given default value. """
1206         return self.headers.get(name, default)
1207
1208     @DictProperty('environ', 'bottle.request.cookies', read_only=True)
1209     def cookies(self):
1210         """ Cookies parsed into a :class:`FormsDict`. Signed cookies are NOT
1211             decoded. Use :meth:`get_cookie` if you expect signed cookies. """
1212         cookies = SimpleCookie(self.environ.get('HTTP_COOKIE', '')).values()
1213         return FormsDict((c.key, c.value) for c in cookies)
1214
1215     def get_cookie(self, key, default=None, secret=None, digestmod=hashlib.sha256):
1216         """ Return the content of a cookie. To read a `Signed Cookie`, the
1217             `secret` must match the one used to create the cookie (see
1218             :meth:`BaseResponse.set_cookie`). If anything goes wrong (missing
1219             cookie or wrong signature), return a default value. """
1220         value = self.cookies.get(key)
1221         if secret:
1222             # See BaseResponse.set_cookie for details on signed cookies.
1223             if value and value.startswith('!') and '?' in value:
1224                 sig, msg = map(tob, value[1:].split('?', 1))
1225                 hash = hmac.new(tob(secret), msg, digestmod=digestmod).digest()
1226                 if _lscmp(sig, base64.b64encode(hash)):
1227                     dst = pickle.loads(base64.b64decode(msg))
1228                     if dst and dst[0] == key:
1229                         return dst[1]
1230             return default
1231         return value or default
1232
1233     @DictProperty('environ', 'bottle.request.query', read_only=True)
1234     def query(self):
1235         """ The :attr:`query_string` parsed into a :class:`FormsDict`. These
1236             values are sometimes called "URL arguments" or "GET parameters", but
1237             not to be confused with "URL wildcards" as they are provided by the
1238             :class:`Router`. """
1239         get = self.environ['bottle.get'] = FormsDict()
1240         pairs = _parse_qsl(self.environ.get('QUERY_STRING', ''))
1241         for key, value in pairs:
1242             get[key] = value
1243         return get
1244
1245     @DictProperty('environ', 'bottle.request.forms', read_only=True)
1246     def forms(self):
1247         """ Form values parsed from an `url-encoded` or `multipart/form-data`
1248             encoded POST or PUT request body. The result is returned as a
1249             :class:`FormsDict`. All keys and values are strings. File uploads
1250             are stored separately in :attr:`files`. """
1251         forms = FormsDict()
1252         for name, item in self.POST.allitems():
1253             if not isinstance(item, FileUpload):
1254                 forms[name] = item
1255         return forms
1256
1257     @DictProperty('environ', 'bottle.request.params', read_only=True)
1258     def params(self):
1259         """ A :class:`FormsDict` with the combined values of :attr:`query` and
1260             :attr:`forms`. File uploads are stored in :attr:`files`. """
1261         params = FormsDict()
1262         for key, value in self.query.allitems():
1263             params[key] = value
1264         for key, value in self.forms.allitems():
1265             params[key] = value
1266         return params
1267
1268     @DictProperty('environ', 'bottle.request.files', read_only=True)
1269     def files(self):
1270         """ File uploads parsed from `multipart/form-data` encoded POST or PUT
1271             request body. The values are instances of :class:`FileUpload`.
1272
1273         """
1274         files = FormsDict()
1275         for name, item in self.POST.allitems():
1276             if isinstance(item, FileUpload):
1277                 files[name] = item
1278         return files
1279
1280     @DictProperty('environ', 'bottle.request.json', read_only=True)
1281     def json(self):
1282         """ If the ``Content-Type`` header is ``application/json`` or
1283             ``application/json-rpc``, this property holds the parsed content
1284             of the request body. Only requests smaller than :attr:`MEMFILE_MAX`
1285             are processed to avoid memory exhaustion.
1286             Invalid JSON raises a 400 error response.
1287         """
1288         ctype = self.environ.get('CONTENT_TYPE', '').lower().split(';')[0]
1289         if ctype in ('application/json', 'application/json-rpc'):
1290             b = self._get_body_string()
1291             if not b:
1292                 return None
1293             try:
1294                 return json_loads(b)
1295             except (ValueError, TypeError):
1296                 raise HTTPError(400, 'Invalid JSON')
1297         return None
1298
1299     def _iter_body(self, read, bufsize):
1300         maxread = max(0, self.content_length)
1301         while maxread:
1302             part = read(min(maxread, bufsize))
1303             if not part: break
1304             yield part
1305             maxread -= len(part)
1306
1307     @staticmethod
1308     def _iter_chunked(read, bufsize):
1309         err = HTTPError(400, 'Error while parsing chunked transfer body.')
1310         rn, sem, bs = tob('\r\n'), tob(';'), tob('')
1311         while True:
1312             header = read(1)
1313             while header[-2:] != rn:
1314                 c = read(1)
1315                 header += c
1316                 if not c: raise err
1317                 if len(header) > bufsize: raise err
1318             size, _, _ = header.partition(sem)
1319             try:
1320                 maxread = int(tonat(size.strip()), 16)
1321             except ValueError:
1322                 raise err
1323             if maxread == 0: break
1324             buff = bs
1325             while maxread > 0:
1326                 if not buff:
1327                     buff = read(min(maxread, bufsize))
1328                 part, buff = buff[:maxread], buff[maxread:]
1329                 if not part: raise err
1330                 yield part
1331                 maxread -= len(part)
1332             if read(2) != rn:
1333                 raise err
1334
1335     @DictProperty('environ', 'bottle.request.body', read_only=True)
1336     def _body(self):
1337         try:
1338             read_func = self.environ['wsgi.input'].read
1339         except KeyError:
1340             self.environ['wsgi.input'] = BytesIO()
1341             return self.environ['wsgi.input']
1342         body_iter = self._iter_chunked if self.chunked else self._iter_body
1343         body, body_size, is_temp_file = BytesIO(), 0, False
1344         for part in body_iter(read_func, self.MEMFILE_MAX):
1345             body.write(part)
1346             body_size += len(part)
1347             if not is_temp_file and body_size > self.MEMFILE_MAX:
1348                 body, tmp = TemporaryFile(mode='w+b'), body
1349                 body.write(tmp.getvalue())
1350                 del tmp
1351                 is_temp_file = True
1352         self.environ['wsgi.input'] = body
1353         body.seek(0)
1354         return body
1355
1356     def _get_body_string(self):
1357         """ read body until content-length or MEMFILE_MAX into a string. Raise
1358             HTTPError(413) on requests that are to large. """
1359         clen = self.content_length
1360         if clen > self.MEMFILE_MAX:
1361             raise HTTPError(413, 'Request entity too large')
1362         if clen < 0: clen = self.MEMFILE_MAX + 1
1363         data = self.body.read(clen)
1364         if len(data) > self.MEMFILE_MAX:  # Fail fast
1365             raise HTTPError(413, 'Request entity too large')
1366         return data
1367
1368     @property
1369     def body(self):
1370         """ The HTTP request body as a seek-able file-like object. Depending on
1371             :attr:`MEMFILE_MAX`, this is either a temporary file or a
1372             :class:`io.BytesIO` instance. Accessing this property for the first
1373             time reads and replaces the ``wsgi.input`` environ variable.
1374             Subsequent accesses just do a `seek(0)` on the file object. """
1375         self._body.seek(0)
1376         return self._body
1377
1378     @property
1379     def chunked(self):
1380         """ True if Chunked transfer encoding was. """
1381         return 'chunked' in self.environ.get(
1382             'HTTP_TRANSFER_ENCODING', '').lower()
1383
1384     #: An alias for :attr:`query`.
1385     GET = query
1386
1387     @DictProperty('environ', 'bottle.request.post', read_only=True)
1388     def POST(self):
1389         """ The values of :attr:`forms` and :attr:`files` combined into a single
1390             :class:`FormsDict`. Values are either strings (form values) or
1391             instances of :class:`cgi.FieldStorage` (file uploads).
1392         """
1393         post = FormsDict()
1394         # We default to application/x-www-form-urlencoded for everything that
1395         # is not multipart and take the fast path (also: 3.1 workaround)
1396         if not self.content_type.startswith('multipart/'):
1397             pairs = _parse_qsl(tonat(self._get_body_string(), 'latin1'))
1398             for key, value in pairs:
1399                 post[key] = value
1400             return post
1401
1402         safe_env = {'QUERY_STRING': ''}  # Build a safe environment for cgi
1403         for key in ('REQUEST_METHOD', 'CONTENT_TYPE', 'CONTENT_LENGTH'):
1404             if key in self.environ: safe_env[key] = self.environ[key]
1405         args = dict(fp=self.body, environ=safe_env, keep_blank_values=True)
1406
1407         if py3k:
1408             args['encoding'] = 'utf8'
1409         data = cgi.FieldStorage(**args)
1410         self['_cgi.FieldStorage'] = data  #http://bugs.python.org/issue18394
1411         data = data.list or []
1412         for item in data:
1413             if item.filename:
1414                 post[item.name] = FileUpload(item.file, item.name,
1415                                              item.filename, item.headers)
1416             else:
1417                 post[item.name] = item.value
1418         return post
1419
1420     @property
1421     def url(self):
1422         """ The full request URI including hostname and scheme. If your app
1423             lives behind a reverse proxy or load balancer and you get confusing
1424             results, make sure that the ``X-Forwarded-Host`` header is set
1425             correctly. """
1426         return self.urlparts.geturl()
1427
1428     @DictProperty('environ', 'bottle.request.urlparts', read_only=True)
1429     def urlparts(self):
1430         """ The :attr:`url` string as an :class:`urlparse.SplitResult` tuple.
1431             The tuple contains (scheme, host, path, query_string and fragment),
1432             but the fragment is always empty because it is not visible to the
1433             server. """
1434         env = self.environ
1435         http = env.get('HTTP_X_FORWARDED_PROTO') \
1436              or env.get('wsgi.url_scheme', 'http')
1437         host = env.get('HTTP_X_FORWARDED_HOST') or env.get('HTTP_HOST')
1438         if not host:
1439             # HTTP 1.1 requires a Host-header. This is for HTTP/1.0 clients.
1440             host = env.get('SERVER_NAME', '127.0.0.1')
1441             port = env.get('SERVER_PORT')
1442             if port and port != ('80' if http == 'http' else '443'):
1443                 host += ':' + port
1444         path = urlquote(self.fullpath)
1445         return UrlSplitResult(http, host, path, env.get('QUERY_STRING'), '')
1446
1447     @property
1448     def fullpath(self):
1449         """ Request path including :attr:`script_name` (if present). """
1450         return urljoin(self.script_name, self.path.lstrip('/'))
1451
1452     @property
1453     def query_string(self):
1454         """ The raw :attr:`query` part of the URL (everything in between ``?``
1455             and ``#``) as a string. """
1456         return self.environ.get('QUERY_STRING', '')
1457
1458     @property
1459     def script_name(self):
1460         """ The initial portion of the URL's `path` that was removed by a higher
1461             level (server or routing middleware) before the application was
1462             called. This script path is returned with leading and tailing
1463             slashes. """
1464         script_name = self.environ.get('SCRIPT_NAME', '').strip('/')
1465         return '/' + script_name + '/' if script_name else '/'
1466
1467     def path_shift(self, shift=1):
1468         """ Shift path segments from :attr:`path` to :attr:`script_name` and
1469             vice versa.
1470
1471            :param shift: The number of path segments to shift. May be negative
1472                          to change the shift direction. (default: 1)
1473         """
1474         script, path = path_shift(self.environ.get('SCRIPT_NAME', '/'), self.path, shift)
1475         self['SCRIPT_NAME'], self['PATH_INFO'] = script, path
1476
1477     @property
1478     def content_length(self):
1479         """ The request body length as an integer. The client is responsible to
1480             set this header. Otherwise, the real length of the body is unknown
1481             and -1 is returned. In this case, :attr:`body` will be empty. """
1482         return int(self.environ.get('CONTENT_LENGTH') or -1)
1483
1484     @property
1485     def content_type(self):
1486         """ The Content-Type header as a lowercase-string (default: empty). """
1487         return self.environ.get('CONTENT_TYPE', '').lower()
1488
1489     @property
1490     def is_xhr(self):
1491         """ True if the request was triggered by a XMLHttpRequest. This only
1492             works with JavaScript libraries that support the `X-Requested-With`
1493             header (most of the popular libraries do). """
1494         requested_with = self.environ.get('HTTP_X_REQUESTED_WITH', '')
1495         return requested_with.lower() == 'xmlhttprequest'
1496
1497     @property
1498     def is_ajax(self):
1499         """ Alias for :attr:`is_xhr`. "Ajax" is not the right term. """
1500         return self.is_xhr
1501
1502     @property
1503     def auth(self):
1504         """ HTTP authentication data as a (user, password) tuple. This
1505             implementation currently supports basic (not digest) authentication
1506             only. If the authentication happened at a higher level (e.g. in the
1507             front web-server or a middleware), the password field is None, but
1508             the user field is looked up from the ``REMOTE_USER`` environ
1509             variable. On any errors, None is returned. """
1510         basic = parse_auth(self.environ.get('HTTP_AUTHORIZATION', ''))
1511         if basic: return basic
1512         ruser = self.environ.get('REMOTE_USER')
1513         if ruser: return (ruser, None)
1514         return None
1515
1516     @property
1517     def remote_route(self):
1518         """ A list of all IPs that were involved in this request, starting with
1519             the client IP and followed by zero or more proxies. This does only
1520             work if all proxies support the ```X-Forwarded-For`` header. Note
1521             that this information can be forged by malicious clients. """
1522         proxy = self.environ.get('HTTP_X_FORWARDED_FOR')
1523         if proxy: return [ip.strip() for ip in proxy.split(',')]
1524         remote = self.environ.get('REMOTE_ADDR')
1525         return [remote] if remote else []
1526
1527     @property
1528     def remote_addr(self):
1529         """ The client IP as a string. Note that this information can be forged
1530             by malicious clients. """
1531         route = self.remote_route
1532         return route[0] if route else None
1533
1534     def copy(self):
1535         """ Return a new :class:`Request` with a shallow :attr:`environ` copy. """
1536         return Request(self.environ.copy())
1537
1538     def get(self, value, default=None):
1539         return self.environ.get(value, default)
1540
1541     def __getitem__(self, key):
1542         return self.environ[key]
1543
1544     def __delitem__(self, key):
1545         self[key] = ""
1546         del (self.environ[key])
1547
1548     def __iter__(self):
1549         return iter(self.environ)
1550
1551     def __len__(self):
1552         return len(self.environ)
1553
1554     def keys(self):
1555         return self.environ.keys()
1556
1557     def __setitem__(self, key, value):
1558         """ Change an environ value and clear all caches that depend on it. """
1559
1560         if self.environ.get('bottle.request.readonly'):
1561             raise KeyError('The environ dictionary is read-only.')
1562
1563         self.environ[key] = value
1564         todelete = ()
1565
1566         if key == 'wsgi.input':
1567             todelete = ('body', 'forms', 'files', 'params', 'post', 'json')
1568         elif key == 'QUERY_STRING':
1569             todelete = ('query', 'params')
1570         elif key.startswith('HTTP_'):
1571             todelete = ('headers', 'cookies')
1572
1573         for key in todelete:
1574             self.environ.pop('bottle.request.' + key, None)
1575
1576     def __repr__(self):
1577         return '<%s: %s %s>' % (self.__class__.__name__, self.method, self.url)
1578
1579     def __getattr__(self, name):
1580         """ Search in self.environ for additional user defined attributes. """
1581         try:
1582             var = self.environ['bottle.request.ext.%s' % name]
1583             return var.__get__(self) if hasattr(var, '__get__') else var
1584         except KeyError:
1585             raise AttributeError('Attribute %r not defined.' % name)
1586
1587     def __setattr__(self, name, value):
1588         if name == 'environ': return object.__setattr__(self, name, value)
1589         key = 'bottle.request.ext.%s' % name
1590         if key in self.environ:
1591             raise AttributeError("Attribute already defined: %s" % name)
1592         self.environ[key] = value
1593
1594     def __delattr__(self, name):
1595         try:
1596             del self.environ['bottle.request.ext.%s' % name]
1597         except KeyError:
1598             raise AttributeError("Attribute not defined: %s" % name)
1599
1600
1601 def _hkey(key):
1602     if '\n' in key or '\r' in key or '\0' in key:
1603         raise ValueError("Header names must not contain control characters: %r" % key)
1604     return key.title().replace('_', '-')
1605
1606
1607 def _hval(value):
1608     value = tonat(value)
1609     if '\n' in value or '\r' in value or '\0' in value:
1610         raise ValueError("Header value must not contain control characters: %r" % value)
1611     return value
1612
1613
1614 class HeaderProperty(object):
1615     def __init__(self, name, reader=None, writer=None, default=''):
1616         self.name, self.default = name, default
1617         self.reader, self.writer = reader, writer
1618         self.__doc__ = 'Current value of the %r header.' % name.title()
1619
1620     def __get__(self, obj, _):
1621         if obj is None: return self
1622         value = obj.get_header(self.name, self.default)
1623         return self.reader(value) if self.reader else value
1624
1625     def __set__(self, obj, value):
1626         obj[self.name] = self.writer(value) if self.writer else value
1627
1628     def __delete__(self, obj):
1629         del obj[self.name]
1630
1631
1632 class BaseResponse(object):
1633     """ Storage class for a response body as well as headers and cookies.
1634
1635         This class does support dict-like case-insensitive item-access to
1636         headers, but is NOT a dict. Most notably, iterating over a response
1637         yields parts of the body and not the headers.
1638
1639         :param body: The response body as one of the supported types.
1640         :param status: Either an HTTP status code (e.g. 200) or a status line
1641                        including the reason phrase (e.g. '200 OK').
1642         :param headers: A dictionary or a list of name-value pairs.
1643
1644         Additional keyword arguments are added to the list of headers.
1645         Underscores in the header name are replaced with dashes.
1646     """
1647
1648     default_status = 200
1649     default_content_type = 'text/html; charset=UTF-8'
1650
1651     # Header blacklist for specific response codes
1652     # (rfc2616 section 10.2.3 and 10.3.5)
1653     bad_headers = {
1654         204: frozenset(('Content-Type', 'Content-Length')),
1655         304: frozenset(('Allow', 'Content-Encoding', 'Content-Language',
1656                   'Content-Length', 'Content-Range', 'Content-Type',
1657                   'Content-Md5', 'Last-Modified'))
1658     }
1659
1660     def __init__(self, body='', status=None, headers=None, **more_headers):
1661         self._cookies = None
1662         self._headers = {}
1663         self.body = body
1664         self.status = status or self.default_status
1665         if headers:
1666             if isinstance(headers, dict):
1667                 headers = headers.items()
1668             for name, value in headers:
1669                 self.add_header(name, value)
1670         if more_headers:
1671             for name, value in more_headers.items():
1672                 self.add_header(name, value)
1673
1674     def copy(self, cls=None):
1675         """ Returns a copy of self. """
1676         cls = cls or BaseResponse
1677         assert issubclass(cls, BaseResponse)
1678         copy = cls()
1679         copy.status = self.status
1680         copy._headers = dict((k, v[:]) for (k, v) in self._headers.items())
1681         if self._cookies:
1682             copy._cookies = SimpleCookie()
1683             copy._cookies.load(self._cookies.output(header=''))
1684         return copy
1685
1686     def __iter__(self):
1687         return iter(self.body)
1688
1689     def close(self):
1690         if hasattr(self.body, 'close'):
1691             self.body.close()
1692
1693     @property
1694     def status_line(self):
1695         """ The HTTP status line as a string (e.g. ``404 Not Found``)."""
1696         return self._status_line
1697
1698     @property
1699     def status_code(self):
1700         """ The HTTP status code as an integer (e.g. 404)."""
1701         return self._status_code
1702
1703     def _set_status(self, status):
1704         if isinstance(status, int):
1705             code, status = status, _HTTP_STATUS_LINES.get(status)
1706         elif ' ' in status:
1707             status = status.strip()
1708             code = int(status.split()[0])
1709         else:
1710             raise ValueError('String status line without a reason phrase.')
1711         if not 100 <= code <= 999:
1712             raise ValueError('Status code out of range.')
1713         self._status_code = code
1714         self._status_line = str(status or ('%d Unknown' % code))
1715
1716     def _get_status(self):
1717         return self._status_line
1718
1719     status = property(
1720         _get_status, _set_status, None,
1721         ''' A writeable property to change the HTTP response status. It accepts
1722             either a numeric code (100-999) or a string with a custom reason
1723             phrase (e.g. "404 Brain not found"). Both :data:`status_line` and
1724             :data:`status_code` are updated accordingly. The return value is
1725             always a status string. ''')
1726     del _get_status, _set_status
1727
1728     @property
1729     def headers(self):
1730         """ An instance of :class:`HeaderDict`, a case-insensitive dict-like
1731             view on the response headers. """
1732         hdict = HeaderDict()
1733         hdict.dict = self._headers
1734         return hdict
1735
1736     def __contains__(self, name):
1737         return _hkey(name) in self._headers
1738
1739     def __delitem__(self, name):
1740         del self._headers[_hkey(name)]
1741
1742     def __getitem__(self, name):
1743         return self._headers[_hkey(name)][-1]
1744
1745     def __setitem__(self, name, value):
1746         self._headers[_hkey(name)] = [_hval(value)]
1747
1748     def get_header(self, name, default=None):
1749         """ Return the value of a previously defined header. If there is no
1750             header with that name, return a default value. """
1751         return self._headers.get(_hkey(name), [default])[-1]
1752
1753     def set_header(self, name, value):
1754         """ Create a new response header, replacing any previously defined
1755             headers with the same name. """
1756         self._headers[_hkey(name)] = [_hval(value)]
1757
1758     def add_header(self, name, value):
1759         """ Add an additional response header, not removing duplicates. """
1760         self._headers.setdefault(_hkey(name), []).append(_hval(value))
1761
1762     def iter_headers(self):
1763         """ Yield (header, value) tuples, skipping headers that are not
1764             allowed with the current response status code. """
1765         return self.headerlist
1766
1767     @property
1768     def headerlist(self):
1769         """ WSGI conform list of (header, value) tuples. """
1770         out = []
1771         headers = list(self._headers.items())
1772         if 'Content-Type' not in self._headers:
1773             headers.append(('Content-Type', [self.default_content_type]))
1774         if self._status_code in self.bad_headers:
1775             bad_headers = self.bad_headers[self._status_code]
1776             headers = [h for h in headers if h[0] not in bad_headers]
1777         out += [(name, val) for (name, vals) in headers for val in vals]
1778         if self._cookies:
1779             for c in self._cookies.values():
1780                 out.append(('Set-Cookie', _hval(c.OutputString())))
1781         if py3k:
1782             out = [(k, v.encode('utf8').decode('latin1')) for (k, v) in out]
1783         return out
1784
1785     content_type = HeaderProperty('Content-Type')
1786     content_length = HeaderProperty('Content-Length', reader=int)
1787     expires = HeaderProperty(
1788         'Expires',
1789         reader=lambda x: datetime.utcfromtimestamp(parse_date(x)),
1790         writer=lambda x: http_date(x))
1791
1792     @property
1793     def charset(self, default='UTF-8'):
1794         """ Return the charset specified in the content-type header (default: utf8). """
1795         if 'charset=' in self.content_type:
1796             return self.content_type.split('charset=')[-1].split(';')[0].strip()
1797         return default
1798
1799     def set_cookie(self, name, value, secret=None, digestmod=hashlib.sha256, **options):
1800         """ Create a new cookie or replace an old one. If the `secret` parameter is
1801             set, create a `Signed Cookie` (described below).
1802
1803             :param name: the name of the cookie.
1804             :param value: the value of the cookie.
1805             :param secret: a signature key required for signed cookies.
1806
1807             Additionally, this method accepts all RFC 2109 attributes that are
1808             supported by :class:`cookie.Morsel`, including:
1809
1810             :param max_age: maximum age in seconds. (default: None)
1811             :param expires: a datetime object or UNIX timestamp. (default: None)
1812             :param domain: the domain that is allowed to read the cookie.
1813               (default: current domain)
1814             :param path: limits the cookie to a given path (default: current path)
1815             :param secure: limit the cookie to HTTPS connections (default: off).
1816             :param httponly: prevents client-side javascript to read this cookie
1817               (default: off, requires Python 2.6 or newer).
1818             :param same_site: disables third-party use for a cookie.
1819               Allowed attributes: `lax` and `strict`.
1820               In strict mode the cookie will never be sent.
1821               In lax mode the cookie is only sent with a top-level GET request.
1822
1823             If neither `expires` nor `max_age` is set (default), the cookie will
1824             expire at the end of the browser session (as soon as the browser
1825             window is closed).
1826
1827             Signed cookies may store any pickle-able object and are
1828             cryptographically signed to prevent manipulation. Keep in mind that
1829             cookies are limited to 4kb in most browsers.
1830
1831             Warning: Pickle is a potentially dangerous format. If an attacker
1832             gains access to the secret key, he could forge cookies that execute
1833             code on server side if unpickeld. Using pickle is discouraged and
1834             support for it will be removed in later versions of bottle.
1835
1836             Warning: Signed cookies are not encrypted (the client can still see
1837             the content) and not copy-protected (the client can restore an old
1838             cookie). The main intention is to make pickling and unpickling
1839             save, not to store secret information at client side.
1840         """
1841         if not self._cookies:
1842             self._cookies = SimpleCookie()
1843
1844         # To add "SameSite" cookie support.
1845         Morsel._reserved['same-site'] = 'SameSite'
1846
1847         if secret:
1848             if not isinstance(value, basestring):
1849                 depr(0, 13, "Pickling of arbitrary objects into cookies is "
1850                             "deprecated.", "Only store strings in cookies. "
1851                             "JSON strings are fine, too.")
1852             encoded = base64.b64encode(pickle.dumps([name, value], -1))
1853             sig = base64.b64encode(hmac.new(tob(secret), encoded,
1854                                             digestmod=digestmod).digest())
1855             value = touni(tob('!') + sig + tob('?') + encoded)
1856         elif not isinstance(value, basestring):
1857             raise TypeError('Secret key required for non-string cookies.')
1858
1859         # Cookie size plus options must not exceed 4kb.
1860         if len(name) + len(value) > 3800:
1861             raise ValueError('Content does not fit into a cookie.')
1862
1863         self._cookies[name] = value
1864
1865         for key, value in options.items():
1866             if key == 'max_age':
1867                 if isinstance(value, timedelta):
1868                     value = value.seconds + value.days * 24 * 3600
1869             if key == 'expires':
1870                 if isinstance(value, (datedate, datetime)):
1871                     value = value.timetuple()
1872                 elif isinstance(value, (int, float)):
1873                     value = time.gmtime(value)
1874                 value = time.strftime("%a, %d %b %Y %H:%M:%S GMT", value)
1875             # check values for SameSite cookie, because it's not natively supported by http.cookies.
1876             if key == 'same_site' and value.lower() not in ('lax', 'strict'):
1877                 raise CookieError("Invalid attribute %r" % (key,))
1878             if key in ('secure', 'httponly') and not value:
1879                 continue
1880             self._cookies[name][key.replace('_', '-')] = value
1881
1882     def delete_cookie(self, key, **kwargs):
1883         """ Delete a cookie. Be sure to use the same `domain` and `path`
1884             settings as used to create the cookie. """
1885         kwargs['max_age'] = -1
1886         kwargs['expires'] = 0
1887         self.set_cookie(key, '', **kwargs)
1888
1889     def __repr__(self):
1890         out = ''
1891         for name, value in self.headerlist:
1892             out += '%s: %s\n' % (name.title(), value.strip())
1893         return out
1894
1895
1896 def _local_property():
1897     ls = threading.local()
1898
1899     def fget(_):
1900         try:
1901             return ls.var
1902         except AttributeError:
1903             raise RuntimeError("Request context not initialized.")
1904
1905     def fset(_, value):
1906         ls.var = value
1907
1908     def fdel(_):
1909         del ls.var
1910
1911     return property(fget, fset, fdel, 'Thread-local property')
1912
1913
1914 class LocalRequest(BaseRequest):
1915     """ A thread-local subclass of :class:`BaseRequest` with a different
1916         set of attributes for each thread. There is usually only one global
1917         instance of this class (:data:`request`). If accessed during a
1918         request/response cycle, this instance always refers to the *current*
1919         request (even on a multithreaded server). """
1920     bind = BaseRequest.__init__
1921     environ = _local_property()
1922
1923
1924 class LocalResponse(BaseResponse):
1925     """ A thread-local subclass of :class:`BaseResponse` with a different
1926         set of attributes for each thread. There is usually only one global
1927         instance of this class (:data:`response`). Its attributes are used
1928         to build the HTTP response at the end of the request/response cycle.
1929     """
1930     bind = BaseResponse.__init__
1931     _status_line = _local_property()
1932     _status_code = _local_property()
1933     _cookies = _local_property()
1934     _headers = _local_property()
1935     body = _local_property()
1936
1937
1938 Request = BaseRequest
1939 Response = BaseResponse
1940
1941
1942 class HTTPResponse(Response, BottleException):
1943     def __init__(self, body='', status=None, headers=None, **more_headers):
1944         super(HTTPResponse, self).__init__(body, status, headers, **more_headers)
1945
1946     def apply(self, other):
1947         other._status_code = self._status_code
1948         other._status_line = self._status_line
1949         other._headers = self._headers
1950         other._cookies = self._cookies
1951         other.body = self.body
1952
1953
1954 class HTTPError(HTTPResponse):
1955     default_status = 500
1956
1957     def __init__(self,
1958                  status=None,
1959                  body=None,
1960                  exception=None,
1961                  traceback=None, **more_headers):
1962         self.exception = exception
1963         self.traceback = traceback
1964         super(HTTPError, self).__init__(body, status, **more_headers)
1965
1966 ###############################################################################
1967 # Plugins ######################################################################
1968 ###############################################################################
1969
1970
1971 class PluginError(BottleException):
1972     pass
1973
1974
1975 class JSONPlugin(object):
1976     name = 'json'
1977     api = 2
1978
1979     def __init__(self, json_dumps=json_dumps):
1980         self.json_dumps = json_dumps
1981
1982     def setup(self, app):
1983         app.config._define('json.enable', default=True, validate=bool,
1984                           help="Enable or disable automatic dict->json filter.")
1985         app.config._define('json.ascii', default=False, validate=bool,
1986                           help="Use only 7-bit ASCII characters in output.")
1987         app.config._define('json.indent', default=True, validate=bool,
1988                           help="Add whitespace to make json more readable.")
1989         app.config._define('json.dump_func', default=None,
1990                           help="If defined, use this function to transform"
1991                                " dict into json. The other options no longer"
1992                                " apply.")
1993
1994     def apply(self, callback, route):
1995         dumps = self.json_dumps
1996         if not self.json_dumps: return callback
1997
1998         def wrapper(*a, **ka):
1999             try:
2000                 rv = callback(*a, **ka)
2001             except HTTPResponse as resp:
2002                 rv = resp
2003
2004             if isinstance(rv, dict):
2005                 #Attempt to serialize, raises exception on failure
2006                 json_response = dumps(rv)
2007                 #Set content type only if serialization successful
2008                 response.content_type = 'application/json'
2009                 return json_response
2010             elif isinstance(rv, HTTPResponse) and isinstance(rv.body, dict):
2011                 rv.body = dumps(rv.body)
2012                 rv.content_type = 'application/json'
2013             return rv
2014
2015         return wrapper
2016
2017
2018 class TemplatePlugin(object):
2019     """ This plugin applies the :func:`view` decorator to all routes with a
2020         `template` config parameter. If the parameter is a tuple, the second
2021         element must be a dict with additional options (e.g. `template_engine`)
2022         or default variables for the template. """
2023     name = 'template'
2024     api = 2
2025
2026     def setup(self, app):
2027         app.tpl = self
2028
2029     def apply(self, callback, route):
2030         conf = route.config.get('template')
2031         if isinstance(conf, (tuple, list)) and len(conf) == 2:
2032             return view(conf[0], **conf[1])(callback)
2033         elif isinstance(conf, str):
2034             return view(conf)(callback)
2035         else:
2036             return callback
2037
2038
2039 #: Not a plugin, but part of the plugin API. TODO: Find a better place.
2040 class _ImportRedirect(object):
2041     def __init__(self, name, impmask):
2042         """ Create a virtual package that redirects imports (see PEP 302). """
2043         self.name = name
2044         self.impmask = impmask
2045         self.module = sys.modules.setdefault(name, imp.new_module(name))
2046         self.module.__dict__.update({
2047             '__file__': __file__,
2048             '__path__': [],
2049             '__all__': [],
2050             '__loader__': self
2051         })
2052         sys.meta_path.append(self)
2053
2054     def find_module(self, fullname, path=None):
2055         if '.' not in fullname: return
2056         packname = fullname.rsplit('.', 1)[0]
2057         if packname != self.name: return
2058         return self
2059
2060     def load_module(self, fullname):
2061         if fullname in sys.modules: return sys.modules[fullname]
2062         modname = fullname.rsplit('.', 1)[1]
2063         realname = self.impmask % modname
2064         __import__(realname)
2065         module = sys.modules[fullname] = sys.modules[realname]
2066         setattr(self.module, modname, module)
2067         module.__loader__ = self
2068         return module
2069
2070 ###############################################################################
2071 # Common Utilities #############################################################
2072 ###############################################################################
2073
2074
2075 class MultiDict(DictMixin):
2076     """ This dict stores multiple values per key, but behaves exactly like a
2077         normal dict in that it returns only the newest value for any given key.
2078         There are special methods available to access the full list of values.
2079     """
2080
2081     def __init__(self, *a, **k):
2082         self.dict = dict((k, [v]) for (k, v) in dict(*a, **k).items())
2083
2084     def __len__(self):
2085         return len(self.dict)
2086
2087     def __iter__(self):
2088         return iter(self.dict)
2089
2090     def __contains__(self, key):
2091         return key in self.dict
2092
2093     def __delitem__(self, key):
2094         del self.dict[key]
2095
2096     def __getitem__(self, key):
2097         return self.dict[key][-1]
2098
2099     def __setitem__(self, key, value):
2100         self.append(key, value)
2101
2102     def keys(self):
2103         return self.dict.keys()
2104
2105     if py3k:
2106
2107         def values(self):
2108             return (v[-1] for v in self.dict.values())
2109
2110         def items(self):
2111             return ((k, v[-1]) for k, v in self.dict.items())
2112
2113         def allitems(self):
2114             return ((k, v) for k, vl in self.dict.items() for v in vl)
2115
2116         iterkeys = keys
2117         itervalues = values
2118         iteritems = items
2119         iterallitems = allitems
2120
2121     else:
2122
2123         def values(self):
2124             return [v[-1] for v in self.dict.values()]
2125
2126         def items(self):
2127             return [(k, v[-1]) for k, v in self.dict.items()]
2128
2129         def iterkeys(self):
2130             return self.dict.iterkeys()
2131
2132         def itervalues(self):
2133             return (v[-1] for v in self.dict.itervalues())
2134
2135         def iteritems(self):
2136             return ((k, v[-1]) for k, v in self.dict.iteritems())
2137
2138         def iterallitems(self):
2139             return ((k, v) for k, vl in self.dict.iteritems() for v in vl)
2140
2141         def allitems(self):
2142             return [(k, v) for k, vl in self.dict.iteritems() for v in vl]
2143
2144     def get(self, key, default=None, index=-1, type=None):
2145         """ Return the most recent value for a key.
2146
2147             :param default: The default value to be returned if the key is not
2148                    present or the type conversion fails.
2149             :param index: An index for the list of available values.
2150             :param type: If defined, this callable is used to cast the value
2151                     into a specific type. Exception are suppressed and result in
2152                     the default value to be returned.
2153         """
2154         try:
2155             val = self.dict[key][index]
2156             return type(val) if type else val
2157         except Exception:
2158             pass
2159         return default
2160
2161     def append(self, key, value):
2162         """ Add a new value to the list of values for this key. """
2163         self.dict.setdefault(key, []).append(value)
2164
2165     def replace(self, key, value):
2166         """ Replace the list of values with a single value. """
2167         self.dict[key] = [value]
2168
2169     def getall(self, key):
2170         """ Return a (possibly empty) list of values for a key. """
2171         return self.dict.get(key) or []
2172
2173     #: Aliases for WTForms to mimic other multi-dict APIs (Django)
2174     getone = get
2175     getlist = getall
2176
2177
2178 class FormsDict(MultiDict):
2179     """ This :class:`MultiDict` subclass is used to store request form data.
2180         Additionally to the normal dict-like item access methods (which return
2181         unmodified data as native strings), this container also supports
2182         attribute-like access to its values. Attributes are automatically de-
2183         or recoded to match :attr:`input_encoding` (default: 'utf8'). Missing
2184         attributes default to an empty string. """
2185
2186     #: Encoding used for attribute values.
2187     input_encoding = 'utf8'
2188     #: If true (default), unicode strings are first encoded with `latin1`
2189     #: and then decoded to match :attr:`input_encoding`.
2190     recode_unicode = True
2191
2192     def _fix(self, s, encoding=None):
2193         if isinstance(s, unicode) and self.recode_unicode:  # Python 3 WSGI
2194             return s.encode('latin1').decode(encoding or self.input_encoding)
2195         elif isinstance(s, bytes):  # Python 2 WSGI
2196             return s.decode(encoding or self.input_encoding)
2197         else:
2198             return s
2199
2200     def decode(self, encoding=None):
2201         """ Returns a copy with all keys and values de- or recoded to match
2202             :attr:`input_encoding`. Some libraries (e.g. WTForms) want a
2203             unicode dictionary. """
2204         copy = FormsDict()
2205         enc = copy.input_encoding = encoding or self.input_encoding
2206         copy.recode_unicode = False
2207         for key, value in self.allitems():
2208             copy.append(self._fix(key, enc), self._fix(value, enc))
2209         return copy
2210
2211     def getunicode(self, name, default=None, encoding=None):
2212         """ Return the value as a unicode string, or the default. """
2213         try:
2214             return self._fix(self[name], encoding)
2215         except (UnicodeError, KeyError):
2216             return default
2217
2218     def __getattr__(self, name, default=unicode()):
2219         # Without this guard, pickle generates a cryptic TypeError:
2220         if name.startswith('__') and name.endswith('__'):
2221             return super(FormsDict, self).__getattr__(name)
2222         return self.getunicode(name, default=default)
2223
2224 class HeaderDict(MultiDict):
2225     """ A case-insensitive version of :class:`MultiDict` that defaults to
2226         replace the old value instead of appending it. """
2227
2228     def __init__(self, *a, **ka):
2229         self.dict = {}
2230         if a or ka: self.update(*a, **ka)
2231
2232     def __contains__(self, key):
2233         return _hkey(key) in self.dict
2234
2235     def __delitem__(self, key):
2236         del self.dict[_hkey(key)]
2237
2238     def __getitem__(self, key):
2239         return self.dict[_hkey(key)][-1]
2240
2241     def __setitem__(self, key, value):
2242         self.dict[_hkey(key)] = [_hval(value)]
2243
2244     def append(self, key, value):
2245         self.dict.setdefault(_hkey(key), []).append(_hval(value))
2246
2247     def replace(self, key, value):
2248         self.dict[_hkey(key)] = [_hval(value)]
2249
2250     def getall(self, key):
2251         return self.dict.get(_hkey(key)) or []
2252
2253     def get(self, key, default=None, index=-1):
2254         return MultiDict.get(self, _hkey(key), default, index)
2255
2256     def filter(self, names):
2257         for name in (_hkey(n) for n in names):
2258             if name in self.dict:
2259                 del self.dict[name]
2260
2261
2262 class WSGIHeaderDict(DictMixin):
2263     """ This dict-like class wraps a WSGI environ dict and provides convenient
2264         access to HTTP_* fields. Keys and values are native strings
2265         (2.x bytes or 3.x unicode) and keys are case-insensitive. If the WSGI
2266         environment contains non-native string values, these are de- or encoded
2267         using a lossless 'latin1' character set.
2268
2269         The API will remain stable even on changes to the relevant PEPs.
2270         Currently PEP 333, 444 and 3333 are supported. (PEP 444 is the only one
2271         that uses non-native strings.)
2272     """
2273     #: List of keys that do not have a ``HTTP_`` prefix.
2274     cgikeys = ('CONTENT_TYPE', 'CONTENT_LENGTH')
2275
2276     def __init__(self, environ):
2277         self.environ = environ
2278
2279     def _ekey(self, key):
2280         """ Translate header field name to CGI/WSGI environ key. """
2281         key = key.replace('-', '_').upper()
2282         if key in self.cgikeys:
2283             return key
2284         return 'HTTP_' + key
2285
2286     def raw(self, key, default=None):
2287         """ Return the header value as is (may be bytes or unicode). """
2288         return self.environ.get(self._ekey(key), default)
2289
2290     def __getitem__(self, key):
2291         val = self.environ[self._ekey(key)]
2292         if py3k:
2293             if isinstance(val, unicode):
2294                 val = val.encode('latin1').decode('utf8')
2295             else:
2296                 val = val.decode('utf8')
2297         return val
2298
2299     def __setitem__(self, key, value):
2300         raise TypeError("%s is read-only." % self.__class__)
2301
2302     def __delitem__(self, key):
2303         raise TypeError("%s is read-only." % self.__class__)
2304
2305     def __iter__(self):
2306         for key in self.environ:
2307             if key[:5] == 'HTTP_':
2308                 yield _hkey(key[5:])
2309             elif key in self.cgikeys:
2310                 yield _hkey(key)
2311
2312     def keys(self):
2313         return [x for x in self]
2314
2315     def __len__(self):
2316         return len(self.keys())
2317
2318     def __contains__(self, key):
2319         return self._ekey(key) in self.environ
2320
2321 _UNSET = object()
2322
2323 class ConfigDict(dict):
2324     """ A dict-like configuration storage with additional support for
2325         namespaces, validators, meta-data, overlays and more.
2326
2327         This dict-like class is heavily optimized for read access. All read-only
2328         methods as well as item access should be as fast as the built-in dict.
2329     """
2330
2331     __slots__ = ('_meta', '_change_listener', '_overlays', '_virtual_keys', '_source', '__weakref__')
2332
2333     def __init__(self):
2334         self._meta = {}
2335         self._change_listener = []
2336         #: Weak references of overlays that need to be kept in sync.
2337         self._overlays = []
2338         #: Config that is the source for this overlay.
2339         self._source = None
2340         #: Keys of values copied from the source (values we do not own)
2341         self._virtual_keys = set()
2342
2343     def load_module(self, path, squash=True):
2344         """Load values from a Python module.
2345
2346            Example modue ``config.py``::
2347
2348                 DEBUG = True
2349                 SQLITE = {
2350                     "db": ":memory:"
2351                 }
2352
2353
2354            >>> c = ConfigDict()
2355            >>> c.load_module('config')
2356            {DEBUG: True, 'SQLITE.DB': 'memory'}
2357            >>> c.load_module("config", False)
2358            {'DEBUG': True, 'SQLITE': {'DB': 'memory'}}
2359
2360            :param squash: If true (default), dictionary values are assumed to
2361                           represent namespaces (see :meth:`load_dict`).
2362         """
2363         config_obj = load(path)
2364         obj = {key: getattr(config_obj, key) for key in dir(config_obj)
2365                if key.isupper()}
2366
2367         if squash:
2368             self.load_dict(obj)
2369         else:
2370             self.update(obj)
2371         return self
2372
2373     def load_config(self, filename, **options):
2374         """ Load values from an ``*.ini`` style config file.
2375
2376             A configuration file consists of sections, each led by a
2377             ``[section]`` header, followed by key/value entries separated by
2378             either ``=`` or ``:``. Section names and keys are case-insensitive.
2379             Leading and trailing whitespace is removed from keys and values.
2380             Values can be omitted, in which case the key/value delimiter may
2381             also be left out. Values can also span multiple lines, as long as
2382             they are indented deeper than the first line of the value. Commands
2383             are prefixed by ``#`` or ``;`` and may only appear on their own on
2384             an otherwise empty line.
2385
2386             Both section and key names may contain dots (``.``) as namespace
2387             separators. The actual configuration parameter name is constructed
2388             by joining section name and key name together and converting to
2389             lower case.
2390
2391             The special sections ``bottle`` and ``ROOT`` refer to the root
2392             namespace and the ``DEFAULT`` section defines default values for all
2393             other sections.
2394
2395             With Python 3, extended string interpolation is enabled.
2396
2397             :param filename: The path of a config file, or a list of paths.
2398             :param options: All keyword parameters are passed to the underlying
2399                 :class:`python:configparser.ConfigParser` constructor call.
2400
2401         """
2402         options.setdefault('allow_no_value', True)
2403         if py3k:
2404             options.setdefault('interpolation',
2405                                configparser.ExtendedInterpolation())
2406         conf = configparser.ConfigParser(**options)
2407         conf.read(filename)
2408         for section in conf.sections():
2409             for key in conf.options(section):
2410                 value = conf.get(section, key)
2411                 if section not in ['bottle', 'ROOT']:
2412                     key = section + '.' + key
2413                 self[key.lower()] = value
2414         return self
2415
2416     def load_dict(self, source, namespace=''):
2417         """ Load values from a dictionary structure. Nesting can be used to
2418             represent namespaces.
2419
2420             >>> c = ConfigDict()
2421             >>> c.load_dict({'some': {'namespace': {'key': 'value'} } })
2422             {'some.namespace.key': 'value'}
2423         """
2424         for key, value in source.items():
2425             if isinstance(key, basestring):
2426                 nskey = (namespace + '.' + key).strip('.')
2427                 if isinstance(value, dict):
2428                     self.load_dict(value, namespace=nskey)
2429                 else:
2430                     self[nskey] = value
2431             else:
2432                 raise TypeError('Key has type %r (not a string)' % type(key))
2433         return self
2434
2435     def update(self, *a, **ka):
2436         """ If the first parameter is a string, all keys are prefixed with this
2437             namespace. Apart from that it works just as the usual dict.update().
2438
2439             >>> c = ConfigDict()
2440             >>> c.update('some.namespace', key='value')
2441         """
2442         prefix = ''
2443         if a and isinstance(a[0], basestring):
2444             prefix = a[0].strip('.') + '.'
2445             a = a[1:]
2446         for key, value in dict(*a, **ka).items():
2447             self[prefix + key] = value
2448
2449     def setdefault(self, key, value):
2450         if key not in self:
2451             self[key] = value
2452         return self[key]
2453
2454     def __setitem__(self, key, value):
2455         if not isinstance(key, basestring):
2456             raise TypeError('Key has type %r (not a string)' % type(key))
2457
2458         self._virtual_keys.discard(key)
2459
2460         value = self.meta_get(key, 'filter', lambda x: x)(value)
2461         if key in self and self[key] is value:
2462             return
2463
2464         self._on_change(key, value)
2465         dict.__setitem__(self, key, value)
2466
2467         for overlay in self._iter_overlays():
2468             overlay._set_virtual(key, value)
2469
2470     def __delitem__(self, key):
2471         if key not in self:
2472             raise KeyError(key)
2473         if key in self._virtual_keys:
2474             raise KeyError("Virtual keys cannot be deleted: %s" % key)
2475
2476         if self._source and key in self._source:
2477             # Not virtual, but present in source -> Restore virtual value
2478             dict.__delitem__(self, key)
2479             self._set_virtual(key, self._source[key])
2480         else:  # not virtual, not present in source. This is OUR value
2481             self._on_change(key, None)
2482             dict.__delitem__(self, key)
2483             for overlay in self._iter_overlays():
2484                 overlay._delete_virtual(key)
2485
2486     def _set_virtual(self, key, value):
2487         """ Recursively set or update virtual keys. Do nothing if non-virtual
2488             value is present. """
2489         if key in self and key not in self._virtual_keys:
2490             return  # Do nothing for non-virtual keys.
2491
2492         self._virtual_keys.add(key)
2493         if key in self and self[key] is not value:
2494             self._on_change(key, value)
2495         dict.__setitem__(self, key, value)
2496         for overlay in self._iter_overlays():
2497             overlay._set_virtual(key, value)
2498
2499     def _delete_virtual(self, key):
2500         """ Recursively delete virtual entry. Do nothing if key is not virtual.
2501         """
2502         if key not in self._virtual_keys:
2503             return  # Do nothing for non-virtual keys.
2504
2505         if key in self:
2506             self._on_change(key, None)
2507         dict.__delitem__(self, key)
2508         self._virtual_keys.discard(key)
2509         for overlay in self._iter_overlays():
2510             overlay._delete_virtual(key)
2511
2512     def _on_change(self, key, value):
2513         for cb in self._change_listener:
2514             if cb(self, key, value):
2515                 return True
2516
2517     def _add_change_listener(self, func):
2518         self._change_listener.append(func)
2519         return func
2520
2521     def meta_get(self, key, metafield, default=None):
2522         """ Return the value of a meta field for a key. """
2523         return self._meta.get(key, {}).get(metafield, default)
2524
2525     def meta_set(self, key, metafield, value):
2526         """ Set the meta field for a key to a new value. """
2527         self._meta.setdefault(key, {})[metafield] = value
2528
2529     def meta_list(self, key):
2530         """ Return an iterable of meta field names defined for a key. """
2531         return self._meta.get(key, {}).keys()
2532
2533     def _define(self, key, default=_UNSET, help=_UNSET, validate=_UNSET):
2534         """ (Unstable) Shortcut for plugins to define own config parameters. """
2535         if default is not _UNSET:
2536             self.setdefault(key, default)
2537         if help is not _UNSET:
2538             self.meta_set(key, 'help', help)
2539         if validate is not _UNSET:
2540             self.meta_set(key, 'validate', validate)
2541
2542     def _iter_overlays(self):
2543         for ref in self._overlays:
2544             overlay = ref()
2545             if overlay is not None:
2546                 yield overlay
2547
2548     def _make_overlay(self):
2549         """ (Unstable) Create a new overlay that acts like a chained map: Values
2550             missing in the overlay are copied from the source map. Both maps
2551             share the same meta entries.
2552
2553             Entries that were copied from the source are called 'virtual'. You
2554             can not delete virtual keys, but overwrite them, which turns them
2555             into non-virtual entries. Setting keys on an overlay never affects
2556             its source, but may affect any number of child overlays.
2557
2558             Other than collections.ChainMap or most other implementations, this
2559             approach does not resolve missing keys on demand, but instead
2560             actively copies all values from the source to the overlay and keeps
2561             track of virtual and non-virtual keys internally. This removes any
2562             lookup-overhead. Read-access is as fast as a build-in dict for both
2563             virtual and non-virtual keys.
2564
2565             Changes are propagated recursively and depth-first. A failing
2566             on-change handler in an overlay stops the propagation of virtual
2567             values and may result in an partly updated tree. Take extra care
2568             here and make sure that on-change handlers never fail.
2569
2570             Used by Route.config
2571         """
2572         # Cleanup dead references
2573         self._overlays[:] = [ref for ref in self._overlays if ref() is not None]
2574
2575         overlay = ConfigDict()
2576         overlay._meta = self._meta
2577         overlay._source = self
2578         self._overlays.append(weakref.ref(overlay))
2579         for key in self:
2580             overlay._set_virtual(key, self[key])
2581         return overlay
2582
2583
2584
2585
2586 class AppStack(list):
2587     """ A stack-like list. Calling it returns the head of the stack. """
2588
2589     def __call__(self):
2590         """ Return the current default application. """
2591         return self.default
2592
2593     def push(self, value=None):
2594         """ Add a new :class:`Bottle` instance to the stack """
2595         if not isinstance(value, Bottle):
2596             value = Bottle()
2597         self.append(value)
2598         return value
2599     new_app = push
2600
2601     @property
2602     def default(self):
2603         try:
2604             return self[-1]
2605         except IndexError:
2606             return self.push()
2607
2608
2609 class WSGIFileWrapper(object):
2610     def __init__(self, fp, buffer_size=1024 * 64):
2611         self.fp, self.buffer_size = fp, buffer_size
2612         for attr in ('fileno', 'close', 'read', 'readlines', 'tell', 'seek'):
2613             if hasattr(fp, attr): setattr(self, attr, getattr(fp, attr))
2614
2615     def __iter__(self):
2616         buff, read = self.buffer_size, self.read
2617         while True:
2618             part = read(buff)
2619             if not part: return
2620             yield part
2621
2622
2623 class _closeiter(object):
2624     """ This only exists to be able to attach a .close method to iterators that
2625         do not support attribute assignment (most of itertools). """
2626
2627     def __init__(self, iterator, close=None):
2628         self.iterator = iterator
2629         self.close_callbacks = makelist(close)
2630
2631     def __iter__(self):
2632         return iter(self.iterator)
2633
2634     def close(self):
2635         for func in self.close_callbacks:
2636             func()
2637
2638
2639 class ResourceManager(object):
2640     """ This class manages a list of search paths and helps to find and open
2641         application-bound resources (files).
2642
2643         :param base: default value for :meth:`add_path` calls.
2644         :param opener: callable used to open resources.
2645         :param cachemode: controls which lookups are cached. One of 'all',
2646                          'found' or 'none'.
2647     """
2648
2649     def __init__(self, base='./', opener=open, cachemode='all'):
2650         self.opener = opener
2651         self.base = base
2652         self.cachemode = cachemode
2653
2654         #: A list of search paths. See :meth:`add_path` for details.
2655         self.path = []
2656         #: A cache for resolved paths. ``res.cache.clear()`` clears the cache.
2657         self.cache = {}
2658
2659     def add_path(self, path, base=None, index=None, create=False):
2660         """ Add a new path to the list of search paths. Return False if the
2661             path does not exist.
2662
2663             :param path: The new search path. Relative paths are turned into
2664                 an absolute and normalized form. If the path looks like a file
2665                 (not ending in `/`), the filename is stripped off.
2666             :param base: Path used to absolutize relative search paths.
2667                 Defaults to :attr:`base` which defaults to ``os.getcwd()``.
2668             :param index: Position within the list of search paths. Defaults
2669                 to last index (appends to the list).
2670
2671             The `base` parameter makes it easy to reference files installed
2672             along with a python module or package::
2673
2674                 res.add_path('./resources/', __file__)
2675         """
2676         base = os.path.abspath(os.path.dirname(base or self.base))
2677         path = os.path.abspath(os.path.join(base, os.path.dirname(path)))
2678         path += os.sep
2679         if path in self.path:
2680             self.path.remove(path)
2681         if create and not os.path.isdir(path):
2682             os.makedirs(path)
2683         if index is None:
2684             self.path.append(path)
2685         else:
2686             self.path.insert(index, path)
2687         self.cache.clear()
2688         return os.path.exists(path)
2689
2690     def __iter__(self):
2691         """ Iterate over all existing files in all registered paths. """
2692         search = self.path[:]
2693         while search:
2694             path = search.pop()
2695             if not os.path.isdir(path): continue
2696             for name in os.listdir(path):
2697                 full = os.path.join(path, name)
2698                 if os.path.isdir(full): search.append(full)
2699                 else: yield full
2700
2701     def lookup(self, name):
2702         """ Search for a resource and return an absolute file path, or `None`.
2703
2704             The :attr:`path` list is searched in order. The first match is
2705             returend. Symlinks are followed. The result is cached to speed up
2706             future lookups. """
2707         if name not in self.cache or DEBUG:
2708             for path in self.path:
2709                 fpath = os.path.join(path, name)
2710                 if os.path.isfile(fpath):
2711                     if self.cachemode in ('all', 'found'):
2712                         self.cache[name] = fpath
2713                     return fpath
2714             if self.cachemode == 'all':
2715                 self.cache[name] = None
2716         return self.cache[name]
2717
2718     def open(self, name, mode='r', *args, **kwargs):
2719         """ Find a resource and return a file object, or raise IOError. """
2720         fname = self.lookup(name)
2721         if not fname: raise IOError("Resource %r not found." % name)
2722         return self.opener(fname, mode=mode, *args, **kwargs)
2723
2724
2725 class FileUpload(object):
2726     def __init__(self, fileobj, name, filename, headers=None):
2727         """ Wrapper for file uploads. """
2728         #: Open file(-like) object (BytesIO buffer or temporary file)
2729         self.file = fileobj
2730         #: Name of the upload form field
2731         self.name = name
2732         #: Raw filename as sent by the client (may contain unsafe characters)
2733         self.raw_filename = filename
2734         #: A :class:`HeaderDict` with additional headers (e.g. content-type)
2735         self.headers = HeaderDict(headers) if headers else HeaderDict()
2736
2737     content_type = HeaderProperty('Content-Type')
2738     content_length = HeaderProperty('Content-Length', reader=int, default=-1)
2739
2740     def get_header(self, name, default=None):
2741         """ Return the value of a header within the mulripart part. """
2742         return self.headers.get(name, default)
2743
2744     @cached_property
2745     def filename(self):
2746         """ Name of the file on the client file system, but normalized to ensure
2747             file system compatibility. An empty filename is returned as 'empty'.
2748
2749             Only ASCII letters, digits, dashes, underscores and dots are
2750             allowed in the final filename. Accents are removed, if possible.
2751             Whitespace is replaced by a single dash. Leading or tailing dots
2752             or dashes are removed. The filename is limited to 255 characters.
2753         """
2754         fname = self.raw_filename
2755         if not isinstance(fname, unicode):
2756             fname = fname.decode('utf8', 'ignore')
2757         fname = normalize('NFKD', fname)
2758         fname = fname.encode('ASCII', 'ignore').decode('ASCII')
2759         fname = os.path.basename(fname.replace('\\', os.path.sep))
2760         fname = re.sub(r'[^a-zA-Z0-9-_.\s]', '', fname).strip()
2761         fname = re.sub(r'[-\s]+', '-', fname).strip('.-')
2762         return fname[:255] or 'empty'
2763
2764     def _copy_file(self, fp, chunk_size=2 ** 16):
2765         read, write, offset = self.file.read, fp.write, self.file.tell()
2766         while 1:
2767             buf = read(chunk_size)
2768             if not buf: break
2769             write(buf)
2770         self.file.seek(offset)
2771
2772     def save(self, destination, overwrite=False, chunk_size=2 ** 16):
2773         """ Save file to disk or copy its content to an open file(-like) object.
2774             If *destination* is a directory, :attr:`filename` is added to the
2775             path. Existing files are not overwritten by default (IOError).
2776
2777             :param destination: File path, directory or file(-like) object.
2778             :param overwrite: If True, replace existing files. (default: False)
2779             :param chunk_size: Bytes to read at a time. (default: 64kb)
2780         """
2781         if isinstance(destination, basestring):  # Except file-likes here
2782             if os.path.isdir(destination):
2783                 destination = os.path.join(destination, self.filename)
2784             if not overwrite and os.path.exists(destination):
2785                 raise IOError('File exists.')
2786             with open(destination, 'wb') as fp:
2787                 self._copy_file(fp, chunk_size)
2788         else:
2789             self._copy_file(destination, chunk_size)
2790
2791 ###############################################################################
2792 # Application Helper ###########################################################
2793 ###############################################################################
2794
2795
2796 def abort(code=500, text='Unknown Error.'):
2797     """ Aborts execution and causes a HTTP error. """
2798     raise HTTPError(code, text)
2799
2800
2801 def redirect(url, code=None):
2802     """ Aborts execution and causes a 303 or 302 redirect, depending on
2803         the HTTP protocol version. """
2804     if not code:
2805         code = 303 if request.get('SERVER_PROTOCOL') == "HTTP/1.1" else 302
2806     res = response.copy(cls=HTTPResponse)
2807     res.status = code
2808     res.body = ""
2809     res.set_header('Location', urljoin(request.url, url))
2810     raise res
2811
2812
2813 def _file_iter_range(fp, offset, bytes, maxread=1024 * 1024, close=False):
2814     """ Yield chunks from a range in a file, optionally closing it at the end.
2815         No chunk is bigger than maxread. """
2816     fp.seek(offset)
2817     while bytes > 0:
2818         part = fp.read(min(bytes, maxread))
2819         if not part:
2820             break
2821         bytes -= len(part)
2822         yield part
2823     if close:
2824         fp.close()
2825
2826
2827 def static_file(filename, root,
2828                 mimetype=True,
2829                 download=False,
2830                 charset='UTF-8',
2831                 etag=None):
2832     """ Open a file in a safe way and return an instance of :exc:`HTTPResponse`
2833         that can be sent back to the client.
2834
2835         :param filename: Name or path of the file to send, relative to ``root``.
2836         :param root: Root path for file lookups. Should be an absolute directory
2837             path.
2838         :param mimetype: Provide the content-type header (default: guess from
2839             file extension)
2840         :param download: If True, ask the browser to open a `Save as...` dialog
2841             instead of opening the file with the associated program. You can
2842             specify a custom filename as a string. If not specified, the
2843             original filename is used (default: False).
2844         :param charset: The charset for files with a ``text/*`` mime-type.
2845             (default: UTF-8)
2846         :param etag: Provide a pre-computed ETag header. If set to ``False``,
2847             ETag handling is disabled. (default: auto-generate ETag header)
2848
2849         While checking user input is always a good idea, this function provides
2850         additional protection against malicious ``filename`` parameters from
2851         breaking out of the ``root`` directory and leaking sensitive information
2852         to an attacker.
2853
2854         Read-protected files or files outside of the ``root`` directory are
2855         answered with ``403 Access Denied``. Missing files result in a
2856         ``404 Not Found`` response. Conditional requests (``If-Modified-Since``,
2857         ``If-None-Match``) are answered with ``304 Not Modified`` whenever
2858         possible. ``HEAD`` and ``Range`` requests (used by download managers to
2859         check or continue partial downloads) are also handled automatically.
2860
2861     """
2862
2863     root = os.path.join(os.path.abspath(root), '')
2864     filename = os.path.abspath(os.path.join(root, filename.strip('/\\')))
2865     headers = dict()
2866
2867     if not filename.startswith(root):
2868         return HTTPError(403, "Access denied.")
2869     if not os.path.exists(filename) or not os.path.isfile(filename):
2870         return HTTPError(404, "File does not exist.")
2871     if not os.access(filename, os.R_OK):
2872         return HTTPError(403, "You do not have permission to access this file.")
2873
2874     if mimetype is True:
2875         if download and download is not True:
2876             mimetype, encoding = mimetypes.guess_type(download)
2877         else:
2878             mimetype, encoding = mimetypes.guess_type(filename)
2879         if encoding: headers['Content-Encoding'] = encoding
2880
2881     if mimetype:
2882         if (mimetype[:5] == 'text/' or mimetype == 'application/javascript')\
2883         and charset and 'charset' not in mimetype:
2884             mimetype += '; charset=%s' % charset
2885         headers['Content-Type'] = mimetype
2886
2887     if download:
2888         download = os.path.basename(filename if download is True else download)
2889         headers['Content-Disposition'] = 'attachment; filename="%s"' % download
2890
2891     stats = os.stat(filename)
2892     headers['Content-Length'] = clen = stats.st_size
2893     headers['Last-Modified'] = email.utils.formatdate(stats.st_mtime,
2894                                                       usegmt=True)
2895     headers['Date'] = email.utils.formatdate(time.time(), usegmt=True)
2896
2897     getenv = request.environ.get
2898
2899     if etag is None:
2900         etag = '%d:%d:%d:%d:%s' % (stats.st_dev, stats.st_ino, stats.st_mtime,
2901                                    clen, filename)
2902         etag = hashlib.sha1(tob(etag)).hexdigest()
2903
2904     if etag:
2905         headers['ETag'] = etag
2906         check = getenv('HTTP_IF_NONE_MATCH')
2907         if check and check == etag:
2908             return HTTPResponse(status=304, **headers)
2909
2910     ims = getenv('HTTP_IF_MODIFIED_SINCE')
2911     if ims:
2912         ims = parse_date(ims.split(";")[0].strip())
2913     if ims is not None and ims >= int(stats.st_mtime):
2914         return HTTPResponse(status=304, **headers)
2915
2916     body = '' if request.method == 'HEAD' else open(filename, 'rb')
2917
2918     headers["Accept-Ranges"] = "bytes"
2919     range_header = getenv('HTTP_RANGE')
2920     if range_header:
2921         ranges = list(parse_range_header(range_header, clen))
2922         if not ranges:
2923             return HTTPError(416, "Requested Range Not Satisfiable")
2924         offset, end = ranges[0]
2925         headers["Content-Range"] = "bytes %d-%d/%d" % (offset, end - 1, clen)
2926         headers["Content-Length"] = str(end - offset)
2927         if body: body = _file_iter_range(body, offset, end - offset, close=True)
2928         return HTTPResponse(body, status=206, **headers)
2929     return HTTPResponse(body, **headers)
2930
2931 ###############################################################################
2932 # HTTP Utilities and MISC (TODO) ###############################################
2933 ###############################################################################
2934
2935
2936 def debug(mode=True):
2937     """ Change the debug level.
2938     There is only one debug level supported at the moment."""
2939     global DEBUG
2940     if mode: warnings.simplefilter('default')
2941     DEBUG = bool(mode)
2942
2943
2944 def http_date(value):
2945     if isinstance(value, (datedate, datetime)):
2946         value = value.utctimetuple()
2947     elif isinstance(value, (int, float)):
2948         value = time.gmtime(value)
2949     if not isinstance(value, basestring):
2950         value = time.strftime("%a, %d %b %Y %H:%M:%S GMT", value)
2951     return value
2952
2953
2954 def parse_date(ims):
2955     """ Parse rfc1123, rfc850 and asctime timestamps and return UTC epoch. """
2956     try:
2957         ts = email.utils.parsedate_tz(ims)
2958         return time.mktime(ts[:8] + (0, )) - (ts[9] or 0) - time.timezone
2959     except (TypeError, ValueError, IndexError, OverflowError):
2960         return None
2961
2962
2963 def parse_auth(header):
2964     """ Parse rfc2617 HTTP authentication header string (basic) and return (user,pass) tuple or None"""
2965     try:
2966         method, data = header.split(None, 1)
2967         if method.lower() == 'basic':
2968             user, pwd = touni(base64.b64decode(tob(data))).split(':', 1)
2969             return user, pwd
2970     except (KeyError, ValueError):
2971         return None
2972
2973
2974 def parse_range_header(header, maxlen=0):
2975     """ Yield (start, end) ranges parsed from a HTTP Range header. Skip
2976         unsatisfiable ranges. The end index is non-inclusive."""
2977     if not header or header[:6] != 'bytes=': return
2978     ranges = [r.split('-', 1) for r in header[6:].split(',') if '-' in r]
2979     for start, end in ranges:
2980         try:
2981             if not start:  # bytes=-100    -> last 100 bytes
2982                 start, end = max(0, maxlen - int(end)), maxlen
2983             elif not end:  # bytes=100-    -> all but the first 99 bytes
2984                 start, end = int(start), maxlen
2985             else:  # bytes=100-200 -> bytes 100-200 (inclusive)
2986                 start, end = int(start), min(int(end) + 1, maxlen)
2987             if 0 <= start < end <= maxlen:
2988                 yield start, end
2989         except ValueError:
2990             pass
2991
2992
2993 #: Header tokenizer used by _parse_http_header()
2994 _hsplit = re.compile('(?:(?:"((?:[^"\\\\]+|\\\\.)*)")|([^;,=]+))([;,=]?)').findall
2995
2996 def _parse_http_header(h):
2997     """ Parses a typical multi-valued and parametrised HTTP header (e.g. Accept headers) and returns a list of values
2998         and parameters. For non-standard or broken input, this implementation may return partial results.
2999     :param h: A header string (e.g. ``text/html,text/plain;q=0.9,*/*;q=0.8``)
3000     :return: List of (value, params) tuples. The second element is a (possibly empty) dict.
3001     """
3002     values = []
3003     if '"' not in h:  # INFO: Fast path without regexp (~2x faster)
3004         for value in h.split(','):
3005             parts = value.split(';')
3006             values.append((parts[0].strip(), {}))
3007             for attr in parts[1:]:
3008                 name, value = attr.split('=', 1)
3009                 values[-1][1][name.strip()] = value.strip()
3010     else:
3011         lop, key, attrs = ',', None, {}
3012         for quoted, plain, tok in _hsplit(h):
3013             value = plain.strip() if plain else quoted.replace('\\"', '"')
3014             if lop == ',':
3015                 attrs = {}
3016                 values.append((value, attrs))
3017             elif lop == ';':
3018                 if tok == '=':
3019                     key = value
3020                 else:
3021                     attrs[value] = ''
3022             elif lop == '=' and key:
3023                 attrs[key] = value
3024                 key = None
3025             lop = tok
3026     return values
3027
3028
3029 def _parse_qsl(qs):
3030     r = []
3031     for pair in qs.replace(';', '&').split('&'):
3032         if not pair: continue
3033         nv = pair.split('=', 1)
3034         if len(nv) != 2: nv.append('')
3035         key = urlunquote(nv[0].replace('+', ' '))
3036         value = urlunquote(nv[1].replace('+', ' '))
3037         r.append((key, value))
3038     return r
3039
3040
3041 def _lscmp(a, b):
3042     """ Compares two strings in a cryptographically safe way:
3043         Runtime is not affected by length of common prefix. """
3044     return not sum(0 if x == y else 1
3045                    for x, y in zip(a, b)) and len(a) == len(b)
3046
3047
3048 def cookie_encode(data, key, digestmod=None):
3049     """ Encode and sign a pickle-able object. Return a (byte) string """
3050     depr(0, 13, "cookie_encode() will be removed soon.",
3051                 "Do not use this API directly.")
3052     digestmod = digestmod or hashlib.sha256
3053     msg = base64.b64encode(pickle.dumps(data, -1))
3054     sig = base64.b64encode(hmac.new(tob(key), msg, digestmod=digestmod).digest())
3055     return tob('!') + sig + tob('?') + msg
3056
3057
3058 def cookie_decode(data, key, digestmod=None):
3059     """ Verify and decode an encoded string. Return an object or None."""
3060     depr(0, 13, "cookie_decode() will be removed soon.",
3061                 "Do not use this API directly.")
3062     data = tob(data)
3063     if cookie_is_encoded(data):
3064         sig, msg = data.split(tob('?'), 1)
3065         digestmod = digestmod or hashlib.sha256
3066         hashed = hmac.new(tob(key), msg, digestmod=digestmod).digest()
3067         if _lscmp(sig[1:], base64.b64encode(hashed)):
3068             return pickle.loads(base64.b64decode(msg))
3069     return None
3070
3071
3072 def cookie_is_encoded(data):
3073     """ Return True if the argument looks like a encoded cookie."""
3074     depr(0, 13, "cookie_is_encoded() will be removed soon.",
3075                 "Do not use this API directly.")
3076     return bool(data.startswith(tob('!')) and tob('?') in data)
3077
3078
3079 def html_escape(string):
3080     """ Escape HTML special characters ``&<>`` and quotes ``'"``. """
3081     return string.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')\
3082                  .replace('"', '&quot;').replace("'", '&#039;')
3083
3084
3085 def html_quote(string):
3086     """ Escape and quote a string to be used as an HTTP attribute."""
3087     return '"%s"' % html_escape(string).replace('\n', '&#10;')\
3088                     .replace('\r', '&#13;').replace('\t', '&#9;')
3089
3090
3091 def yieldroutes(func):
3092     """ Return a generator for routes that match the signature (name, args)
3093     of the func parameter. This may yield more than one route if the function
3094     takes optional keyword arguments. The output is best described by example::
3095
3096         a()         -> '/a'
3097         b(x, y)     -> '/b/<x>/<y>'
3098         c(x, y=5)   -> '/c/<x>' and '/c/<x>/<y>'
3099         d(x=5, y=6) -> '/d' and '/d/<x>' and '/d/<x>/<y>'
3100     """
3101     path = '/' + func.__name__.replace('__', '/').lstrip('/')
3102     spec = getargspec(func)
3103     argc = len(spec[0]) - len(spec[3] or [])
3104     path += ('/<%s>' * argc) % tuple(spec[0][:argc])
3105     yield path
3106     for arg in spec[0][argc:]:
3107         path += '/<%s>' % arg
3108         yield path
3109
3110
3111 def path_shift(script_name, path_info, shift=1):
3112     """ Shift path fragments from PATH_INFO to SCRIPT_NAME and vice versa.
3113
3114         :return: The modified paths.
3115         :param script_name: The SCRIPT_NAME path.
3116         :param script_name: The PATH_INFO path.
3117         :param shift: The number of path fragments to shift. May be negative to
3118           change the shift direction. (default: 1)
3119     """
3120     if shift == 0: return script_name, path_info
3121     pathlist = path_info.strip('/').split('/')
3122     scriptlist = script_name.strip('/').split('/')
3123     if pathlist and pathlist[0] == '': pathlist = []
3124     if scriptlist and scriptlist[0] == '': scriptlist = []
3125     if 0 < shift <= len(pathlist):
3126         moved = pathlist[:shift]
3127         scriptlist = scriptlist + moved
3128         pathlist = pathlist[shift:]
3129     elif 0 > shift >= -len(scriptlist):
3130         moved = scriptlist[shift:]
3131         pathlist = moved + pathlist
3132         scriptlist = scriptlist[:shift]
3133     else:
3134         empty = 'SCRIPT_NAME' if shift < 0 else 'PATH_INFO'
3135         raise AssertionError("Cannot shift. Nothing left from %s" % empty)
3136     new_script_name = '/' + '/'.join(scriptlist)
3137     new_path_info = '/' + '/'.join(pathlist)
3138     if path_info.endswith('/') and pathlist: new_path_info += '/'
3139     return new_script_name, new_path_info
3140
3141
3142 def auth_basic(check, realm="private", text="Access denied"):
3143     """ Callback decorator to require HTTP auth (basic).
3144         TODO: Add route(check_auth=...) parameter. """
3145
3146     def decorator(func):
3147
3148         @functools.wraps(func)
3149         def wrapper(*a, **ka):
3150             user, password = request.auth or (None, None)
3151             if user is None or not check(user, password):
3152                 err = HTTPError(401, text)
3153                 err.add_header('WWW-Authenticate', 'Basic realm="%s"' % realm)
3154                 return err
3155             return func(*a, **ka)
3156
3157         return wrapper
3158
3159     return decorator
3160
3161 # Shortcuts for common Bottle methods.
3162 # They all refer to the current default application.
3163
3164
3165 def make_default_app_wrapper(name):
3166     """ Return a callable that relays calls to the current default app. """
3167
3168     @functools.wraps(getattr(Bottle, name))
3169     def wrapper(*a, **ka):
3170         return getattr(app(), name)(*a, **ka)
3171
3172     return wrapper
3173
3174
3175 route     = make_default_app_wrapper('route')
3176 get       = make_default_app_wrapper('get')
3177 post      = make_default_app_wrapper('post')
3178 put       = make_default_app_wrapper('put')
3179 delete    = make_default_app_wrapper('delete')
3180 patch     = make_default_app_wrapper('patch')
3181 error     = make_default_app_wrapper('error')
3182 mount     = make_default_app_wrapper('mount')
3183 hook      = make_default_app_wrapper('hook')
3184 install   = make_default_app_wrapper('install')
3185 uninstall = make_default_app_wrapper('uninstall')
3186 url       = make_default_app_wrapper('get_url')
3187
3188 ###############################################################################
3189 # Server Adapter ###############################################################
3190 ###############################################################################
3191
3192 # Before you edit or add a server adapter, please read:
3193 # - https://github.com/bottlepy/bottle/pull/647#issuecomment-60152870
3194 # - https://github.com/bottlepy/bottle/pull/865#issuecomment-242795341
3195
3196 class ServerAdapter(object):
3197     quiet = False
3198
3199     def __init__(self, host='127.0.0.1', port=8080, **options):
3200         self.options = options
3201         self.host = host
3202         self.port = int(port)
3203
3204     def run(self, handler):  # pragma: no cover
3205         pass
3206
3207     def __repr__(self):
3208         args = ', '.join(['%s=%s' % (k, repr(v))
3209                           for k, v in self.options.items()])
3210         return "%s(%s)" % (self.__class__.__name__, args)
3211
3212
3213 class CGIServer(ServerAdapter):
3214     quiet = True
3215
3216     def run(self, handler):  # pragma: no cover
3217         from wsgiref.handlers import CGIHandler
3218
3219         def fixed_environ(environ, start_response):
3220             environ.setdefault('PATH_INFO', '')
3221             return handler(environ, start_response)
3222
3223         CGIHandler().run(fixed_environ)
3224
3225
3226 class FlupFCGIServer(ServerAdapter):
3227     def run(self, handler):  # pragma: no cover
3228         import flup.server.fcgi
3229         self.options.setdefault('bindAddress', (self.host, self.port))
3230         flup.server.fcgi.WSGIServer(handler, **self.options).run()
3231
3232
3233 class WSGIRefServer(ServerAdapter):
3234     def run(self, app):  # pragma: no cover
3235         from wsgiref.simple_server import make_server
3236         from wsgiref.simple_server import WSGIRequestHandler, WSGIServer
3237         import socket
3238
3239         class FixedHandler(WSGIRequestHandler):
3240             def address_string(self):  # Prevent reverse DNS lookups please.
3241                 return self.client_address[0]
3242
3243             def log_request(*args, **kw):
3244                 if not self.quiet:
3245                     return WSGIRequestHandler.log_request(*args, **kw)
3246
3247         handler_cls = self.options.get('handler_class', FixedHandler)
3248         server_cls = self.options.get('server_class', WSGIServer)
3249
3250         if ':' in self.host:  # Fix wsgiref for IPv6 addresses.
3251             if getattr(server_cls, 'address_family') == socket.AF_INET:
3252
3253                 class server_cls(server_cls):
3254                     address_family = socket.AF_INET6
3255
3256         self.srv = make_server(self.host, self.port, app, server_cls,
3257                                handler_cls)
3258         self.port = self.srv.server_port  # update port actual port (0 means random)
3259         try:
3260             self.srv.serve_forever()
3261         except KeyboardInterrupt:
3262             self.srv.server_close()  # Prevent ResourceWarning: unclosed socket
3263             raise
3264
3265
3266 class CherryPyServer(ServerAdapter):
3267     def run(self, handler):  # pragma: no cover
3268         depr(0, 13, "The wsgi server part of cherrypy was split into a new "
3269                     "project called 'cheroot'.", "Use the 'cheroot' server "
3270                     "adapter instead of cherrypy.")
3271         from cherrypy import wsgiserver # This will fail for CherryPy >= 9
3272
3273         self.options['bind_addr'] = (self.host, self.port)
3274         self.options['wsgi_app'] = handler
3275
3276         certfile = self.options.get('certfile')
3277         if certfile:
3278             del self.options['certfile']
3279         keyfile = self.options.get('keyfile')
3280         if keyfile:
3281             del self.options['keyfile']
3282
3283         server = wsgiserver.CherryPyWSGIServer(**self.options)
3284         if certfile:
3285             server.ssl_certificate = certfile
3286         if keyfile:
3287             server.ssl_private_key = keyfile
3288
3289         try:
3290             server.start()
3291         finally:
3292             server.stop()
3293
3294
3295 class CherootServer(ServerAdapter):
3296     def run(self, handler): # pragma: no cover
3297         from cheroot import wsgi
3298         from cheroot.ssl import builtin
3299         self.options['bind_addr'] = (self.host, self.port)
3300         self.options['wsgi_app'] = handler
3301         certfile = self.options.pop('certfile', None)
3302         keyfile = self.options.pop('keyfile', None)
3303         chainfile = self.options.pop('chainfile', None)
3304         server = wsgi.Server(**self.options)
3305         if certfile and keyfile:
3306             server.ssl_adapter = builtin.BuiltinSSLAdapter(
3307                     certfile, keyfile, chainfile)
3308         try:
3309             server.start()
3310         finally:
3311             server.stop()
3312
3313
3314 class WaitressServer(ServerAdapter):
3315     def run(self, handler):
3316         from waitress import serve
3317         serve(handler, host=self.host, port=self.port, _quiet=self.quiet, **self.options)
3318
3319
3320 class PasteServer(ServerAdapter):
3321     def run(self, handler):  # pragma: no cover
3322         from paste import httpserver
3323         from paste.translogger import TransLogger
3324         handler = TransLogger(handler, setup_console_handler=(not self.quiet))
3325         httpserver.serve(handler,
3326                          host=self.host,
3327                          port=str(self.port), **self.options)
3328
3329
3330 class MeinheldServer(ServerAdapter):
3331     def run(self, handler):
3332         from meinheld import server
3333         server.listen((self.host, self.port))
3334         server.run(handler)
3335
3336
3337 class FapwsServer(ServerAdapter):
3338     """ Extremely fast webserver using libev. See http://www.fapws.org/ """
3339
3340     def run(self, handler):  # pragma: no cover
3341         import fapws._evwsgi as evwsgi
3342         from fapws import base, config
3343         port = self.port
3344         if float(config.SERVER_IDENT[-2:]) > 0.4:
3345             # fapws3 silently changed its API in 0.5
3346             port = str(port)
3347         evwsgi.start(self.host, port)
3348         # fapws3 never releases the GIL. Complain upstream. I tried. No luck.
3349         if 'BOTTLE_CHILD' in os.environ and not self.quiet:
3350             _stderr("WARNING: Auto-reloading does not work with Fapws3.\n")
3351             _stderr("         (Fapws3 breaks python thread support)\n")
3352         evwsgi.set_base_module(base)
3353
3354         def app(environ, start_response):
3355             environ['wsgi.multiprocess'] = False
3356             return handler(environ, start_response)
3357
3358         evwsgi.wsgi_cb(('', app))
3359         evwsgi.run()
3360
3361
3362 class TornadoServer(ServerAdapter):
3363     """ The super hyped asynchronous server by facebook. Untested. """
3364
3365     def run(self, handler):  # pragma: no cover
3366         import tornado.wsgi, tornado.httpserver, tornado.ioloop
3367         container = tornado.wsgi.WSGIContainer(handler)
3368         server = tornado.httpserver.HTTPServer(container)
3369         server.listen(port=self.port, address=self.host)
3370         tornado.ioloop.IOLoop.instance().start()
3371
3372
3373 class AppEngineServer(ServerAdapter):
3374     """ Adapter for Google App Engine. """
3375     quiet = True
3376
3377     def run(self, handler):
3378         depr(0, 13, "AppEngineServer no longer required",
3379              "Configure your application directly in your app.yaml")
3380         from google.appengine.ext.webapp import util
3381         # A main() function in the handler script enables 'App Caching'.
3382         # Lets makes sure it is there. This _really_ improves performance.
3383         module = sys.modules.get('__main__')
3384         if module and not hasattr(module, 'main'):
3385             module.main = lambda: util.run_wsgi_app(handler)
3386         util.run_wsgi_app(handler)
3387
3388
3389 class TwistedServer(ServerAdapter):
3390     """ Untested. """
3391
3392     def run(self, handler):
3393         from twisted.web import server, wsgi
3394         from twisted.python.threadpool import ThreadPool
3395         from twisted.internet import reactor
3396         thread_pool = ThreadPool()
3397         thread_pool.start()
3398         reactor.addSystemEventTrigger('after', 'shutdown', thread_pool.stop)
3399         factory = server.Site(wsgi.WSGIResource(reactor, thread_pool, handler))
3400         reactor.listenTCP(self.port, factory, interface=self.host)
3401         if not reactor.running:
3402             reactor.run()
3403
3404
3405 class DieselServer(ServerAdapter):
3406     """ Untested. """
3407
3408     def run(self, handler):
3409         from diesel.protocols.wsgi import WSGIApplication
3410         app = WSGIApplication(handler, port=self.port)
3411         app.run()
3412
3413
3414 class GeventServer(ServerAdapter):
3415     """ Untested. Options:
3416
3417         * See gevent.wsgi.WSGIServer() documentation for more options.
3418     """
3419
3420     def run(self, handler):
3421         from gevent import pywsgi, local
3422         if not isinstance(threading.local(), local.local):
3423             msg = "Bottle requires gevent.monkey.patch_all() (before import)"
3424             raise RuntimeError(msg)
3425         if self.quiet:
3426             self.options['log'] = None
3427         address = (self.host, self.port)
3428         server = pywsgi.WSGIServer(address, handler, **self.options)
3429         if 'BOTTLE_CHILD' in os.environ:
3430             import signal
3431             signal.signal(signal.SIGINT, lambda s, f: server.stop())
3432         server.serve_forever()
3433
3434
3435 class GunicornServer(ServerAdapter):
3436     """ Untested. See http://gunicorn.org/configure.html for options. """
3437
3438     def run(self, handler):
3439         from gunicorn.app.base import Application
3440
3441         config = {'bind': "%s:%d" % (self.host, int(self.port))}
3442         config.update(self.options)
3443
3444         class GunicornApplication(Application):
3445             def init(self, parser, opts, args):
3446                 return config
3447
3448             def load(self):
3449                 return handler
3450
3451         GunicornApplication().run()
3452
3453
3454 class EventletServer(ServerAdapter):
3455     """ Untested. Options:
3456
3457         * `backlog` adjust the eventlet backlog parameter which is the maximum
3458           number of queued connections. Should be at least 1; the maximum
3459           value is system-dependent.
3460         * `family`: (default is 2) socket family, optional. See socket
3461           documentation for available families.
3462     """
3463
3464     def run(self, handler):
3465         from eventlet import wsgi, listen, patcher
3466         if not patcher.is_monkey_patched(os):
3467             msg = "Bottle requires eventlet.monkey_patch() (before import)"
3468             raise RuntimeError(msg)
3469         socket_args = {}
3470         for arg in ('backlog', 'family'):
3471             try:
3472                 socket_args[arg] = self.options.pop(arg)
3473             except KeyError:
3474                 pass
3475         address = (self.host, self.port)
3476         try:
3477             wsgi.server(listen(address, **socket_args), handler,
3478                         log_output=(not self.quiet))
3479         except TypeError:
3480             # Fallback, if we have old version of eventlet
3481             wsgi.server(listen(address), handler)
3482
3483
3484 class RocketServer(ServerAdapter):
3485     """ Untested. """
3486
3487     def run(self, handler):
3488         from rocket import Rocket
3489         server = Rocket((self.host, self.port), 'wsgi', {'wsgi_app': handler})
3490         server.start()
3491
3492
3493 class BjoernServer(ServerAdapter):
3494     """ Fast server written in C: https://github.com/jonashaag/bjoern """
3495
3496     def run(self, handler):
3497         from bjoern import run
3498         run(handler, self.host, self.port)
3499
3500 class AsyncioServerAdapter(ServerAdapter):
3501     """ Extend ServerAdapter for adding custom event loop """
3502     def get_event_loop(self):
3503         pass
3504
3505 class AiohttpServer(AsyncioServerAdapter):
3506     """ Untested.
3507         aiohttp
3508         https://pypi.python.org/pypi/aiohttp/
3509     """
3510
3511     def get_event_loop(self):
3512         import asyncio
3513         return asyncio.new_event_loop()
3514
3515     def run(self, handler):
3516         import asyncio
3517         from aiohttp.wsgi import WSGIServerHttpProtocol
3518         self.loop = self.get_event_loop()
3519         asyncio.set_event_loop(self.loop)
3520
3521         protocol_factory = lambda: WSGIServerHttpProtocol(
3522             handler,
3523             readpayload=True,
3524             debug=(not self.quiet))
3525         self.loop.run_until_complete(self.loop.create_server(protocol_factory,
3526                                                              self.host,
3527                                                              self.port))
3528
3529         if 'BOTTLE_CHILD' in os.environ:
3530             import signal
3531             signal.signal(signal.SIGINT, lambda s, f: self.loop.stop())
3532
3533         try:
3534             self.loop.run_forever()
3535         except KeyboardInterrupt:
3536             self.loop.stop()
3537
3538 class AiohttpUVLoopServer(AiohttpServer):
3539     """uvloop
3540        https://github.com/MagicStack/uvloop
3541     """
3542     def get_event_loop(self):
3543         import uvloop
3544         return uvloop.new_event_loop()
3545
3546 class AutoServer(ServerAdapter):
3547     """ Untested. """
3548     adapters = [WaitressServer, PasteServer, TwistedServer, CherryPyServer,
3549                 CherootServer, WSGIRefServer]
3550
3551     def run(self, handler):
3552         for sa in self.adapters:
3553             try:
3554                 return sa(self.host, self.port, **self.options).run(handler)
3555             except ImportError:
3556                 pass
3557
3558
3559 server_names = {
3560     'cgi': CGIServer,
3561     'flup': FlupFCGIServer,
3562     'wsgiref': WSGIRefServer,
3563     'waitress': WaitressServer,
3564     'cherrypy': CherryPyServer,
3565     'cheroot': CherootServer,
3566     'paste': PasteServer,
3567     'fapws3': FapwsServer,
3568     'tornado': TornadoServer,
3569     'gae': AppEngineServer,
3570     'twisted': TwistedServer,
3571     'diesel': DieselServer,
3572     'meinheld': MeinheldServer,
3573     'gunicorn': GunicornServer,
3574     'eventlet': EventletServer,
3575     'gevent': GeventServer,
3576     'rocket': RocketServer,
3577     'bjoern': BjoernServer,
3578     'aiohttp': AiohttpServer,
3579     'uvloop': AiohttpUVLoopServer,
3580     'auto': AutoServer,
3581 }
3582
3583 ###############################################################################
3584 # Application Control ##########################################################
3585 ###############################################################################
3586
3587
3588 def load(target, **namespace):
3589     """ Import a module or fetch an object from a module.
3590
3591         * ``package.module`` returns `module` as a module object.
3592         * ``pack.mod:name`` returns the module variable `name` from `pack.mod`.
3593         * ``pack.mod:func()`` calls `pack.mod.func()` and returns the result.
3594
3595         The last form accepts not only function calls, but any type of
3596         expression. Keyword arguments passed to this function are available as
3597         local variables. Example: ``import_string('re:compile(x)', x='[a-z]')``
3598     """
3599     module, target = target.split(":", 1) if ':' in target else (target, None)
3600     if module not in sys.modules: __import__(module)
3601     if not target: return sys.modules[module]
3602     if target.isalnum(): return getattr(sys.modules[module], target)
3603     package_name = module.split('.')[0]
3604     namespace[package_name] = sys.modules[package_name]
3605     return eval('%s.%s' % (module, target), namespace)
3606
3607
3608 def load_app(target):
3609     """ Load a bottle application from a module and make sure that the import
3610         does not affect the current default application, but returns a separate
3611         application object. See :func:`load` for the target parameter. """
3612     global NORUN
3613     NORUN, nr_old = True, NORUN
3614     tmp = default_app.push()  # Create a new "default application"
3615     try:
3616         rv = load(target)  # Import the target module
3617         return rv if callable(rv) else tmp
3618     finally:
3619         default_app.remove(tmp)  # Remove the temporary added default application
3620         NORUN = nr_old
3621
3622
3623 _debug = debug
3624
3625
3626 def run(app=None,
3627         server='wsgiref',
3628         host='127.0.0.1',
3629         port=8080,
3630         interval=1,
3631         reloader=False,
3632         quiet=False,
3633         plugins=None,
3634         debug=None,
3635         config=None, **kargs):
3636     """ Start a server instance. This method blocks until the server terminates.
3637
3638         :param app: WSGI application or target string supported by
3639                :func:`load_app`. (default: :func:`default_app`)
3640         :param server: Server adapter to use. See :data:`server_names` keys
3641                for valid names or pass a :class:`ServerAdapter` subclass.
3642                (default: `wsgiref`)
3643         :param host: Server address to bind to. Pass ``0.0.0.0`` to listens on
3644                all interfaces including the external one. (default: 127.0.0.1)
3645         :param port: Server port to bind to. Values below 1024 require root
3646                privileges. (default: 8080)
3647         :param reloader: Start auto-reloading server? (default: False)
3648         :param interval: Auto-reloader interval in seconds (default: 1)
3649         :param quiet: Suppress output to stdout and stderr? (default: False)
3650         :param options: Options passed to the server adapter.
3651      """
3652     if NORUN: return
3653     if reloader and not os.environ.get('BOTTLE_CHILD'):
3654         import subprocess
3655         lockfile = None
3656         try:
3657             fd, lockfile = tempfile.mkstemp(prefix='bottle.', suffix='.lock')
3658             os.close(fd)  # We only need this file to exist. We never write to it
3659             while os.path.exists(lockfile):
3660                 args = [sys.executable] + sys.argv
3661                 environ = os.environ.copy()
3662                 environ['BOTTLE_CHILD'] = 'true'
3663                 environ['BOTTLE_LOCKFILE'] = lockfile
3664                 p = subprocess.Popen(args, env=environ)
3665                 while p.poll() is None:  # Busy wait...
3666                     os.utime(lockfile, None)  # I am alive!
3667                     time.sleep(interval)
3668                 if p.poll() != 3:
3669                     if os.path.exists(lockfile): os.unlink(lockfile)
3670                     sys.exit(p.poll())
3671         except KeyboardInterrupt:
3672             pass
3673         finally:
3674             if os.path.exists(lockfile):
3675                 os.unlink(lockfile)
3676         return
3677
3678     try:
3679         if debug is not None: _debug(debug)
3680         app = app or default_app()
3681         if isinstance(app, basestring):
3682             app = load_app(app)
3683         if not callable(app):
3684             raise ValueError("Application is not callable: %r" % app)
3685
3686         for plugin in plugins or []:
3687             if isinstance(plugin, basestring):
3688                 plugin = load(plugin)
3689             app.install(plugin)
3690
3691         if config:
3692             app.config.update(config)
3693
3694         if server in server_names:
3695             server = server_names.get(server)
3696         if isinstance(server, basestring):
3697             server = load(server)
3698         if isinstance(server, type):
3699             server = server(host=host, port=port, **kargs)
3700         if not isinstance(server, ServerAdapter):
3701             raise ValueError("Unknown or unsupported server: %r" % server)
3702
3703         server.quiet = server.quiet or quiet
3704         if not server.quiet:
3705             _stderr("Bottle v%s server starting up (using %s)...\n" %
3706                     (__version__, repr(server)))
3707             _stderr("Listening on http://%s:%d/\n" %
3708                     (server.host, server.port))
3709             _stderr("Hit Ctrl-C to quit.\n\n")
3710
3711         if reloader:
3712             lockfile = os.environ.get('BOTTLE_LOCKFILE')
3713             bgcheck = FileCheckerThread(lockfile, interval)
3714             with bgcheck:
3715                 server.run(app)
3716             if bgcheck.status == 'reload':
3717                 sys.exit(3)
3718         else:
3719             server.run(app)
3720     except KeyboardInterrupt:
3721         pass
3722     except (SystemExit, MemoryError):
3723         raise
3724     except:
3725         if not reloader: raise
3726         if not getattr(server, 'quiet', quiet):
3727             print_exc()
3728         time.sleep(interval)
3729         sys.exit(3)
3730
3731
3732 class FileCheckerThread(threading.Thread):
3733     """ Interrupt main-thread as soon as a changed module file is detected,
3734         the lockfile gets deleted or gets too old. """
3735
3736     def __init__(self, lockfile, interval):
3737         threading.Thread.__init__(self)
3738         self.daemon = True
3739         self.lockfile, self.interval = lockfile, interval
3740         #: Is one of 'reload', 'error' or 'exit'
3741         self.status = None
3742
3743     def run(self):
3744         exists = os.path.exists
3745         mtime = lambda p: os.stat(p).st_mtime
3746         files = dict()
3747
3748         for module in list(sys.modules.values()):
3749             path = getattr(module, '__file__', '')
3750             if path[-4:] in ('.pyo', '.pyc'): path = path[:-1]
3751             if path and exists(path): files[path] = mtime(path)
3752
3753         while not self.status:
3754             if not exists(self.lockfile)\
3755             or mtime(self.lockfile) < time.time() - self.interval - 5:
3756                 self.status = 'error'
3757                 thread.interrupt_main()
3758             for path, lmtime in list(files.items()):
3759                 if not exists(path) or mtime(path) > lmtime:
3760                     self.status = 'reload'
3761                     thread.interrupt_main()
3762                     break
3763             time.sleep(self.interval)
3764
3765     def __enter__(self):
3766         self.start()
3767
3768     def __exit__(self, exc_type, *_):
3769         if not self.status: self.status = 'exit'  # silent exit
3770         self.join()
3771         return exc_type is not None and issubclass(exc_type, KeyboardInterrupt)
3772
3773 ###############################################################################
3774 # Template Adapters ############################################################
3775 ###############################################################################
3776
3777
3778 class TemplateError(BottleException):
3779     pass
3780
3781
3782 class BaseTemplate(object):
3783     """ Base class and minimal API for template adapters """
3784     extensions = ['tpl', 'html', 'thtml', 'stpl']
3785     settings = {}  #used in prepare()
3786     defaults = {}  #used in render()
3787
3788     def __init__(self,
3789                  source=None,
3790                  name=None,
3791                  lookup=None,
3792                  encoding='utf8', **settings):
3793         """ Create a new template.
3794         If the source parameter (str or buffer) is missing, the name argument
3795         is used to guess a template filename. Subclasses can assume that
3796         self.source and/or self.filename are set. Both are strings.
3797         The lookup, encoding and settings parameters are stored as instance
3798         variables.
3799         The lookup parameter stores a list containing directory paths.
3800         The encoding parameter should be used to decode byte strings or files.
3801         The settings parameter contains a dict for engine-specific settings.
3802         """
3803         self.name = name
3804         self.source = source.read() if hasattr(source, 'read') else source
3805         self.filename = source.filename if hasattr(source, 'filename') else None
3806         self.lookup = [os.path.abspath(x) for x in lookup] if lookup else []
3807         self.encoding = encoding
3808         self.settings = self.settings.copy()  # Copy from class variable
3809         self.settings.update(settings)  # Apply
3810         if not self.source and self.name:
3811             self.filename = self.search(self.name, self.lookup)
3812             if not self.filename:
3813                 raise TemplateError('Template %s not found.' % repr(name))
3814         if not self.source and not self.filename:
3815             raise TemplateError('No template specified.')
3816         self.prepare(**self.settings)
3817
3818     @classmethod
3819     def search(cls, name, lookup=None):
3820         """ Search name in all directories specified in lookup.
3821         First without, then with common extensions. Return first hit. """
3822         if not lookup:
3823             raise depr(0, 12, "Empty template lookup path.", "Configure a template lookup path.")
3824
3825         if os.path.isabs(name):
3826             raise depr(0, 12, "Use of absolute path for template name.",
3827                        "Refer to templates with names or paths relative to the lookup path.")
3828
3829         for spath in lookup:
3830             spath = os.path.abspath(spath) + os.sep
3831             fname = os.path.abspath(os.path.join(spath, name))
3832             if not fname.startswith(spath): continue
3833             if os.path.isfile(fname): return fname
3834             for ext in cls.extensions:
3835                 if os.path.isfile('%s.%s' % (fname, ext)):
3836                     return '%s.%s' % (fname, ext)
3837
3838     @classmethod
3839     def global_config(cls, key, *args):
3840         """ This reads or sets the global settings stored in class.settings. """
3841         if args:
3842             cls.settings = cls.settings.copy()  # Make settings local to class
3843             cls.settings[key] = args[0]
3844         else:
3845             return cls.settings[key]
3846
3847     def prepare(self, **options):
3848         """ Run preparations (parsing, caching, ...).
3849         It should be possible to call this again to refresh a template or to
3850         update settings.
3851         """
3852         raise NotImplementedError
3853
3854     def render(self, *args, **kwargs):
3855         """ Render the template with the specified local variables and return
3856         a single byte or unicode string. If it is a byte string, the encoding
3857         must match self.encoding. This method must be thread-safe!
3858         Local variables may be provided in dictionaries (args)
3859         or directly, as keywords (kwargs).
3860         """
3861         raise NotImplementedError
3862
3863
3864 class MakoTemplate(BaseTemplate):
3865     def prepare(self, **options):
3866         from mako.template import Template
3867         from mako.lookup import TemplateLookup
3868         options.update({'input_encoding': self.encoding})
3869         options.setdefault('format_exceptions', bool(DEBUG))
3870         lookup = TemplateLookup(directories=self.lookup, **options)
3871         if self.source:
3872             self.tpl = Template(self.source, lookup=lookup, **options)
3873         else:
3874             self.tpl = Template(uri=self.name,
3875                                 filename=self.filename,
3876                                 lookup=lookup, **options)
3877
3878     def render(self, *args, **kwargs):
3879         for dictarg in args:
3880             kwargs.update(dictarg)
3881         _defaults = self.defaults.copy()
3882         _defaults.update(kwargs)
3883         return self.tpl.render(**_defaults)
3884
3885
3886 class CheetahTemplate(BaseTemplate):
3887     def prepare(self, **options):
3888         from Cheetah.Template import Template
3889         self.context = threading.local()
3890         self.context.vars = {}
3891         options['searchList'] = [self.context.vars]
3892         if self.source:
3893             self.tpl = Template(source=self.source, **options)
3894         else:
3895             self.tpl = Template(file=self.filename, **options)
3896
3897     def render(self, *args, **kwargs):
3898         for dictarg in args:
3899             kwargs.update(dictarg)
3900         self.context.vars.update(self.defaults)
3901         self.context.vars.update(kwargs)
3902         out = str(self.tpl)
3903         self.context.vars.clear()
3904         return out
3905
3906
3907 class Jinja2Template(BaseTemplate):
3908     def prepare(self, filters=None, tests=None, globals={}, **kwargs):
3909         from jinja2 import Environment, FunctionLoader
3910         self.env = Environment(loader=FunctionLoader(self.loader), **kwargs)
3911         if filters: self.env.filters.update(filters)
3912         if tests: self.env.tests.update(tests)
3913         if globals: self.env.globals.update(globals)
3914         if self.source:
3915             self.tpl = self.env.from_string(self.source)
3916         else:
3917             self.tpl = self.env.get_template(self.name)
3918
3919     def render(self, *args, **kwargs):
3920         for dictarg in args:
3921             kwargs.update(dictarg)
3922         _defaults = self.defaults.copy()
3923         _defaults.update(kwargs)
3924         return self.tpl.render(**_defaults)
3925
3926     def loader(self, name):
3927         if name == self.filename:
3928             fname = name
3929         else:
3930             fname = self.search(name, self.lookup)
3931         if not fname: return
3932         with open(fname, "rb") as f:
3933             return (f.read().decode(self.encoding), fname, lambda: False)
3934
3935
3936 class SimpleTemplate(BaseTemplate):
3937     def prepare(self,
3938                 escape_func=html_escape,
3939                 noescape=False,
3940                 syntax=None, **ka):
3941         self.cache = {}
3942         enc = self.encoding
3943         self._str = lambda x: touni(x, enc)
3944         self._escape = lambda x: escape_func(touni(x, enc))
3945         self.syntax = syntax
3946         if noescape:
3947             self._str, self._escape = self._escape, self._str
3948
3949     @cached_property
3950     def co(self):
3951         return compile(self.code, self.filename or '<string>', 'exec')
3952
3953     @cached_property
3954     def code(self):
3955         source = self.source
3956         if not source:
3957             with open(self.filename, 'rb') as f:
3958                 source = f.read()
3959         try:
3960             source, encoding = touni(source), 'utf8'
3961         except UnicodeError:
3962             raise depr(0, 11, 'Unsupported template encodings.', 'Use utf-8 for templates.')
3963         parser = StplParser(source, encoding=encoding, syntax=self.syntax)
3964         code = parser.translate()
3965         self.encoding = parser.encoding
3966         return code
3967
3968     def _rebase(self, _env, _name=None, **kwargs):
3969         _env['_rebase'] = (_name, kwargs)
3970
3971     def _include(self, _env, _name=None, **kwargs):
3972         env = _env.copy()
3973         env.update(kwargs)
3974         if _name not in self.cache:
3975             self.cache[_name] = self.__class__(name=_name, lookup=self.lookup, syntax=self.syntax)
3976         return self.cache[_name].execute(env['_stdout'], env)
3977
3978     def execute(self, _stdout, kwargs):
3979         env = self.defaults.copy()
3980         env.update(kwargs)
3981         env.update({
3982             '_stdout': _stdout,
3983             '_printlist': _stdout.extend,
3984             'include': functools.partial(self._include, env),
3985             'rebase': functools.partial(self._rebase, env),
3986             '_rebase': None,
3987             '_str': self._str,
3988             '_escape': self._escape,
3989             'get': env.get,
3990             'setdefault': env.setdefault,
3991             'defined': env.__contains__
3992         })
3993         exec(self.co, env)
3994         if env.get('_rebase'):
3995             subtpl, rargs = env.pop('_rebase')
3996             rargs['base'] = ''.join(_stdout)  #copy stdout
3997             del _stdout[:]  # clear stdout
3998             return self._include(env, subtpl, **rargs)
3999         return env
4000
4001     def render(self, *args, **kwargs):
4002         """ Render the template using keyword arguments as local variables. """
4003         env = {}
4004         stdout = []
4005         for dictarg in args:
4006             env.update(dictarg)
4007         env.update(kwargs)
4008         self.execute(stdout, env)
4009         return ''.join(stdout)
4010
4011
4012 class StplSyntaxError(TemplateError):
4013
4014     pass
4015
4016
4017 class StplParser(object):
4018     """ Parser for stpl templates. """
4019     _re_cache = {}  #: Cache for compiled re patterns
4020
4021     # This huge pile of voodoo magic splits python code into 8 different tokens.
4022     # We use the verbose (?x) regex mode to make this more manageable
4023
4024     _re_tok = _re_inl = r'''(
4025         [urbURB]*
4026         (?:  ''(?!')
4027             |""(?!")
4028             |'{6}
4029             |"{6}
4030             |'(?:[^\\']|\\.)+?'
4031             |"(?:[^\\"]|\\.)+?"
4032             |'{3}(?:[^\\]|\\.|\n)+?'{3}
4033             |"{3}(?:[^\\]|\\.|\n)+?"{3}
4034         )
4035     )'''
4036
4037     _re_inl = _re_tok.replace(r'|\n', '')  # We re-use this string pattern later
4038
4039     _re_tok += r'''
4040         # 2: Comments (until end of line, but not the newline itself)
4041         |(\#.*)
4042
4043         # 3: Open and close (4) grouping tokens
4044         |([\[\{\(])
4045         |([\]\}\)])
4046
4047         # 5,6: Keywords that start or continue a python block (only start of line)
4048         |^([\ \t]*(?:if|for|while|with|try|def|class)\b)
4049         |^([\ \t]*(?:elif|else|except|finally)\b)
4050
4051         # 7: Our special 'end' keyword (but only if it stands alone)
4052         |((?:^|;)[\ \t]*end[\ \t]*(?=(?:%(block_close)s[\ \t]*)?\r?$|;|\#))
4053
4054         # 8: A customizable end-of-code-block template token (only end of line)
4055         |(%(block_close)s[\ \t]*(?=\r?$))
4056
4057         # 9: And finally, a single newline. The 10th token is 'everything else'
4058         |(\r?\n)
4059     '''
4060
4061     # Match the start tokens of code areas in a template
4062     _re_split = r'''(?m)^[ \t]*(\\?)((%(line_start)s)|(%(block_start)s))'''
4063     # Match inline statements (may contain python strings)
4064     _re_inl = r'''%%(inline_start)s((?:%s|[^'"\n]+?)*?)%%(inline_end)s''' % _re_inl
4065
4066     # add the flag in front of the regexp to avoid Deprecation warning (see Issue #949)
4067     # verbose and dot-matches-newline mode
4068     _re_tok = '(?mx)' + _re_tok
4069     _re_inl = '(?mx)' + _re_inl
4070
4071
4072     default_syntax = '<% %> % {{ }}'
4073
4074     def __init__(self, source, syntax=None, encoding='utf8'):
4075         self.source, self.encoding = touni(source, encoding), encoding
4076         self.set_syntax(syntax or self.default_syntax)
4077         self.code_buffer, self.text_buffer = [], []
4078         self.lineno, self.offset = 1, 0
4079         self.indent, self.indent_mod = 0, 0
4080         self.paren_depth = 0
4081
4082     def get_syntax(self):
4083         """ Tokens as a space separated string (default: <% %> % {{ }}) """
4084         return self._syntax
4085
4086     def set_syntax(self, syntax):
4087         self._syntax = syntax
4088         self._tokens = syntax.split()
4089         if syntax not in self._re_cache:
4090             names = 'block_start block_close line_start inline_start inline_end'
4091             etokens = map(re.escape, self._tokens)
4092             pattern_vars = dict(zip(names.split(), etokens))
4093             patterns = (self._re_split, self._re_tok, self._re_inl)
4094             patterns = [re.compile(p % pattern_vars) for p in patterns]
4095             self._re_cache[syntax] = patterns
4096         self.re_split, self.re_tok, self.re_inl = self._re_cache[syntax]
4097
4098     syntax = property(get_syntax, set_syntax)
4099
4100     def translate(self):
4101         if self.offset: raise RuntimeError('Parser is a one time instance.')
4102         while True:
4103             m = self.re_split.search(self.source, pos=self.offset)
4104             if m:
4105                 text = self.source[self.offset:m.start()]
4106                 self.text_buffer.append(text)
4107                 self.offset = m.end()
4108                 if m.group(1):  # Escape syntax
4109                     line, sep, _ = self.source[self.offset:].partition('\n')
4110                     self.text_buffer.append(self.source[m.start():m.start(1)] +
4111                                             m.group(2) + line + sep)
4112                     self.offset += len(line + sep)
4113                     continue
4114                 self.flush_text()
4115                 self.offset += self.read_code(self.source[self.offset:],
4116                                               multiline=bool(m.group(4)))
4117             else:
4118                 break
4119         self.text_buffer.append(self.source[self.offset:])
4120         self.flush_text()
4121         return ''.join(self.code_buffer)
4122
4123     def read_code(self, pysource, multiline):
4124         code_line, comment = '', ''
4125         offset = 0
4126         while True:
4127             m = self.re_tok.search(pysource, pos=offset)
4128             if not m:
4129                 code_line += pysource[offset:]
4130                 offset = len(pysource)
4131                 self.write_code(code_line.strip(), comment)
4132                 break
4133             code_line += pysource[offset:m.start()]
4134             offset = m.end()
4135             _str, _com, _po, _pc, _blk1, _blk2, _end, _cend, _nl = m.groups()
4136             if self.paren_depth > 0 and (_blk1 or _blk2):  # a if b else c
4137                 code_line += _blk1 or _blk2
4138                 continue
4139             if _str:  # Python string
4140                 code_line += _str
4141             elif _com:  # Python comment (up to EOL)
4142                 comment = _com
4143                 if multiline and _com.strip().endswith(self._tokens[1]):
4144                     multiline = False  # Allow end-of-block in comments
4145             elif _po:  # open parenthesis
4146                 self.paren_depth += 1
4147                 code_line += _po
4148             elif _pc:  # close parenthesis
4149                 if self.paren_depth > 0:
4150                     # we could check for matching parentheses here, but it's
4151                     # easier to leave that to python - just check counts
4152                     self.paren_depth -= 1
4153                 code_line += _pc
4154             elif _blk1:  # Start-block keyword (if/for/while/def/try/...)
4155                 code_line, self.indent_mod = _blk1, -1
4156                 self.indent += 1
4157             elif _blk2:  # Continue-block keyword (else/elif/except/...)
4158                 code_line, self.indent_mod = _blk2, -1
4159             elif _end:  # The non-standard 'end'-keyword (ends a block)
4160                 self.indent -= 1
4161             elif _cend:  # The end-code-block template token (usually '%>')
4162                 if multiline: multiline = False
4163                 else: code_line += _cend
4164             else:  # \n
4165                 self.write_code(code_line.strip(), comment)
4166                 self.lineno += 1
4167                 code_line, comment, self.indent_mod = '', '', 0
4168                 if not multiline:
4169                     break
4170
4171         return offset
4172
4173     def flush_text(self):
4174         text = ''.join(self.text_buffer)
4175         del self.text_buffer[:]
4176         if not text: return
4177         parts, pos, nl = [], 0, '\\\n' + '  ' * self.indent
4178         for m in self.re_inl.finditer(text):
4179             prefix, pos = text[pos:m.start()], m.end()
4180             if prefix:
4181                 parts.append(nl.join(map(repr, prefix.splitlines(True))))
4182             if prefix.endswith('\n'): parts[-1] += nl
4183             parts.append(self.process_inline(m.group(1).strip()))
4184         if pos < len(text):
4185             prefix = text[pos:]
4186             lines = prefix.splitlines(True)
4187             if lines[-1].endswith('\\\\\n'): lines[-1] = lines[-1][:-3]
4188             elif lines[-1].endswith('\\\\\r\n'): lines[-1] = lines[-1][:-4]
4189             parts.append(nl.join(map(repr, lines)))
4190         code = '_printlist((%s,))' % ', '.join(parts)
4191         self.lineno += code.count('\n') + 1
4192         self.write_code(code)
4193
4194     @staticmethod
4195     def process_inline(chunk):
4196         if chunk[0] == '!': return '_str(%s)' % chunk[1:]
4197         return '_escape(%s)' % chunk
4198
4199     def write_code(self, line, comment=''):
4200         code = '  ' * (self.indent + self.indent_mod)
4201         code += line.lstrip() + comment + '\n'
4202         self.code_buffer.append(code)
4203
4204
4205 def template(*args, **kwargs):
4206     """
4207     Get a rendered template as a string iterator.
4208     You can use a name, a filename or a template string as first parameter.
4209     Template rendering arguments can be passed as dictionaries
4210     or directly (as keyword arguments).
4211     """
4212     tpl = args[0] if args else None
4213     for dictarg in args[1:]:
4214         kwargs.update(dictarg)
4215     adapter = kwargs.pop('template_adapter', SimpleTemplate)
4216     lookup = kwargs.pop('template_lookup', TEMPLATE_PATH)
4217     tplid = (id(lookup), tpl)
4218     if tplid not in TEMPLATES or DEBUG:
4219         settings = kwargs.pop('template_settings', {})
4220         if isinstance(tpl, adapter):
4221             TEMPLATES[tplid] = tpl
4222             if settings: TEMPLATES[tplid].prepare(**settings)
4223         elif "\n" in tpl or "{" in tpl or "%" in tpl or '$' in tpl:
4224             TEMPLATES[tplid] = adapter(source=tpl, lookup=lookup, **settings)
4225         else:
4226             TEMPLATES[tplid] = adapter(name=tpl, lookup=lookup, **settings)
4227     if not TEMPLATES[tplid]:
4228         abort(500, 'Template (%s) not found' % tpl)
4229     return TEMPLATES[tplid].render(kwargs)
4230
4231
4232 mako_template = functools.partial(template, template_adapter=MakoTemplate)
4233 cheetah_template = functools.partial(template,
4234                                      template_adapter=CheetahTemplate)
4235 jinja2_template = functools.partial(template, template_adapter=Jinja2Template)
4236
4237
4238 def view(tpl_name, **defaults):
4239     """ Decorator: renders a template for a handler.
4240         The handler can control its behavior like that:
4241
4242           - return a dict of template vars to fill out the template
4243           - return something other than a dict and the view decorator will not
4244             process the template, but return the handler result as is.
4245             This includes returning a HTTPResponse(dict) to get,
4246             for instance, JSON with autojson or other castfilters.
4247     """
4248
4249     def decorator(func):
4250
4251         @functools.wraps(func)
4252         def wrapper(*args, **kwargs):
4253             result = func(*args, **kwargs)
4254             if isinstance(result, (dict, DictMixin)):
4255                 tplvars = defaults.copy()
4256                 tplvars.update(result)
4257                 return template(tpl_name, **tplvars)
4258             elif result is None:
4259                 return template(tpl_name, defaults)
4260             return result
4261
4262         return wrapper
4263
4264     return decorator
4265
4266
4267 mako_view = functools.partial(view, template_adapter=MakoTemplate)
4268 cheetah_view = functools.partial(view, template_adapter=CheetahTemplate)
4269 jinja2_view = functools.partial(view, template_adapter=Jinja2Template)
4270
4271 ###############################################################################
4272 # Constants and Globals ########################################################
4273 ###############################################################################
4274
4275 TEMPLATE_PATH = ['./', './views/']
4276 TEMPLATES = {}
4277 DEBUG = False
4278 NORUN = False  # If set, run() does nothing. Used by load_app()
4279
4280 #: A dict to map HTTP status codes (e.g. 404) to phrases (e.g. 'Not Found')
4281 HTTP_CODES = httplib.responses.copy()
4282 HTTP_CODES[418] = "I'm a teapot"  # RFC 2324
4283 HTTP_CODES[428] = "Precondition Required"
4284 HTTP_CODES[429] = "Too Many Requests"
4285 HTTP_CODES[431] = "Request Header Fields Too Large"
4286 HTTP_CODES[451] = "Unavailable For Legal Reasons" # RFC 7725
4287 HTTP_CODES[511] = "Network Authentication Required"
4288 _HTTP_STATUS_LINES = dict((k, '%d %s' % (k, v))
4289                           for (k, v) in HTTP_CODES.items())
4290
4291 #: The default template used for error pages. Override with @error()
4292 ERROR_PAGE_TEMPLATE = """
4293 %%try:
4294     %%from %s import DEBUG, request
4295     <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
4296     <html>
4297         <head>
4298             <title>Error: {{e.status}}</title>
4299             <style type="text/css">
4300               html {background-color: #eee; font-family: sans-serif;}
4301               body {background-color: #fff; border: 1px solid #ddd;
4302                     padding: 15px; margin: 15px;}
4303               pre {background-color: #eee; border: 1px solid #ddd; padding: 5px;}
4304             </style>
4305         </head>
4306         <body>
4307             <h1>Error: {{e.status}}</h1>
4308             <p>Sorry, the requested URL <tt>{{repr(request.url)}}</tt>
4309                caused an error:</p>
4310             <pre>{{e.body}}</pre>
4311             %%if DEBUG and e.exception:
4312               <h2>Exception:</h2>
4313               %%try:
4314                 %%exc = repr(e.exception)
4315               %%except:
4316                 %%exc = '<unprintable %%s object>' %% type(e.exception).__name__
4317               %%end
4318               <pre>{{exc}}</pre>
4319             %%end
4320             %%if DEBUG and e.traceback:
4321               <h2>Traceback:</h2>
4322               <pre>{{e.traceback}}</pre>
4323             %%end
4324         </body>
4325     </html>
4326 %%except ImportError:
4327     <b>ImportError:</b> Could not generate the error page. Please add bottle to
4328     the import path.
4329 %%end
4330 """ % __name__
4331
4332 #: A thread-safe instance of :class:`LocalRequest`. If accessed from within a
4333 #: request callback, this instance always refers to the *current* request
4334 #: (even on a multi-threaded server).
4335 request = LocalRequest()
4336
4337 #: A thread-safe instance of :class:`LocalResponse`. It is used to change the
4338 #: HTTP response for the *current* request.
4339 response = LocalResponse()
4340
4341 #: A thread-safe namespace. Not used by Bottle.
4342 local = threading.local()
4343
4344 # Initialize app stack (create first empty Bottle app now deferred until needed)
4345 # BC: 0.6.4 and needed for run()
4346 apps = app = default_app = AppStack()
4347
4348 #: A virtual package that redirects import statements.
4349 #: Example: ``import bottle.ext.sqlite`` actually imports `bottle_sqlite`.
4350 ext = _ImportRedirect('bottle.ext' if __name__ == '__main__' else
4351                       __name__ + ".ext", 'bottle_%s').module
4352
4353
4354 def _main(argv):  # pragma: no coverage
4355     args, parser = _cli_parse(argv)
4356
4357     def _cli_error(cli_msg):
4358         parser.print_help()
4359         _stderr('\nError: %s\n' % cli_msg)
4360         sys.exit(1)
4361
4362     if args.version:
4363         _stdout('Bottle %s\n' % __version__)
4364         sys.exit(0)
4365     if not args.app:
4366         _cli_error("No application entry point specified.")
4367
4368     sys.path.insert(0, '.')
4369     sys.modules.setdefault('bottle', sys.modules['__main__'])
4370
4371     host, port = (args.bind or 'localhost'), 8080
4372     if ':' in host and host.rfind(']') < host.rfind(':'):
4373         host, port = host.rsplit(':', 1)
4374     host = host.strip('[]')
4375
4376     config = ConfigDict()
4377
4378     for cfile in args.conf or []:
4379         try:
4380             if cfile.endswith('.json'):
4381                 with open(cfile, 'rb') as fp:
4382                     config.load_dict(json_loads(fp.read()))
4383             else:
4384                 config.load_config(cfile)
4385         except configparser.Error as parse_error:
4386             _cli_error(parse_error)
4387         except IOError:
4388             _cli_error("Unable to read config file %r" % cfile)
4389         except (UnicodeError, TypeError, ValueError) as error:
4390             _cli_error("Unable to parse config file %r: %s" % (cfile, error))
4391
4392     for cval in args.param or []:
4393         if '=' in cval:
4394             config.update((cval.split('=', 1),))
4395         else:
4396             config[cval] = True
4397
4398     run(args.app,
4399         host=host,
4400         port=int(port),
4401         server=args.server,
4402         reloader=args.reload,
4403         plugins=args.plugin,
4404         debug=args.debug,
4405         config=config)
4406
4407
4408 if __name__ == '__main__':  # pragma: no coverage
4409     _main(sys.argv)