python: Remove HTTP_CONTENT_{TYPE,LENGTH} from WSGI environment.
[ashd.git] / python3 / ashd-wsgi3
index 5f5b5e1..dcf1613 100755 (executable)
@@ -1,27 +1,40 @@
 #!/usr/bin/python3
 
-import sys, os, getopt, threading, time, locale, collections
-import ashd.proto, ashd.util
+import sys, os, getopt, threading, logging, time, locale, collections
+import ashd.proto, ashd.util, ashd.perf
+try:
+    import pdm.srv
+except:
+    pdm = None
 
 def usage(out):
-    out.write("usage: ashd-wsgi3 [-hA] [-p MODPATH] [-l REQLIMIT] HANDLER-MODULE [ARGS...]\n")
+    out.write("usage: ashd-wsgi3 [-hAL] [-m PDM-SPEC] [-p MODPATH] [-l REQLIMIT] HANDLER-MODULE [ARGS...]\n")
 
 reqlimit = 0
 modwsgi_compat = False
-opts, args = getopt.getopt(sys.argv[1:], "+hAp:l:")
+setlog = True
+opts, args = getopt.getopt(sys.argv[1:], "+hALp:l:m:")
 for o, a in opts:
     if o == "-h":
         usage(sys.stdout)
         sys.exit(0)
     elif o == "-p":
         sys.path.insert(0, a)
+    elif o == "-L":
+        setlog = False
     elif o == "-A":
         modwsgi_compat = True
     elif o == "-l":
         reqlimit = int(a)
+    elif o == "-m":
+        if pdm is not None:
+            pdm.srv.listen(a)
 if len(args) < 1:
     usage(sys.stderr)
     sys.exit(1)
+if setlog:
+    logging.basicConfig(format="ashd-wsgi3(%(name)s): %(levelname)s: %(message)s")
+log = logging.getLogger("ashd-wsgi3")
 
 try:
     handlermod = __import__(args[0], fromlist = ["dummy"])
@@ -122,6 +135,10 @@ def dowsgi(req):
                      ("HTTP_X_ASH_ADDRESS", "REMOTE_ADDR"), ("HTTP_CONTENT_TYPE", "CONTENT_TYPE"),
                      ("HTTP_CONTENT_LENGTH", "CONTENT_LENGTH"), ("HTTP_X_ASH_PROTOCOL", "wsgi.url_scheme")]:
         if src in env: env[tgt] = env[src]
+    for key in ["HTTP_CONTENT_TYPE", "HTTP_CONTENT_LENGTH"]:
+        # The CGI specification does not strictly require this, but
+        # many actualy programs and libraries seem to.
+        if key in env: del env[key]
     if "X-Ash-Protocol" in req and req["X-Ash-Protocol"] == b"https": env["HTTPS"] = "on"
     if "X-Ash-File" in req: env["SCRIPT_FILENAME"] = absolutify(req["X-Ash-File"].decode(locale.getpreferredencoding()))
     env["wsgi.input"] = req.sk
@@ -178,18 +195,21 @@ def dowsgi(req):
         resp[:] = status, headers
         return write
 
-    respiter = handler(env, startreq)
-    try:
+    with ashd.perf.request(env) as reqevent:
         try:
-            for data in respiter:
-                write(data)
-            if resp:
-                flushreq()
+            respiter = handler(env, startreq)
+            try:
+                for data in respiter:
+                    write(data)
+                if resp:
+                    flushreq()
+            finally:
+                if hasattr(respiter, "close"):
+                    respiter.close()
         except closed:
             pass
-    finally:
-        if hasattr(respiter, "close"):
-            respiter.close()
+        if resp:
+            reqevent.response(resp)
 
 flightlock = threading.Condition()
 inflight = 0
@@ -216,8 +236,11 @@ class reqthread(threading.Thread):
                 with flightlock:
                     inflight -= 1
                     flightlock.notify()
+        except:
+            log.error("exception occurred in handler thread", exc_info=True)
         finally:
             self.req.close()
+            sys.stderr.flush()
     
 def handle(req):
     reqthread(req).start()