]> jfr.im git - irc/quakenet/qwebirc.git/blobdiff - qwebirc/root.py
add dynamic configuration support
[irc/quakenet/qwebirc.git] / qwebirc / root.py
index 347dbbc8817eb7c366fe8b32216deeed4eac1de4..6afaa0fdc81cfae4f66641a06d9e09f4b22699f8 100644 (file)
@@ -1,3 +1,4 @@
+from twisted.protocols.policies import TimeoutMixin
 from twisted.web import resource, server, static, http
 from twisted.internet import error, reactor
 import engines
 from twisted.web import resource, server, static, http
 from twisted.internet import error, reactor
 import engines
@@ -12,31 +13,7 @@ class RootResource(resource.Resource):
       name = "qui.html"
     return self.primaryChild.getChild(name, request)
 
       name = "qui.html"
     return self.primaryChild.getChild(name, request)
 
-# we do NOT use the built-in timeOut mixin as it's very very buggy!
-class TimeoutHTTPChannel(http.HTTPChannel):
-  timeout = config.HTTP_REQUEST_TIMEOUT
-
-  def connectionMade(self):
-    self.customTimeout = reactor.callLater(self.timeout, self.timeoutOccured)
-    http.HTTPChannel.connectionMade(self)
-    
-  def timeoutOccured(self):
-    self.customTimeout = None
-    self.transport.loseConnection()
-    
-  def cancelTimeout(self):
-    if self.customTimeout is not None:
-      try:
-        self.customTimeout.cancel()
-        self.customTimeout = None
-      except error.AlreadyCalled:
-        pass
-
-  def connectionLost(self, reason):
-    self.cancelTimeout()
-    http.HTTPChannel.connectionLost(self, reason)
-
-class ProxyRequest(server.Request):
+class WrappedRequest(server.Request):
   ip_re = re.compile(r"^((25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})|(::|(([a-fA-F0-9]{1,4}):){7}(([a-fA-F0-9]{1,4}))|(:(:([a-fA-F0-9]{1,4})){1,6})|((([a-fA-F0-9]{1,4}):){1,6}:)|((([a-fA-F0-9]{1,4}):)(:([a-fA-F0-9]{1,4})){1,6})|((([a-fA-F0-9]{1,4}):){2}(:([a-fA-F0-9]{1,4})){1,5})|((([a-fA-F0-9]{1,4}):){3}(:([a-fA-F0-9]{1,4})){1,4})|((([a-fA-F0-9]{1,4}):){4}(:([a-fA-F0-9]{1,4})){1,3})|((([a-fA-F0-9]{1,4}):){5}(:([a-fA-F0-9]{1,4})){1,2})))$", re.IGNORECASE)
   def validIP(self, ip):
     m = self.ip_re.match(ip)
   ip_re = re.compile(r"^((25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})|(::|(([a-fA-F0-9]{1,4}):){7}(([a-fA-F0-9]{1,4}))|(:(:([a-fA-F0-9]{1,4})){1,6})|((([a-fA-F0-9]{1,4}):){1,6}:)|((([a-fA-F0-9]{1,4}):)(:([a-fA-F0-9]{1,4})){1,6})|((([a-fA-F0-9]{1,4}):){2}(:([a-fA-F0-9]{1,4})){1,5})|((([a-fA-F0-9]{1,4}):){3}(:([a-fA-F0-9]{1,4})){1,4})|((([a-fA-F0-9]{1,4}):){4}(:([a-fA-F0-9]{1,4})){1,3})|((([a-fA-F0-9]{1,4}):){5}(:([a-fA-F0-9]{1,4})){1,2})))$", re.IGNORECASE)
   def validIP(self, ip):
     m = self.ip_re.match(ip)
@@ -44,8 +21,21 @@ class ProxyRequest(server.Request):
       return False
     return True
     
       return False
     return True
     
-  def getClientIP(self):
-    real_ip = http.Request.getClientIP(self)
+  def _getClientIP(self):
+    # twisted.web.http.Request.getClientIP returns None if not IPv4;
+    # client.host has the real address
+
+    if not hasattr(self, "client") or not hasattr(self.client, "host"):
+        return None
+
+    real_ip = self.client.host
+
+    if real_ip[:7] == "::ffff:":
+      real_ip = real_ip[7:]
+
+    if not hasattr(config, "FORWARDED_FOR_HEADER"):
+      return real_ip
+
     if real_ip not in config.FORWARDED_FOR_IPS:
       return real_ip
       
     if real_ip not in config.FORWARDED_FOR_IPS:
       return real_ip
       
@@ -58,18 +48,30 @@ class ProxyRequest(server.Request):
       return real_ip
       
     return fake_ip
       return real_ip
       
     return fake_ip
-    
+
+  def getClientIP(self):
+    ip = self._getClientIP()
+
+    if ip is None:
+      return None
+
+    # make absolutely sure that the address doesn't start with : before we
+    # try to use it as a string to the IRC server!
+    return ip.lstrip(":")
+
+class HTTPChannel(http.HTTPChannel):
+  def timeoutConnection(self):
+    self.transport.abortConnection()
+
 class RootSite(server.Site):
 class RootSite(server.Site):
-  # we do this ourselves as the built in timeout stuff is really really buggy
-  protocol = TimeoutHTTPChannel
-  
-  if hasattr(config, "FORWARDED_FOR_HEADER"):
-    requestFactory = ProxyRequest
+  protocol = HTTPChannel
+
+  requestFactory = WrappedRequest
 
   def __init__(self, path, *args, **kwargs):
     root = RootResource()
 
   def __init__(self, path, *args, **kwargs):
     root = RootResource()
+    kwargs["timeout"] = config.HTTP_REQUEST_TIMEOUT
     server.Site.__init__(self, root, *args, **kwargs)
     server.Site.__init__(self, root, *args, **kwargs)
-
     services = {}
     services["StaticEngine"] = root.primaryChild = engines.StaticEngine(path)
 
     services = {}
     services["StaticEngine"] = root.primaryChild = engines.StaticEngine(path)
 
@@ -83,7 +85,6 @@ class RootSite(server.Site):
       register(engines.WebSocketEngine, "w")
     except AttributeError:
       pass
       register(engines.WebSocketEngine, "w")
     except AttributeError:
       pass
-    register(engines.FeedbackEngine, "feedback")
     register(engines.AuthgateEngine, "auth")
     register(engines.AdminEngine, "adminengine", services)
     
     register(engines.AuthgateEngine, "auth")
     register(engines.AdminEngine, "adminengine", services)