source: package_branches/invirt-web/cherrypy/code/view.py @ 2486

Last change on this file since 2486 was 2485, checked in by quentin, 15 years ago

Full error handling

File size: 5.4 KB
Line 
1import os, sys
2
3import cherrypy
4from mako.template import Template
5from mako.lookup import TemplateLookup
6import simplejson
7import datetime, decimal
8from StringIO import StringIO
9from invirt.config import structs as config
10from webcommon import State
11
12class MakoHandler(cherrypy.dispatch.LateParamPageHandler):
13    """Callable which sets response.body."""
14   
15    def __init__(self, template, next_handler, content_type='text/html; charset=utf-8'):
16        self.template = template
17        self.next_handler = next_handler
18        self.content_type = content_type
19   
20    def __call__(self):
21        env = globals().copy()
22        env.update(self.next_handler())
23        cherrypy.response.headers['Content-Type'] = self.content_type
24        return self.template.render(**env)
25       
26
27class MakoLoader(object):
28   
29    def __init__(self):
30        self.lookups = {}
31
32    def get_lookup(self, directories, module_directory=None,
33                     collection_size=-1, imports=[], **kwargs):
34        # Find the appropriate template lookup.
35        key = (tuple(directories), module_directory)
36        try:
37            lookup = self.lookups[key]
38        except KeyError:
39            lookup = TemplateLookup(directories=directories,
40                                    module_directory=module_directory,
41                                    collection_size=collection_size,
42                                    default_filters=['decode.utf8'],
43                                    input_encoding='utf-8',
44                                    output_encoding='utf-8',
45                                    imports=imports,
46                                    )
47            self.lookups[key] = lookup
48        return lookup
49
50    def __call__(self, filename, directories, module_directory=None,
51                 collection_size=-1, content_type='text/html; charset=utf-8',
52                 imports=[]):
53        cherrypy.request.lookup = lookup = self.get_lookup(directories, module_directory,
54                                                           collection_size, imports)
55       
56        # Replace the current handler.
57        cherrypy.request.template = t = lookup.get_template(filename)
58        cherrypy.request.handler = MakoHandler(t, cherrypy.request.handler, content_type)
59
60main = MakoLoader()
61cherrypy.tools.mako = cherrypy.Tool('on_start_resource', main)
62
63def revertStandardError():
64    """Move stderr to stdout, and return the contents of the old stderr."""
65    errio = sys.stderr
66    if not isinstance(errio, StringIO):
67        return ''
68    sys.stderr = sys.stdout
69    errio.seek(0)
70    return errio.read()
71
72def catchStderr():
73    old_handler = cherrypy.request.handler
74    def wrapper(*args, **kwargs):
75        sys.stderr = StringIO()
76        ret = old_handler(*args, **kwargs)
77        e = revertStandardError()
78        if e:
79            if isinstance(ret, dict):
80                ret["error_text"] = e
81        return ret
82    if old_handler:
83        cherrypy.request.handler = wrapper
84
85cherrypy.tools.catch_stderr = cherrypy.Tool('before_handler', catchStderr)
86
87class JSONEncoder(simplejson.JSONEncoder):
88        def default(self, obj):
89                if isinstance(obj, datetime.datetime):
90                        return str(obj)
91                elif isinstance(obj, decimal.Decimal):
92                        return float(obj)
93                else:
94                        return simplejson.JSONEncoder.default(self, obj)
95
96def jsonify_tool_callback(*args, **kwargs):
97    if not cherrypy.request.cached:
98        response = cherrypy.response
99        response.headers['Content-Type'] = 'text/javascript'
100        response.body = JSONEncoder().iterencode(response.body)
101
102cherrypy.tools.jsonify = cherrypy.Tool('before_finalize', jsonify_tool_callback, priority=30)
103
104def external_remote_user_login():
105    pass
106
107def require_login():
108    """If the user isn't logged in, raise 403 with an error."""
109    if cherrypy.request.login is False:
110        raise cherrypy.HTTPError(403,
111            "You are not authorized to access that resource")
112
113cherrypy.tools.require_login = cherrypy.Tool('on_start_resource', require_login, priority=150)
114
115def require_POST():
116    """If the request isn't a POST request, raise 405 Method Not Allowed"""
117    if cherrypy.request.method != "POST":
118        raise cherrypy.HTTPError(405,
119                                 "You must submit this request with POST")
120
121cherrypy.tools.require_POST = cherrypy.Tool('on_start_resource', require_POST, priority=150)
122
123def remote_user_login():
124    """Get the current user based on the SSL or GSSAPI environment variables"""
125    environ = cherrypy.request.wsgi_environ
126    user = environ.get('REMOTE_USER')
127    if user is None:
128        return
129    else:
130        cherrypy.request.login = None # clear what cherrypy put there
131
132    if environ.get('AUTH_TYPE') == 'Negotiate':
133        # Convert the krb5 principal into a krb4 username
134        if not user.endswith('@%s' % config.kerberos.realm):
135            cherrypy.request.login = False # failed to login
136        else:
137            cherrypy.request.login = user.split('@')[0].replace('/', '.')
138    else:
139        cherrypy.request.login = user
140
141cherrypy.tools.remote_user_login = cherrypy.Tool('on_start_resource', remote_user_login, priority=50)
142
143def invirtwebstate_init():
144    """Initialize the cherrypy.request.state object from Invirt"""
145    if not hasattr(cherrypy.request, "state"):
146        cherrypy.request.state = State(cherrypy.request.login)
147
148cherrypy.tools.invirtwebstate = cherrypy.Tool('on_start_resource', invirtwebstate_init, priority=100)
149
150class View(object):
151    _cp_config = {'tools.mako.directories': [os.path.join(os.path.dirname(__file__),'templates')]}
Note: See TracBrowser for help on using the repository browser.