Ejemplo n.º 1
0
    def __init__(self, **kwargs):
        #: A :class:`ConfigDict` for app specific configuration.
        self.config = self._global_config._make_overlay()
        self.config._add_change_listener(
            functools.partial(self.trigger_hook, 'config'))

        self.config.update({
            "catchall": True
        })

        if kwargs.get('catchall') is False:
            depr(0, 13, "Bottle(catchall) keyword argument.",
                        "The 'catchall' setting is now part of the app "
                        "configuration. Fix: `app.config['catchall'] = False`")
            self.config['catchall'] = False
        if kwargs.get('autojson') is False:
            depr(0, 13, "Bottle(autojson) keyword argument.",
                 "The 'autojson' setting is now part of the app "
                 "configuration. Fix: `app.config['json.enable'] = False`")
            self.config['json.disable'] = True

        self._mounts = []

        #: A :class:`ResourceManager` for application files
        self.resources = ResourceManager()

        self.routes = []  # List of installed :class:`Route` instances.
        self.router = Router()  # Maps requests to :class:`Route` instances.
        self.error_handler = {}

        # Core plugins
        self.plugins = []  # List of installed plugins.
        self.install(JSONPlugin())
        self.install(TemplatePlugin())
Ejemplo n.º 2
0
 def get_config(self, key, default=None):
     """ Lookup a config field and return its value, first checking the
         route.config, then route.app.config."""
     depr(0, 13, "Route.get_config() is deprectated.",
                 "The Route.config property already includes values from the"
                 " application config for missing keys. Access it directly.")
     return self.config.get(key, default)
Ejemplo n.º 3
0
def cookie_encode(data, key, digestmod=None):
    """ Encode and sign a pickle-able object. Return a (byte) string """
    depr(0, 13, "cookie_encode() will be removed soon.",
                "Do not use this API directly.")
    digestmod = digestmod or hashlib.sha256
    msg = base64.b64encode(pickle.dumps(data, -1))
    sig = base64.b64encode(hmac.new(bytes(key), msg, digestmod=digestmod).digest())
    return bytes('!') + sig + bytes('?') + msg
Ejemplo n.º 4
0
def cookie_decode(data, key, digestmod=None):
    """ Verify and decode an encoded string. Return an object or None."""
    depr(0, 13, "cookie_decode() will be removed soon.",
                "Do not use this API directly.")
    data = bytes(data)
    if cookie_is_encoded(data):
        sig, msg = data.split(bytes('?'), 1)
        digestmod = digestmod or hashlib.sha256
        hashed = hmac.new(bytes(key), msg, digestmod=digestmod).digest()
        if _lscmp(sig[1:], base64.b64encode(hashed)):
            return pickle.loads(base64.b64decode(msg))
    return None
Ejemplo n.º 5
0
    def _handle(self, environ):
        path = environ['bottle.raw_path'] = environ['PATH_INFO']
        environ['PATH_INFO'] = path.encode('latin1').decode('utf8', 'ignore')

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

        try:
            while True: # Remove in 0.14 together with RouteReset
                out = None
                try:
                    self.trigger_hook('before_request')
                    route, args = self.router.match(environ)
                    environ['route.handle'] = route
                    environ['bottle.route'] = route
                    environ['route.url_args'] = args
                    out = route.call(**args)
                    break
                except HTTPResponse as E:
                    out = E
                    break
                except RouteReset:
                    depr(0, 13, "RouteReset exception deprecated",
                                "Call route.call() after route.reset() and "
                                "return the result.")
                    route.reset()
                    continue
                finally:
                    if isinstance(out, HTTPResponse):
                        out.apply(response)
                    try:
                        self.trigger_hook('after_request')
                    except HTTPResponse as E:
                        out = E
                        out.apply(response)
        except (KeyboardInterrupt, SystemExit, MemoryError):
            raise
        except Exception as E:
            if not self.catchall: raise
            stacktrace = format_exc()
            environ['wsgi.errors'].write(stacktrace)
            environ['wsgi.errors'].flush()
            out = HTTPError(500, "Internal Server Error", E, stacktrace)
            out.apply(response)

        return out
Ejemplo n.º 6
0
    def search(cls, name, lookup=None):
        """ Search name in all directories specified in lookup.
        First without, then with common extensions. Return first hit. """
        if not lookup:
            raise depr(0, 12, "Empty template lookup path.", "Configure a template lookup path.")

        if os.path.isabs(name):
            raise depr(0, 12, "Use of absolute path for template name.",
                       "Refer to templates with names or paths relative to the lookup path.")

        for spath in lookup:
            spath = os.path.abspath(spath) + os.sep
            fname = os.path.abspath(os.path.join(spath, name))
            if not fname.startswith(spath): continue
            if os.path.isfile(fname): return fname
            for ext in cls.extensions:
                if os.path.isfile('%s.%s' % (fname, ext)):
                    return '%s.%s' % (fname, ext)
Ejemplo n.º 7
0
 def _itertokens(self, rule):
     offset, prefix = 0, ''
     for match in self.rule_syntax.finditer(rule):
         prefix += rule[offset:match.start()]
         g = match.groups()
         if g[2] is not None:
             depr(0, 13, "Use of old route syntax.",
                         "Use <name> instead of :name in routes.")
         if len(g[0]) % 2:  # Escaped wildcard
             prefix += match.group(0)[len(g[0]):]
             offset = match.end()
             continue
         if prefix:
             yield prefix, None, None
         name, filtr, conf = g[4:7] if g[2] is None else g[1:4]
         yield name, filtr or 'default', conf or None
         offset, prefix = match.end(), ''
     if offset <= len(rule) or prefix:
         yield prefix + rule[offset:], None, None
Ejemplo n.º 8
0
 def code(self):
     source = self.source
     if not source:
         with open(self.filename, 'rb') as f:
             source = f.read()
     try:
         source, encoding = to_str(source), 'utf8'
     except UnicodeError:
         raise depr(0, 11, 'Unsupported template encodings.', 'Use utf-8 for templates.')
     parser = StplParser(source, encoding=encoding, syntax=self.syntax)
     code = parser.translate()
     self.encoding = parser.encoding
     return code
Ejemplo n.º 9
0
    def _mount_app(self, prefix, app, **options):
        if app in self._mounts or '_mount.app' in app.config:
            depr(0, 13, "Application mounted multiple times. Falling back to WSGI mount.",
                 "Clone application before mounting to a different location.")
            return self._mount_wsgi(prefix, app, **options)

        if options:
            depr(0, 13, "Unsupported mount options. Falling back to WSGI mount.",
                 "Do not specify any route options when mounting bottle application.")
            return self._mount_wsgi(prefix, app, **options)

        if not prefix.endswith("/"):
            depr(0, 13, "Prefix must end in '/'. Falling back to WSGI mount.",
                 "Consider adding an explicit redirect from '/prefix' to '/prefix/' in the parent application.")
            return self._mount_wsgi(prefix, app, **options)

        self._mounts.append(app)
        app.config['_mount.prefix'] = prefix
        app.config['_mount.app'] = self
        for route in app.routes:
            route.rule = prefix + route.rule.lstrip('/')
            self.add_route(route)
Ejemplo n.º 10
0
 def _environ(self):
     utils.depr("Request._environ renamed to Request.environ")
     return self.environ
Ejemplo n.º 11
0
 def header(self):
     utils.depr(
         "The Request.header property was renamed to Request.headers")
     return self.headers
Ejemplo n.º 12
0
 def header(self):
     utils.depr("Response.header renamed to Response.headers")
     return self.headers
Ejemplo n.º 13
0
    def set_cookie(self, name, value, secret=None, digestmod=hashlib.sha256, **options):
        """ Create a new cookie or replace an old one. If the `secret` parameter is
            set, create a `Signed Cookie` (described below).
            :param name: the name of the cookie.
            :param value: the value of the cookie.
            :param secret: a signature key required for signed cookies.
            Additionally, this method accepts all RFC 2109 attributes that are
            supported by :class:`cookie.Morsel`, including:
            :param max_age: maximum age in seconds. (default: None)
            :param expires: a datetime object or UNIX timestamp. (default: None)
            :param domain: the domain that is allowed to read the cookie.
              (default: current domain)
            :param path: limits the cookie to a given path (default: current path)
            :param secure: limit the cookie to HTTPS connections (default: off).
            :param httponly: prevents client-side javascript to read this cookie
              (default: off, requires Python 2.6 or newer).
            :param same_site: disables third-party use for a cookie.
              Allowed attributes: `lax` and `strict`.
              In strict mode the cookie will never be sent.
              In lax mode the cookie is only sent with a top-level GET request.
            If neither `expires` nor `max_age` is set (default), the cookie will
            expire at the end of the browser session (as soon as the browser
            window is closed).
            Signed cookies may store any pickle-able object and are
            cryptographically signed to prevent manipulation. Keep in mind that
            cookies are limited to 4kb in most browsers.
            Warning: Pickle is a potentially dangerous format. If an attacker
            gains access to the secret key, he could forge cookies that execute
            code on server side if unpickeld. Using pickle is discouraged and
            support for it will be removed in later versions of bottle.
            Warning: Signed cookies are not encrypted (the client can still see
            the content) and not copy-protected (the client can restore an old
            cookie). The main intention is to make pickling and unpickling
            save, not to store secret information at client side.
        """
        if not self._cookies:
            self._cookies = SimpleCookie()

        # To add "SameSite" cookie support.
        Morsel._reserved['same-site'] = 'SameSite'

        if secret:
            if not isinstance(value, str):
                depr(0, 13, "Pickling of arbitrary objects into cookies is "
                            "deprecated.", "Only store strings in cookies. "
                            "JSON strings are fine, too.")
            encoded = base64.b64encode(pickle.dumps([name, value], -1))
            sig = base64.b64encode(hmac.new(bytes(secret), encoded,
                                            digestmod=digestmod).digest())
            value = str(bytes('!') + sig + bytes('?') + encoded)
        elif not isinstance(value, str):
            raise TypeError('Secret key required for non-string cookies.')

        # Cookie size plus options must not exceed 4kb.
        if len(name) + len(value) > 3800:
            raise ValueError('Content does not fit into a cookie.')

        self._cookies[name] = value

        for key, value in options.items():
            if key == 'max_age':
                if isinstance(value, timedelta):
                    value = value.seconds + value.days * 24 * 3600
            if key == 'expires':
                if isinstance(value, (datedate, datetime)):
                    value = value.timetuple()
                elif isinstance(value, (int, float)):
                    value = time.gmtime(value)
                value = time.strftime("%a, %d %b %Y %H:%M:%S GMT", value)
            # check values for SameSite cookie, because it's not natively supported by http.cookies.
            if key == 'same_site' and value.lower() not in ('lax', 'strict'):
                raise CookieError("Invalid attribute %r" % (key,))
            if key in ('secure', 'httponly') and not value:
                continue
            self._cookies[name][key.replace('_', '-')] = value
Ejemplo n.º 14
0
def cookie_is_encoded(data):
    """ Return True if the argument looks like a encoded cookie."""
    depr(0, 13, "cookie_is_encoded() will be removed soon.",
                "Do not use this API directly.")
    return bool(data.startswith(bytes('!')) and bytes('?') in data)
Ejemplo n.º 15
0
 def header(self):
     utils.depr("The Request.header property was renamed to Request.headers")
     return self.headers
Ejemplo n.º 16
0
 def header(self):
     utils.depr("Response.header renamed to Response.headers")
     return self.headers
Ejemplo n.º 17
0
 def _environ(self):
     utils.depr("Request._environ renamed to Request.environ")
     return self.environ