]> jfr.im git - irc/quakenet/qwebirc.git/blob - qwebirc/root.py
experimental websocket support
[irc/quakenet/qwebirc.git] / qwebirc / root.py
1 from twisted.web import resource, server, static, http
2 from twisted.internet import error, reactor
3 import engines
4 import mimetypes
5 import config
6 import sigdebug
7 import re
8
9 class RootResource(resource.Resource):
10 def getChild(self, name, request):
11 if name == "":
12 name = "qui.html"
13 return self.primaryChild.getChild(name, request)
14
15 # we do NOT use the built-in timeOut mixin as it's very very buggy!
16 class TimeoutHTTPChannel(http.HTTPChannel):
17 timeout = config.HTTP_REQUEST_TIMEOUT
18
19 def connectionMade(self):
20 self.customTimeout = reactor.callLater(self.timeout, self.timeoutOccured)
21 http.HTTPChannel.connectionMade(self)
22
23 def timeoutOccured(self):
24 self.customTimeout = None
25 self.transport.loseConnection()
26
27 def cancelTimeout(self):
28 if self.customTimeout is not None:
29 try:
30 self.customTimeout.cancel()
31 self.customTimeout = None
32 except error.AlreadyCalled:
33 pass
34
35 def connectionLost(self, reason):
36 self.cancelTimeout()
37 http.HTTPChannel.connectionLost(self, reason)
38
39 class ProxyRequest(server.Request):
40 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)
41 def validIP(self, ip):
42 m = self.ip_re.match(ip)
43 if m is None:
44 return False
45 return True
46
47 def getClientIP(self):
48 real_ip = http.Request.getClientIP(self)
49 if real_ip not in config.FORWARDED_FOR_IPS:
50 return real_ip
51
52 fake_ips = self.getHeader(config.FORWARDED_FOR_HEADER)
53 if fake_ips is None:
54 return real_ip
55
56 fake_ip = fake_ips.split(",")[-1].strip()
57 if not self.validIP(fake_ip):
58 return real_ip
59
60 return fake_ip
61
62 class RootSite(server.Site):
63 # we do this ourselves as the built in timeout stuff is really really buggy
64 protocol = TimeoutHTTPChannel
65
66 if hasattr(config, "FORWARDED_FOR_HEADER"):
67 requestFactory = ProxyRequest
68
69 def __init__(self, path, *args, **kwargs):
70 root = RootResource()
71 server.Site.__init__(self, root, *args, **kwargs)
72
73 services = {}
74 services["StaticEngine"] = root.primaryChild = engines.StaticEngine(path)
75
76 def register(service, path, *args, **kwargs):
77 sobj = service("/" + path, *args, **kwargs)
78 services[service.__name__] = sobj
79 root.putChild(path, sobj)
80
81 register(engines.AJAXEngine, "e")
82 try:
83 register(engines.WebSocketEngine, "w")
84 except AttributeError:
85 pass
86 register(engines.FeedbackEngine, "feedback")
87 register(engines.AuthgateEngine, "auth")
88 register(engines.AdminEngine, "adminengine", services)
89
90 mimetypes.types_map[".ico"] = "image/vnd.microsoft.icon"