""" * ==================================================================== * Copyright (c) 2001 Jon Travis. All rights reserved. * See the file COPYING for information on usage and redistribution. * ==================================================================== """ import mod_snake import os import string import sys import traceback _myname = "SnakeSimple" # Hook orientation constants _FIRST = 0 _ALL = 1 _VOID = 2 def _format_exception(depth): etype, value, tb = sys.exc_info() tback = traceback.format_exception(etype, value, tb, None)[depth:] return string.rstrip(string.join(tback,'')) class SimpleObject: def __init__(self, module_name): self.module_name = module_name self.mtime = 0 self.module = None def get_module_mtime(self): if not self.module: return 0 real_file = file = self.module.__file__ if file[-4:] == '.pyc': # Try to see if this came from a .py real_file = file[:-1] try: statinfo = os.stat(real_file) return statinfo[-2] except: real_file = file return os.stat(real_file)[-2] def is_outdated(self): if self.mtime != self.get_module_mtime(): return 1 def load(self): try: if self.module: self.module = reload(self.module) else: self.module = __import__(self.module_name, None, None, None) self.mtime = self.get_module_mtime() return None except: self.mtime = -1 # Ensures outdatedness return _format_exception(2) def handler(self, handle): if self.module.__dict__.has_key(handle): return self.module.__dict__[handle] return None def run_conn_rec(self, server_vars, handler_name, conn_rec): if not self.module or self.mtime <= 0: return mod_snake.HTTP_INTERNAL_SERVER_ERROR else: return self.module.__dict__[handler_name](server_vars, conn_rec) def run_request_rec(self, server_vars, handler_name, per_dir, request_rec): if not self.module or self.mtime <= 0: return mod_snake.HTTP_INTERNAL_SERVER_ERROR else: return self.module.__dict__[handler_name](per_dir, server_vars, request_rec) class SnakeSimple: "A Python module for easy creation and invocation of Python handlers" def handler_check(self, handler_name): res = string.split(handler_name, '.') if len(res) != 2: return None return res def _handler_loader(self, per_dir, per_svr, hook_name, handler_name): "a module.handler name to call" x = self.handler_check(handler_name) if not x: return "Snake%s: bogus handler name '%s'" % (hook_name, handler_name) if not per_svr['modules'].has_key(x[0]): newmod = SimpleObject(x[0]) err = newmod.load() if err: return "Could not load Snake%s %s:\n%s" % (hook_name, handler_name, err) per_svr['modules'][x[0]] = newmod if not per_dir or not per_dir['directory']: handlers = per_svr['handlers'] else: handlers = per_dir handlers[hook_name].append((x[0], x[1])) def _generic_handler(self, per_dir, per_svr, handler_func, handler_obj, hook_type, hook_name): if not per_dir: handlers = per_svr['handlers'][hook_name] else: if per_svr['handlers'].has_key(hook_name): handlers = per_dir[hook_name] + per_svr['handlers'][hook_name] else: handlers = per_dir[hook_name] # On pre_connection, try to reload if we need to if hook_name == 'PreConnection': for module in per_svr['modules'].values(): if module.is_outdated(): err = module.load() if err: mod_snake.ap_log_error(mod_snake.APLOG_CRIT, per_svr['server'], err) if hook_type != _VOID: return mod_snake.HTTP_INTERNAL_SERVER_ERROR for modulename, handlename in handlers: module = per_svr['modules'][modulename] if not module.handler(handlename): mod_snake.ap_log_error(mod_snake.APLOG_CRIT, per_svr['server'], 'Snake%s: %s has no handler named "%s"' % ( hook_name, modulename, handlename)) if hook_type == _VOID: continue else: return mod_snake.HTTP_INTERNAL_SERVER_ERROR try: if per_dir: dir_vars = per_dir['vars'] else: dir_vars = {} if hook_name in ('PreConnection', 'ProcessConnection'): resval = handler_func(module, per_svr['vars'], handlename, handler_obj) else: resval = handler_func(module, per_svr['vars'], handlename, dir_vars, handler_obj) except: err = _format_exception(3) mod_snake.ap_log_error(mod_snake.APLOG_CRIT, per_svr['server'], 'Snake%s: Error\n%s' % (hook_name, err)) if hook_type == _VOID: continue else: return mod_snake.HTTP_INTERNAL_SERVER_ERROR if type(resval) != type(0): mod_snake.ap_log_error(mod_snake.APLOG_CRIT, per_svr['server'], 'Snake%s: %s handler returned non-int'%( hook_name, modulename + '.' + handlename)) if hook_type == _VOID: continue else: return mod_snake.HTTP_INTERNAL_SERVER_ERROR if hook_type == _ALL and not resval in (mod_snake.OK, mod_snake.DECLINED): return resval elif hook_type == _FIRST and resval != mod_snake.DECLINED: return resval return mod_snake.DECLINED def cmd_SnakePreConnection(self, per_dir, per_svr, handler_name): "a module.handler pair" return self._handler_loader(per_dir, per_svr, 'PreConnection', handler_name) def cmd_SnakeProcessConnection(self, per_dir, per_svr, handler_name): "a module.handler pair" return self._handler_loader(per_dir, per_svr, 'ProcessConnection', handler_name) def cmd_SnakePostReadRequest(self, per_dir, per_svr, handler_name): "a module.handler pair" return self._handler_loader(per_dir, per_svr, 'PostReadRequest', handler_name) def cmd_SnakeTranslateName(self, per_dir, per_svr, handler_name): "a module.handler pair" return self._handler_loader(per_dir, per_svr, 'TranslateName', handler_name) def cmd_SnakeHeaderParser(self, per_dir, per_svr, handler_name): "a module.handler pair" return self._handler_loader(per_dir, per_svr, 'HeaderParser', handler_name) def cmd_SnakeAccessChecker(self, per_dir, per_svr, handler_name): "a module.handler pair" return self._handler_loader(per_dir, per_svr, 'AccessChecker', handler_name) def cmd_SnakeCheckUserId(self, per_dir, per_svr, handler_name): "a module.handler pair" return self._handler_loader(per_dir, per_svr, 'CheckUserId', handler_name) def cmd_SnakeAuthChecker(self, per_dir, per_svr, handler_name): "a module.handler pair" return self._handler_loader(per_dir, per_svr, 'AuthChecker', handler_name) def cmd_SnakeTypeChecker(self, per_dir, per_svr, handler_name): "a module.handler pair" return self._handler_loader(per_dir, per_svr, 'TypeChecker', handler_name) def cmd_SnakeFixups(self, per_dir, per_svr, handler_name): "a module.handler pair" return self._handler_loader(per_dir, per_svr, 'Fixups', handler_name) def cmd_SnakeLogTransaction(self, per_dir, per_svr, handler_name): "a module.handler pair" return self._handler_loader(per_dir, per_svr, 'LogTransaction', handler_name) def cmd_SnakeContentHandler(self, per_dir, per_svr, handler_name): "a module.handler pair" return self._handler_loader(per_dir, per_svr, 'ContentHandler', handler_name) def cmd_SnakeVarSet(self, per_dir, per_svr, key, val): "a key value pair" if not per_dir: per_svr['vars'][key] = val else: per_dir['vars'][key] = val def create_svr_config(self, svr): return { 'server' : svr, 'modules' : {}, 'handlers' : { 'PreConnection' : [], 'ProcessConnection' : [], 'PostReadRequest' : [], 'TranslateName' : [], 'HeaderParser' : [], 'AccessChecker' : [], 'CheckUserId' : [], 'AuthChecker' : [], 'TypeChecker' : [], 'Fixups' : [], 'LogTransaction' : [], 'ContentHandler' : [] }, 'vars' : {} } def create_dir_config(self, path): return { 'HeaderParser' : [], 'CheckUserId' : [], 'AuthChecker' : [], 'AccessChecker' : [], 'TypeChecker' : [], 'Fixups' : [], 'LogTransaction' : [], 'ContentHandler' : [], 'directory' : path, 'vars' : {}, } def pre_connection(self, per_svr, conn_rec): return self._generic_handler(None, per_svr, SimpleObject.run_conn_rec, conn_rec, _ALL, 'PreConnection') def process_connection(self, per_svr, conn_rec): return self._generic_handler(None, per_svr, SimpleObject.run_conn_rec, conn_rec, _ALL, 'ProcessConnection') def post_read_request(self, per_dir, per_svr, request_rec): return self._generic_handler(None, per_svr, SimpleObject.run_request_rec, request_rec, _ALL, 'PostReadRequest') def translate_name(self, per_dir, per_svr, request_rec): return self._generic_handler(None, per_svr, SimpleObject.run_request_rec, request_rec, _FIRST, 'TranslateName') def header_parser(self, per_dir, per_svr, request_rec): return self._generic_handler(per_dir, per_svr, SimpleObject.run_request_rec, request_rec, _ALL, 'HeaderParser') def access_checker(self, per_dir, per_svr, request_rec): return self._generic_handler(per_dir, per_svr, SimpleObject.run_request_rec, request_rec, _ALL, 'AccessChecker') def check_user_id(self, per_dir, per_svr, request_rec): return self._generic_handler(per_dir, per_svr, SimpleObject.run_request_rec, request_rec, _FIRST, 'CheckUserId') def auth_checker(self, per_dir, per_svr, request_rec): return self._generic_handler(per_dir, per_svr, SimpleObject.run_request_rec, request_rec, _FIRST, 'AuthChecker') def type_checker(self, per_dir, per_svr, request_rec): return self._generic_handler(per_dir, per_svr, SimpleObject.run_request_rec, request_rec, _FIRST, 'TypeChecker') def fixups(self, per_dir, per_svr, request_rec): return self._generic_handler(per_dir, per_svr, SimpleObject.run_request_rec, request_rec, _ALL, 'Fixups') def log_transaction(self, per_dir, per_svr, request_rec): return self._generic_handler(per_dir, per_svr, SimpleObject.run_request_rec, request_rec, _ALL, 'LogTransaction') def content_handler(self, per_dir, per_svr, request_rec): return self._generic_handler(per_dir, per_svr, SimpleObject.run_request_rec, request_rec, _FIRST, 'ContentHandler') def __init__(self, module): # Configuration directives that we support directives = { "SnakePreConnection" : (mod_snake.RSRC_CONF, mod_snake.TAKE1, self.cmd_SnakePreConnection), "SnakeProcessConnection" : (mod_snake.RSRC_CONF, mod_snake.TAKE1, self.cmd_SnakeProcessConnection), "SnakePostReadRequest" : (mod_snake.RSRC_CONF, mod_snake.TAKE1, self.cmd_SnakePostReadRequest), "SnakeTranslateName" : (mod_snake.RSRC_CONF, mod_snake.TAKE1, self.cmd_SnakeTranslateName), "SnakeHeaderParser" : (mod_snake.OR_ALL, mod_snake.TAKE1, self.cmd_SnakeHeaderParser), "SnakeAccessChecker" : (mod_snake.OR_ALL, mod_snake.TAKE1, self.cmd_SnakeAccessChecker), "SnakeCheckUserId" : (mod_snake.OR_ALL, mod_snake.TAKE1, self.cmd_SnakeCheckUserId), "SnakeAuthChecker" : (mod_snake.OR_ALL, mod_snake.TAKE1, self.cmd_SnakeAuthChecker), "SnakeTypeChecker" : (mod_snake.OR_ALL, mod_snake.TAKE1, self.cmd_SnakeTypeChecker), "SnakeFixups" : (mod_snake.OR_ALL, mod_snake.TAKE1, self.cmd_SnakeFixups), "SnakeLogTransaction" : (mod_snake.OR_ALL, mod_snake.TAKE1, self.cmd_SnakeLogTransaction), "SnakeContentHandler" : (mod_snake.OR_ALL, mod_snake.TAKE1, self.cmd_SnakeContentHandler), "SnakeVarSet" : (mod_snake.OR_ALL, mod_snake.TAKE2, self.cmd_SnakeVarSet), } if string.find(mod_snake.ap_get_server_version(), '/2.0') == -1: del directives['SnakePreConnection'] del directives['SnakeProcessConnection'] module.add_directives(directives) hooks = { "create_dir_config" : self.create_dir_config, "create_svr_config" : self.create_svr_config, "post_read_request" : self.post_read_request, "translate_name" : self.translate_name, "header_parser" : self.header_parser, "access_checker" : self.access_checker, "check_user_id" : self.check_user_id, "auth_checker" : self.auth_checker, "type_checker" : self.type_checker, "fixups" : self.fixups, "content_handler" : self.content_handler, "log_transaction" : self.log_transaction, } if string.find(mod_snake.ap_get_server_version(), '/2.0') != -1: hooks["pre_connection"] = self.pre_connection hooks["process_connection"] = self.process_connection for hook in hooks.keys(): module.add_hook(hook, hooks[hook])