import os, sys import cherrypy from mako.template import Template from mako.lookup import TemplateLookup import simplejson import datetime, decimal from StringIO import StringIO from invirt.config import structs as config from webcommon import State class MakoHandler(cherrypy.dispatch.LateParamPageHandler): """Callable which processes a dictionary, returning the rendered body.""" def __init__(self, template, next_handler, content_type='text/html; charset=utf-8'): self.template = template self.next_handler = next_handler self.content_type = content_type def __call__(self): env = globals().copy() env.update(self.next_handler()) cherrypy.response.headers['Content-Type'] = self.content_type return self.template.render(**env) class MakoLoader(object): def __init__(self): self.lookups = {} def get_lookup(self, directories, module_directory=None, collection_size=-1, imports=[], **kwargs): # Find the appropriate template lookup. key = (tuple(directories), module_directory) try: lookup = self.lookups[key] except KeyError: lookup = TemplateLookup(directories=directories, module_directory=module_directory, collection_size=collection_size, default_filters=['decode.utf8'], input_encoding='utf-8', output_encoding='utf-8', imports=imports, ) self.lookups[key] = lookup return lookup def __call__(self, filename, directories, module_directory=None, collection_size=-1, content_type='text/html; charset=utf-8', imports=[]): cherrypy.request.lookup = lookup = self.get_lookup(directories, module_directory, collection_size, imports) cherrypy.request.template = t = lookup.get_template(filename) cherrypy.request.handler = MakoHandler(t, cherrypy.request.handler, content_type) cherrypy.tools.mako = cherrypy.Tool('on_start_resource', MakoLoader()) def revertStandardError(): """Move stderr to stdout, and return the contents of the old stderr.""" errio = sys.stderr if not isinstance(errio, StringIO): return '' sys.stderr = sys.stdout errio.seek(0) return errio.read() def catchStderr(): old_handler = cherrypy.request.handler def wrapper(*args, **kwargs): sys.stderr = StringIO() ret = old_handler(*args, **kwargs) e = revertStandardError() if e: if isinstance(ret, dict): ret["error_text"] = e return ret if old_handler: cherrypy.request.handler = wrapper cherrypy.tools.catch_stderr = cherrypy.Tool('before_handler', catchStderr) class JSONEncoder(simplejson.JSONEncoder): def default(self, obj): if isinstance(obj, datetime.datetime): return str(obj) elif isinstance(obj, decimal.Decimal): return float(obj) else: return simplejson.JSONEncoder.default(self, obj) def jsonify_tool_callback(*args, **kwargs): if not cherrypy.request.cached: response = cherrypy.response response.headers['Content-Type'] = 'text/javascript' response.body = JSONEncoder().iterencode(response.body) cherrypy.tools.jsonify = cherrypy.Tool('before_finalize', jsonify_tool_callback, priority=30) def require_login(): """If the user isn't logged in, raise 403 with an error.""" if cherrypy.request.login is False: raise cherrypy.HTTPError(403, "You are not authorized to access that resource") cherrypy.tools.require_login = cherrypy.Tool('on_start_resource', require_login, priority=150) def require_POST(): """If the request isn't a POST request, raise 405 Method Not Allowed""" if cherrypy.request.method != "POST": raise cherrypy.HTTPError(405, "You must submit this request with POST") cherrypy.tools.require_POST = cherrypy.Tool('on_start_resource', require_POST, priority=150) def remote_user_login(): """Get the current user based on the SSL or GSSAPI environment variables and store it in the request object's login variable. This conforms to the CherryPy API: http://www.cherrypy.org/wiki/RequestObject#login If the user is logged in successfully, cherrypy.request.login is set to the username. If the user failed to log in, cherrypy.request.login is set to False. If the user did not attempt authentication, cherrypy.request.login is set to None.""" environ = cherrypy.request.wsgi_environ user = environ.get('REMOTE_USER') if user is None: return else: cherrypy.request.login = None # clear what cherrypy put there if environ.get('AUTH_TYPE') == 'Negotiate': # Convert the krb5 principal into a krb4 username if not user.endswith('@%s' % config.kerberos.realm): cherrypy.request.login = False # failed to login else: cherrypy.request.login = user.split('@')[0].replace('/', '.') else: cherrypy.request.login = user cherrypy.tools.remote_user_login = cherrypy.Tool('on_start_resource', remote_user_login, priority=50) def invirtwebstate_init(): """Initialize the cherrypy.request.state object from Invirt""" if not hasattr(cherrypy.request, "state"): cherrypy.request.state = State(cherrypy.request.login) cherrypy.tools.invirtwebstate = cherrypy.Tool('on_start_resource', invirtwebstate_init, priority=100) class View(object): _cp_config = {'tools.mako.directories': [os.path.join(os.path.dirname(__file__),'templates')]}