python: Added a safety timeout in the new-thread wait loop.
[ashd.git] / python3 / ashd / serve.py
index 15e2903..ce17b9d 100644 (file)
@@ -23,7 +23,7 @@ class reqthread(threading.Thread):
         super().__init__(name=name, **kw)
 
 class wsgirequest(object):
-    def __init__(self, handler):
+    def __init__(self, *, handler):
         self.status = None
         self.headers = []
         self.respsent = False
@@ -88,6 +88,8 @@ class handler(object):
         return {}
 
 class single(handler):
+    cname = "single"
+
     def handle(self, req):
         try:
             env = req.mkenv()
@@ -107,6 +109,8 @@ class single(handler):
             req.close()
 
 class freethread(handler):
+    cname = "free"
+
     def __init__(self, *, max=None, timeout=None, **kw):
         super().__init__(**kw)
         self.current = set()
@@ -140,7 +144,7 @@ class freethread(handler):
             th = reqthread(target=self.run, args=[req])
             th.start()
             while th.is_alive() and th not in self.current:
-                self.tcond.wait()
+                self.tcond.wait(1)
 
     def run(self, req):
         try:
@@ -179,6 +183,8 @@ class freethread(handler):
             th.join()
 
 class resplex(handler):
+    cname = "rplex"
+
     def __init__(self, *, max=None, **kw):
         super().__init__(**kw)
         self.current = set()
@@ -208,7 +214,7 @@ class resplex(handler):
             th = reqthread(target=self.handle1, args=[req])
             th.start()
             while th.is_alive() and th not in self.current:
-                self.tcond.wait()
+                self.tcond.wait(1)
 
     def handle1(self, req):
         try:
@@ -266,15 +272,22 @@ class resplex(handler):
                         data = next(respiter)
                     except StopIteration:
                         rem = True
-                        req.flushreq()
+                        try:
+                            req.flushreq()
+                        except:
+                            log.error("exception occurred when handling response data", exc_info=True)
                     except:
                         rem = True
                         log.error("exception occurred when iterating response", exc_info=True)
                     if not rem:
                         if data:
-                            req.flushreq()
-                            req.writedata(data)
-                    else:
+                            try:
+                                req.flushreq()
+                                req.writedata(data)
+                            except:
+                                log.error("exception occurred when handling response data", exc_info=True)
+                                rem = True
+                    if rem:
                         current[req] = None
                         try:
                             if hasattr(respiter, "close"):
@@ -326,9 +339,10 @@ class resplex(handler):
         os.close(self.cnpipe[1])
         self.rthread.join()
 
-names = {"single": single,
-         "free": freethread,
-         "rplex": resplex}
+names = {cls.cname: cls for cls in globals().values() if
+         isinstance(cls, type) and
+         issubclass(cls, handler) and
+         hasattr(cls, "cname")}
 
 def parsehspec(spec):
     if ":" not in spec: