]>
Commit | Line | Data |
---|---|---|
1d924d97 CP |
1 | from twisted.web import resource, server, static, http |
2 | from twisted.internet import error, reactor | |
85f01e3f | 3 | import engines |
85f01e3f | 4 | import mimetypes |
1d924d97 | 5 | import config |
e44c9cdc | 6 | import sigdebug |
23f85e9b | 7 | import re |
9e769c12 CP |
8 | |
9 | class 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! |
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 | ||
23f85e9b | 39 | class ProxyRequest(server.Request): |
133b7132 | 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) |
23f85e9b CP |
41 | def validIP(self, ip): |
42 | m = self.ip_re.match(ip) | |
43 | if m is None: | |
44 | return False | |
133b7132 | 45 | return True |
23f85e9b CP |
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 | 62 | class 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") | |
c60795d6 CP |
82 | try: |
83 | register(engines.WebSocketEngine, "w") | |
84 | except AttributeError: | |
85 | pass | |
85f01e3f CP |
86 | register(engines.FeedbackEngine, "feedback") |
87 | register(engines.AuthgateEngine, "auth") | |
88 | register(engines.AdminEngine, "adminengine", services) | |
89 | ||
28c8008e | 90 | mimetypes.types_map[".ico"] = "image/vnd.microsoft.icon" |