10
10
import os, time, sys, cgi, StringIO
11
from MoinMoin import config, wikiutil, user
12
from MoinMoin import config, wikiutil, user, caching
12
13
from MoinMoin.util import MoinMoinNoFooter, IsWin9x
14
15
# Timing ---------------------------------------------------------------
101
102
# not on external non-Apache servers
102
103
self.forbidden = False
103
104
if self.request_uri.startswith('http://'):
105
self.makeForbidden403()
108
109
self.writestack = []
109
110
self.clock = Clock()
110
111
# order is important here!
112
self.__dict__.update(properties)
111
113
self._load_multi_cfg()
113
115
# Set decode charsets. Input from the user is always in
141
143
self.rootpage = Page(self, rootname, is_rootpage=1)
143
145
self.user = self.get_user()
147
if not self.query_string.startswith('action=xmlrpc'):
148
if self.surge_protect():
149
self.makeUnavailable503()
145
151
from MoinMoin import i18n
149
155
self.mode_getpagelinks = 0
150
156
self.no_closing_html_code = 0
152
self.__dict__.update(properties)
155
159
self.lang = i18n.requestLanguage(self)
156
160
# Language for content. Page content should use the wiki
162
166
self.opened_logs = 0
169
def surge_protect(self):
170
""" check if someone requesting too much from us """
171
validuser = self.user.valid
172
current_id = validuser and self.user.name or self.remote_addr
173
current_action = self.form.get('action', ['show'])[0]
174
if not validuser and current_id.startswith('127.'): # localnet
177
limits = self.cfg.surge_action_limits
178
default_limit = self.cfg.surge_action_limits.get('default', (30, 60))
180
now = int(time.time())
182
surge_detected = False
185
cache = caching.CacheEntry(self, 'surgeprotect', 'surge-log')
186
data = cache.content()
187
data = data.split("\n")
190
id, t, action, surge_indicator = line.split("\t")
192
maxnum, dt = limits.get(action, default_limit)
194
events = surgedict.setdefault(id, copy.copy({}))
195
timestamps = events.setdefault(action, copy.copy([]))
196
timestamps.append((t, surge_indicator))
197
except StandardError, err:
200
maxnum, dt = limits.get(current_action, default_limit)
201
events = surgedict.setdefault(current_id, copy.copy({}))
202
timestamps = events.setdefault(current_action, copy.copy([]))
203
surge_detected = len(timestamps) > maxnum
204
surge_indicator = surge_detected and "!" or ""
205
timestamps.append((now, surge_indicator))
207
if len(timestamps) < maxnum*2:
208
timestamps.append((now + self.cfg.surge_lockout_time, surge_indicator)) # continue like that and get locked out
211
for id, events in surgedict.items():
212
for action, timestamps in events.items():
213
for t, surge_indicator in timestamps:
214
data.append("%s\t%d\t%s\t%s" % (id, t, action, surge_indicator))
215
data = "\n".join(data)
217
except StandardError, err:
220
return surge_detected
165
222
def getDicts(self):
166
223
""" Lazy initialize the dicts on the first access """
167
224
if self._dicts is None:
506
562
self.content_lang = lang
507
563
self.current_lang = lang
509
def add2footer(self, key, htmlcode):
510
""" Add a named HTML fragment to the footer, after the default links
512
self._footer_fragments[key] = htmlcode
514
565
def getPragma(self, key, defval=None):
515
566
""" Query a pragma value (#pragma processing instruction)
894
945
""" Get the user agent. """
895
946
return self.http_user_agent
897
def makeForbidden(self):
898
self.forbidden = True
948
def makeForbidden(self, resultcode, msg):
951
503: 'Service unavailable',
899
953
self.http_headers([
900
'Status: 403 FORBIDDEN',
954
'Status: %d %s' % (resultcode, statusmsg[resultcode]),
901
955
'Content-Type: text/plain'
903
self.write('You are not allowed to access this!\r\n')
904
self.setResponseCode(403)
958
self.setResponseCode(resultcode)
959
self.forbidden = True
961
def makeForbidden403(self):
962
self.makeForbidden(403, 'You are not allowed to access this!\r\n')
964
def makeUnavailable503(self):
965
self.makeForbidden(503, "Warning:\r\n"
966
"You triggered the wiki's surge protection by doing too many requests in a short time.\r\n"
967
"Please make a short break reading the stuff you already got.\r\n"
968
"When you restart doing requests AFTER that, slow down or you might get locked out for a longer time!\r\n")
906
970
def initTheme(self):
907
971
""" Set theme - forced theme, user theme or wiki default """
1072
1136
@param url: relative or absolute url, ascii using url encoding.
1074
1138
url = self.getQualifiedURL(url)
1075
self.http_headers(["Status: 302", "Location: %s" % url])
1139
self.http_headers(["Status: 302 Found", "Location: %s" % url])
1077
1141
def setHttpHeader(self, header):
1078
1142
""" Save header for later send. """
1332
1396
def __init__(self, properties={}):
1334
self._setup_vars_from_std_env(os.environ)
1335
RequestBase.__init__(self, properties)
1337
1398
# force input/output to binary
1338
1399
if sys.platform == "win32":
1340
1401
msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
1341
1402
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
1404
self._setup_vars_from_std_env(os.environ)
1405
RequestBase.__init__(self, properties)
1343
1407
except Exception, err: