X-Git-Url: http://www.dolda2000.com/gitweb/?p=ashd.git;a=blobdiff_plain;f=python%2Fashd%2Fwsgidir.py;h=77f41fb3971a1ca5c6fe6ca743593f484eab2cde;hp=6080d9188a96b88aee09d5cb4d1f055458b28d63;hb=e9817feefe4f2ed35ded74f0ec2323ed3d0c09e4;hpb=fc2aa563ea22418e23abe89285c7a87c1ee90c5b diff --git a/python/ashd/wsgidir.py b/python/ashd/wsgidir.py index 6080d91..77f41fb 100644 --- a/python/ashd/wsgidir.py +++ b/python/ashd/wsgidir.py @@ -27,15 +27,14 @@ form `.EXT=MODULE.HANDLER', where EXT is the file extension to be handled, and the MODULE.HANDLER string is treated by splitting it along its last constituent dot. The part left of the dot is the name of a module which is imported, and the part right of the dot is the -name of an object in that module, which should be a callable of three -arguments. When files of the given extension are handled, that -callable is called with the file's absolute path, the WSGI environment -and the WSGI `start_response' function, in that order. For example, -the argument `.fpy=my.module.foohandler' can be given to pass requests -for `.fpy' files to the function `foohandler' in the module -`my.module' (which must, of course, be importable). When writing such -handler functions, you will probably want to use the getmod() function -in this module. +name of an object in that module, which should be a callable adhering +to the WSGI specification. When called, this module will have made +sure that the WSGI environment contains the SCRIPT_FILENAME parameter +and that it is properly working. For example, the argument +`.fpy=my.module.foohandler' can be given to pass requests for `.fpy' +files to the function `foohandler' in the module `my.module' (which +must, of course, be importable). When writing such handler functions, +you will probably want to use the getmod() function in this module. """ import os, threading, types @@ -56,12 +55,11 @@ class cachedmod(object): Additional data attributes can be arbitrarily added for recording any meta-data about the module. """ - def __init__(self, mod, mtime): + def __init__(self, mod = None, mtime = -1): self.lock = threading.Lock() self.mod = mod self.mtime = mtime -exts = {} modcache = {} cachelock = threading.Lock() @@ -92,25 +90,85 @@ def getmod(path): try: if path in modcache: entry = modcache[path] - if sb.st_mtime <= entry.mtime: - return entry - - f = open(path) - try: - text = f.read() - finally: - f.close() - code = compile(text, path, "exec") - mod = types.ModuleType(mangle(path)) - mod.__file__ = path - exec code in mod.__dict__ - entry = cachedmod(mod, sb.st_mtime) - modcache[path] = entry - return entry + else: + entry = cachedmod() + modcache[path] = entry finally: cachelock.release() + entry.lock.acquire() + try: + if entry.mod is None or sb.st_mtime > entry.mtime: + f = open(path, "r") + try: + text = f.read() + finally: + f.close() + code = compile(text, path, "exec") + mod = types.ModuleType(mangle(path)) + mod.__file__ = path + exec code in mod.__dict__ + entry.mod = mod + entry.mtime = sb.st_mtime + return entry + finally: + entry.lock.release() + +class handler(object): + def __init__(self): + self.lock = threading.Lock() + self.handlers = {} + self.exts = {} + self.addext("wsgi", "chain") + self.addext("wsgi2", "chain") -def chain(path, env, startreq): + def resolve(self, name): + self.lock.acquire() + try: + if name in self.handlers: + return self.handlers[name] + p = name.rfind('.') + if p < 0: + return globals()[name] + mname = name[:p] + hname = name[p + 1:] + mod = __import__(mname, fromlist = ["dummy"]) + ret = getattr(mod, hname) + self.handlers[name] = ret + return ret + finally: + self.lock.release() + + def addext(self, ext, handler): + self.exts[ext] = self.resolve(handler) + + def handle(self, env, startreq): + if not "SCRIPT_FILENAME" in env: + return wsgiutil.simpleerror(env, startreq, 500, "Internal Error", "The server is erroneously configured.") + path = env["SCRIPT_FILENAME"] + base = os.path.basename(path) + p = base.rfind('.') + if p < 0 or not os.access(path, os.R_OK): + return wsgiutil.simpleerror(env, startreq, 500, "Internal Error", "The server is erroneously configured.") + ext = base[p + 1:] + if not ext in self.exts: + return wsgiutil.simpleerror(env, startreq, 500, "Internal Error", "The server is erroneously configured.") + return(self.exts[ext](env, startreq)) + +def wmain(*argv): + """Main function for ashd(7)-compatible WSGI handlers + + Returns the `application' function. If any arguments are given, + they are parsed according to the module documentation. + """ + ret = handler() + for arg in argv: + if arg[0] == '.': + p = arg.index('=') + ret.addext(arg[1:p], arg[p + 1:]) + return ret.handle + +def chain(env, startreq): + path = env["SCRIPT_FILENAME"] mod = getmod(path) entry = None if mod is not None: @@ -129,40 +187,5 @@ def chain(path, env, startreq): if entry is not None: return entry(env, startreq) return wsgiutil.simpleerror(env, startreq, 500, "Internal Error", "Invalid WSGI handler.") -exts["wsgi"] = chain - -def addext(ext, handler): - p = handler.rindex('.') - mname = handler[:p] - hname = handler[p + 1:] - mod = __import__(mname, fromlist = ["dummy"]) - exts[ext] = getattr(mod, hname) - -def application(env, startreq): - """WSGI handler function - - Handles WSGI requests as per the module documentation. - """ - if not "SCRIPT_FILENAME" in env: - return wsgiutil.simpleerror(env, startreq, 500, "Internal Error", "The server is erroneously configured.") - path = env["SCRIPT_FILENAME"] - base = os.path.basename(path) - p = base.rfind('.') - if p < 0 or not os.access(path, os.R_OK): - return wsgiutil.simpleerror(env, startreq, 500, "Internal Error", "The server is erroneously configured.") - ext = base[p + 1:] - if not ext in exts: - return wsgiutil.simpleerror(env, startreq, 500, "Internal Error", "The server is erroneously configured.") - return(exts[ext](path, env, startreq)) -def wmain(*argv): - """Main function for ashd(7)-compatible WSGI handlers - - Returns the `application' function. If any arguments are given, - they are parsed according to the module documentation. - """ - for arg in argv: - if arg[0] == '.': - p = arg.index('=') - addext(arg[1:p], arg[p + 1:]) - return application +application = handler().handle