inject_user_key routine fixes
[osm/RO.git] / osm_ro / http_tools / handler.py
1 # -*- coding: utf-8 -*-
2 ##
3 # Copyright 2018 University of Bristol - High Performance Networks Research
4 # Group
5 # All Rights Reserved.
6 #
7 # Contributors: Anderson Bravalheri, Dimitrios Gkounis, Abubakar Siddique
8 # Muqaddas, Navdeep Uniyal, Reza Nejabati and Dimitra Simeonidou
9 #
10 # Licensed under the Apache License, Version 2.0 (the "License"); you may
11 # not use this file except in compliance with the License. You may obtain
12 # a copy of the License at
13 #
14 # http://www.apache.org/licenses/LICENSE-2.0
15 #
16 # Unless required by applicable law or agreed to in writing, software
17 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
18 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
19 # License for the specific language governing permissions and limitations
20 # under the License.
21 #
22 # For those usages not covered by the Apache License, Version 2.0 please
23 # contact with: <highperformance-networks@bristol.ac.uk>
24 #
25 # Neither the name of the University of Bristol nor the names of its
26 # contributors may be used to endorse or promote products derived from
27 # this software without specific prior written permission.
28 #
29 # This work has been performed in the context of DCMS UK 5G Testbeds
30 # & Trials Programme and in the framework of the Metro-Haul project -
31 # funded by the European Commission under Grant number 761727 through the
32 # Horizon 2020 and 5G-PPP programmes.
33 ##
34
35 from types import MethodType
36
37 from bottle import Bottle
38
39
40 class route(object):
41 """Decorator that stores route information, so creating the routes can be
42 postponed.
43
44 This allows methods (OOP) with bottle.
45
46 Arguments:
47 method: HTTP verb (e.g. ``'get'``, ``'post'``, ``'put'``, ...)
48 path: URL path that will be handled by the callback
49 """
50 def __init__(self, method, path, **kwargs):
51 kwargs['method'] = method.upper()
52 self.route_info = (path, kwargs)
53
54 def __call__(self, function):
55 function.route_info = self.route_info
56 return function
57
58
59 class BaseHandler(object):
60 """Base class that allows isolated webapp implementation using Bottle,
61 when used in conjunction with the ``route`` decorator.
62
63 In this context, a ``Handler`` is meant to be a collection of Bottle
64 routes/callbacks related to a specific topic.
65
66 A ``Handler`` instance can produce a WSGI app that can be mounted or merged
67 inside another more general bottle app.
68
69 Example:
70
71 from http_tools.handler import Handler, route
72 from http_tools.errors import ErrorHandler
73
74 class MyHandler(Handler):
75 plugins = [ErrorHandler()]
76 url_base = '/my/url/base'
77
78 @route('GET', '/some/path/<var>')
79 def get_var(self, var):
80 return var
81
82 app = MyHandler.wsgi_app
83 # ^ Webapp with a `GET /my/url/base/some/path/<var>` route
84 """
85 _wsgi_app = None
86
87 url_base = ''
88 """String representing a path fragment to be prepended to the routes"""
89
90 plugins = []
91 """Bottle plugins to be installed when creating the WSGI app"""
92
93 @property
94 def wsgi_app(self):
95 """Create a WSGI app based on the implemented callbacks"""
96
97 if self._wsgi_app:
98 # Return if cached
99 return self._wsgi_app
100
101 app = Bottle()
102
103 members = (getattr(self, m) for m in dir(self) if m != 'wsgi_app')
104 callbacks = (m for m in members
105 if isinstance(m, MethodType) and hasattr(m, 'route_info'))
106
107 for callback in callbacks:
108 path, kwargs = callback.route_info
109 kwargs.update(callback=callback, apply=self.plugins)
110 app.route(self.url_base + path, **kwargs)
111
112 self._wsgi_app = app
113
114 return app