]> jfr.im git - irc/quakenet/qwebirc.git/blame - qwebirc/root.py
Add HTTP X-Forwarded-For support (fixes issue 30).
[irc/quakenet/qwebirc.git] / qwebirc / root.py
CommitLineData
1d924d97
CP
1from twisted.web import resource, server, static, http
2from twisted.internet import error, reactor
85f01e3f 3import engines
85f01e3f 4import mimetypes
1d924d97 5import config
e44c9cdc 6import sigdebug
23f85e9b 7import re
9e769c12
CP
8
9class RootResource(resource.Resource):
d65fe45f
CP
10 def getChild(self, name, request):
11 if name == "":
2b8e1a88 12 name = "qui.html"
d65fe45f
CP
13 return self.primaryChild.getChild(name, request)
14
1d924d97
CP
15# we do NOT use the built-in timeOut mixin as it's very very buggy!
16class 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
23f85e9b
CP
39class ProxyRequest(server.Request):
40 ip_re = re.compile(r"^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$")
41 def validIP(self, ip):
42 m = self.ip_re.match(ip)
43 if m is None:
44 return False
45 return all(int(m.group(x)) < 256 for x in range(1, 4+1))
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
9e769c12 62class RootSite(server.Site):
1d924d97
CP
63 # we do this ourselves as the built in timeout stuff is really really buggy
64 protocol = TimeoutHTTPChannel
65
23f85e9b
CP
66 if hasattr(config, "FORWARDED_FOR_HEADER"):
67 requestFactory = ProxyRequest
68
9e769c12 69 def __init__(self, path, *args, **kwargs):
d65fe45f 70 root = RootResource()
9e769c12 71 server.Site.__init__(self, root, *args, **kwargs)
d65fe45f 72
85f01e3f
CP
73 services = {}
74 services["StaticEngine"] = root.primaryChild = engines.StaticEngine(path)
28c8008e 75
85f01e3f
CP
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 register(engines.FeedbackEngine, "feedback")
83 register(engines.AuthgateEngine, "auth")
84 register(engines.AdminEngine, "adminengine", services)
85
28c8008e 86mimetypes.types_map[".ico"] = "image/vnd.microsoft.icon"