doc: Documented htpipe.
[ashd.git] / python / ashd / wsgidir.py
index 2da3a94..1fc66f9 100644 (file)
@@ -33,11 +33,13 @@ argument `.fpy=my.module.foohandler' can be given to pass requests for
 functions, you may want to use the getmod() function in this module.
 """
 
 functions, you may want to use the getmod() function in this module.
 """
 
-import os, threading, types, getopt
+import sys, os, threading, types, logging, getopt
 import wsgiutil
 
 __all__ = ["application", "wmain", "getmod", "cachedmod", "chain"]
 
 import wsgiutil
 
 __all__ = ["application", "wmain", "getmod", "cachedmod", "chain"]
 
+log = logging.getLogger("wsgidir")
+
 class cachedmod(object):
     """Cache entry for modules loaded by getmod()
 
 class cachedmod(object):
     """Cache entry for modules loaded by getmod()
 
@@ -108,6 +110,27 @@ def getmod(path):
     finally:
         entry[0].release()
 
     finally:
         entry[0].release()
 
+def importlocal(filename):
+    import inspect
+    cf = inspect.currentframe()
+    if cf is None: raise ImportError("could not get current frame")
+    if cf.f_back is None: raise ImportError("could not get caller frame")
+    cfile = cf.f_back.f_code.co_filename
+    if not os.path.exists(cfile):
+        raise ImportError("caller is not in a proper file")
+    path = os.path.realpath(os.path.join(os.path.dirname(cfile), filename))
+    if '.' not in os.path.basename(path):
+        for ext in [".pyl", ".py"]:
+            if os.path.exists(path + ext):
+                path += ext
+                break
+        else:
+            raise ImportError("could not resolve file: " + filename)
+    else:
+        if not os.path.exists(cfile):
+            raise ImportError("no such file: " + filename)
+    return getmod(path).mod
+
 class handler(object):
     def __init__(self):
         self.lock = threading.Lock()
 class handler(object):
     def __init__(self):
         self.lock = threading.Lock()
@@ -138,19 +161,27 @@ class handler(object):
 
     def handle(self, env, startreq):
         if not "SCRIPT_FILENAME" in env:
 
     def handle(self, env, startreq):
         if not "SCRIPT_FILENAME" in env:
+            log.error("wsgidir called without SCRIPT_FILENAME set")
             return wsgiutil.simpleerror(env, startreq, 500, "Internal Error", "The server is erroneously configured.")
         path = env["SCRIPT_FILENAME"]
         if not os.access(path, os.R_OK):
             return wsgiutil.simpleerror(env, startreq, 500, "Internal Error", "The server is erroneously configured.")
         path = env["SCRIPT_FILENAME"]
         if not os.access(path, os.R_OK):
+            log.error("%s: not readable" % path)
             return wsgiutil.simpleerror(env, startreq, 500, "Internal Error", "The server is erroneously configured.")
         if "HTTP_X_ASH_PYTHON_HANDLER" in env:
             return wsgiutil.simpleerror(env, startreq, 500, "Internal Error", "The server is erroneously configured.")
         if "HTTP_X_ASH_PYTHON_HANDLER" in env:
-            handler = self.resolve(env["HTTP_X_ASH_PYTHON_HANDLER"])
+            try:
+                handler = self.resolve(env["HTTP_X_ASH_PYTHON_HANDLER"])
+            except Exception:
+                log.error("could not load handler %s" % env["HTTP_X_ASH_PYTHON_HANDLER"], exc_info=sys.exc_info())
+                return wsgiutil.simpleerror(env, startreq, 500, "Internal Error", "The server is erroneously configured.")
         else:
             base = os.path.basename(path)
             p = base.rfind('.')
             if p < 0:
         else:
             base = os.path.basename(path)
             p = base.rfind('.')
             if p < 0:
+                log.error("wsgidir called with neither X-Ash-Python-Handler nor a file extension: %s" % path)
                 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.")
             ext = base[p + 1:]
             if not ext in self.exts:
+                log.error("unregistered file extension: %s" % ext)
                 return wsgiutil.simpleerror(env, startreq, 500, "Internal Error", "The server is erroneously configured.")
             handler = self.exts[ext]
         return handler(env, startreq)
                 return wsgiutil.simpleerror(env, startreq, 500, "Internal Error", "The server is erroneously configured.")
             handler = self.exts[ext]
         return handler(env, startreq)
@@ -192,7 +223,11 @@ def chain(env, startreq):
     object.
     """
     path = env["SCRIPT_FILENAME"]
     object.
     """
     path = env["SCRIPT_FILENAME"]
-    mod = getmod(path)
+    try:
+        mod = getmod(path)
+    except Exception:
+        log.error("Exception occurred when loading %s" % path, exc_info=sys.exc_info())
+        return wsgiutil.simpleerror(env, startreq, 500, "Internal Error", "Could not load WSGI handler.")
     entry = None
     if mod is not None:
         mod.lock.acquire()
     entry = None
     if mod is not None:
         mod.lock.acquire()