root@dss2 ~/moin-1.5.5a> python setup.py --quiet install --record=install.local /usr/lib/python2.3/site-packages/MoinMoin/support/lupy/store.py:158: FutureWarning: hex/oct constants > sys.maxint will return positive values in Python 2.4 and up self.writeInt((i >> 32) & 0xFFFFFFFF) /usr/lib/python2.3/site-packages/MoinMoin/support/lupy/store.py:159: FutureWarning: hex/oct constants > sys.maxint will return positive values in Python 2.4 and up self.writeInt(i & 0xFFFFFFFF) root@dss2 ~/moin-1.5.5a> cd /usr/lib/python/site-packages/ root@dss2 /usr/lib/python/site-packages> diff --recursive --brief MoinMoin MoinMoin1.5.5a/ Files MoinMoin/action/MyPages.pyc and MoinMoin1.5.5a/action/MyPages.pyc differ Files MoinMoin/action/rss_rc.pyc and MoinMoin1.5.5a/action/rss_rc.pyc differ Files MoinMoin/i18n/__init__.pyc and MoinMoin1.5.5a/i18n/__init__.pyc differ Files MoinMoin/i18n/meta.pyc and MoinMoin1.5.5a/i18n/meta.pyc differ Files MoinMoin/request.py and MoinMoin1.5.5a/request.py differ Files MoinMoin/request.pyc and MoinMoin1.5.5a/request.pyc differ Only in MoinMoin1.5.5a/: request.py.new Only in MoinMoin1.5.5a/_tests: test_formatter.py Only in MoinMoin1.5.5a/_tests: test_formatter.pyc Files MoinMoin/theme/__init__.pyc and MoinMoin1.5.5a/theme/__init__.pyc differ Files MoinMoin/util/mail.pyc and MoinMoin1.5.5a/util/mail.pyc differ root@dss2 /usr/lib/python/site-packages> t@dss2 /usr/lib/python/site-packages> diff -u MoinMoin/request.py MoinMoin1.5.5a/request.py --- MoinMoin/request.py 2006-09-15 14:26:51.000000000 -0700 +++ MoinMoin1.5.5a/request.py 2006-09-26 15:26:32.000000000 -0700 @@ -10,17 +10,8 @@ import os, re, time, sys, cgi, StringIO import copy from MoinMoin import config, wikiutil, user, caching -from MoinMoin import error, multiconfig from MoinMoin.util import MoinMoinNoFooter, IsWin9x -# umask setting -------------------------------------------------------- -# We do this once per Python process, when request is imported: -try: - # we need to use a bitwise inverted value of config.umask - os.umask(0777 ^ config.umask) -except: # we are on win32 - pass - # Timing --------------------------------------------------------------- class Clock: @@ -29,46 +20,21 @@ """ def __init__(self): - self.timings = {} - self.states = {} + self.timings = {'total': time.time()} def start(self, timer): - state = self.states.setdefault(timer, 'new') - if state == 'new': - self.timings[timer] = time.time() - self.states[timer] = 'running' - elif state == 'running': - pass # this timer is already running, do nothing - elif state == 'stopped': - # if a timer is stopped, timings has the sum of all times it was running - self.timings[timer] = time.time() - self.timings[timer] - self.states[timer] = 'running' + self.timings[timer] = time.time() - self.timings.get(timer, 0) def stop(self, timer): - state = self.states.setdefault(timer, 'neverstarted') - if state == 'running': - self.timings[timer] = time.time() - self.timings[timer] - self.states[timer] = 'stopped' - elif state == 'stopped': - pass # this timer already has been stopped, do nothing - elif state == 'neverstarted': - pass # this timer never has been started, do nothing + self.timings[timer] = time.time() - self.timings[timer] def value(self, timer): - state = self.states.setdefault(timer, 'nosuchtimer') - if state == 'stopped': - result = "%.3fs" % self.timings[timer] - elif state == 'running': - result = "%.3fs (still running)" % (time.time() - self.timings[timer]) - else: - result = "- (%s)" % state - return result + return "%.3f" % (self.timings[timer], ) def dump(self): outlist = [] - for timer in self.timings.keys(): - value = self.value(timer) - outlist.append("%s = %s" % (timer, value)) + for timing in self.timings.items(): + outlist.append("%s = %.3fs" % timing) outlist.sort() return outlist @@ -142,15 +108,10 @@ else: self.writestack = [] self.clock = Clock() - self.clock.start('total') # order is important here! self.__dict__.update(properties) - try: - self._load_multi_cfg() - except error.NoConfigMatchedError: - self.makeForbidden(404, 'No wiki configuration matching the URL found!\r\n') - return - + self._load_multi_cfg() + self.isSpiderAgent = self.check_spider() # Set decode charsets. Input from the user is always in @@ -190,12 +151,13 @@ if not self.forbidden and self.surge_protect(): self.makeUnavailable503() + from MoinMoin import i18n + self.logger = None self.pragma = {} self.mode_getpagelinks = 0 self.no_closing_html_code = 0 - from MoinMoin import i18n self.i18n = i18n self.lang = i18n.requestLanguage(self) # Language for content. Page content should use the wiki default lang, @@ -206,19 +168,15 @@ self.opened_logs = 0 self.reset() - def surge_protect(self, kick_him=False): - """ check if someone requesting too much from us, - if kick_him is True, we unconditionally blacklist the current user/ip - """ - limits = self.cfg.surge_action_limits - if not limits: - return False + def surge_protect(self): + """ check if someone requesting too much from us """ validuser = self.user.valid current_id = validuser and self.user.name or self.remote_addr if not validuser and current_id.startswith('127.'): # localnet return False current_action = self.form.get('action', ['show'])[0] + limits = self.cfg.surge_action_limits default_limit = self.cfg.surge_action_limits.get('default', (30, 60)) now = int(time.time()) @@ -258,10 +216,6 @@ maxnum, dt = limits.get(current_action, default_limit) events = surgedict.setdefault(current_id, copy.copy({})) timestamps = events.setdefault(current_action, copy.copy([])) - - if kick_him: # ban this guy, NOW - timestamps.extend([(now + self.cfg.surge_lockout_time, "!")] * (2*maxnum)) - surge_detected = surge_detected or len(timestamps) > maxnum surge_indicator = surge_detected and "!" or "" @@ -301,9 +255,8 @@ def _load_multi_cfg(self): # protect against calling multiple times if not hasattr(self, 'cfg'): - self.clock.start('load_multi_cfg') + from MoinMoin import multiconfig self.cfg = multiconfig.getConfig(self.url) - self.clock.stop('load_multi_cfg') def setAcceptedCharsets(self, accept_charset): """ Set accepted_charsets by parsing accept-charset header @@ -349,7 +302,8 @@ """ # Values we can just copy self.env = env - self.http_accept_language = env.get('HTTP_ACCEPT_LANGUAGE', self.http_accept_language) + self.http_accept_language = env.get('HTTP_ACCEPT_LANGUAGE', + self.http_accept_language) self.server_name = env.get('SERVER_NAME', self.server_name) self.server_port = env.get('SERVER_PORT', self.server_port) self.saved_cookie = env.get('HTTP_COOKIE', '') @@ -359,8 +313,6 @@ self.request_method = env.get('REQUEST_METHOD', None) self.remote_addr = env.get('REMOTE_ADDR', '') self.http_user_agent = env.get('HTTP_USER_AGENT', '') - self.if_modified_since = env.get('If-modified-since') or env.get(cgiMetaVariable('If-modified-since')) - self.if_none_match = env.get('If-none-match') or env.get(cgiMetaVariable('If-none-match')) # REQUEST_URI is not part of CGI spec, but an addition of Apache. self.request_uri = env.get('REQUEST_URI', '') @@ -657,6 +609,18 @@ return '' return self.script_name + def getPageNameFromQueryString(self): + """ Try to get pagename from the query string + + Support urls like http://netloc/script/?page_name. Allow + solving path_info encoding problems by calling with the page + name as a query. + """ + pagename = wikiutil.url_unquote(self.query_string, want_unicode=False) + pagename = self.decodePagename(pagename) + pagename = self.normalizePagename(pagename) + return pagename + def getKnownActions(self): """ Create a dict of avaiable actions @@ -784,14 +748,12 @@ try: if isinstance(d, unicode): # if we are REALLY sure, we can use "strict" - d = d.encode(config.charset, 'replace') - elif d is None: - continue + d = d.encode(config.charset, 'replace') wd.append(d) except UnicodeError: print >>sys.stderr, "Unicode error on: %s" % repr(d) return ''.join(wd) - + def decodePagename(self, name): """ Decode path, possibly using non ascii characters @@ -1018,7 +980,6 @@ def makeForbidden(self, resultcode, msg): statusmsg = { 403: 'FORBIDDEN', - 404: 'Not found', 503: 'Service unavailable', } self.http_headers([ @@ -1081,15 +1042,6 @@ else: pagename = None - # need to inform caches that content changes based on: - # * cookie (even if we aren't sending one now) - # * User-Agent (because a bot might be denied and get no content) - # * Accept-Language (except if moin is told to ignore browser language) - if self.cfg.language_ignore_browser: - self.setHttpHeader("Vary: Cookie,User-Agent") - else: - self.setHttpHeader("Vary: Cookie,User-Agent,Accept-Language") - # Handle request. We have these options: # 1. If user has a bad user name, delete its bad cookie and @@ -1130,6 +1082,10 @@ else: if action is None: action = 'show' + if not pagename and self.query_string: + # Remove the action from the query_string + self.query_string = self.query_string.replace('action=%s' % action,'') + pagename = self.getPageNameFromQueryString() # pagename could be empty after normalization e.g. '///' -> '' # Use localized FrontPage if pagename is empty if not pagename: @@ -1191,11 +1147,7 @@ self.http_headers(["Status: 302 Found", "Location: %s" % url]) def setHttpHeader(self, header): - """ Save header for later send. - - Attention: although we use a list here, some implementations use a dict, - thus multiple calls with the same header type do NOT work in the end! - """ + """ Save header for later send. """ self.user_headers.append(header) def setResponseCode(self, code, message=None): @@ -1293,7 +1245,9 @@ # Set Cache control header for http 1.1 caches # See http://www.cse.ohio-state.edu/cgi-bin/rfc/rfc2109.html#sec-4.2.3 # and http://www.cse.ohio-state.edu/cgi-bin/rfc/rfc2068.html#sec-14.9 - self.setHttpHeader('Cache-Control: no-cache="set-cookie", private, max-age=0') + self.setHttpHeader('Cache-Control: no-cache="set-cookie"') + self.setHttpHeader('Cache-Control: private') + self.setHttpHeader('Cache-Control: max-age=0') # Set Expires for http 1.0 caches (does not support Cache-Control) yearago = time.time() - (3600 * 24 * 365) @@ -1331,7 +1285,7 @@ 'query_string', # 'remote_addr', 'request_method', -# 'request_uri', + 'request_uri', # 'saved_cookie', 'script_name', # 'server_name', @@ -1450,9 +1404,7 @@ self.http_accept_language = self.twistd.getHeader('Accept-Language') self.saved_cookie = self.twistd.getHeader('Cookie') self.http_user_agent = self.twistd.getHeader('User-Agent') - self.if_modified_since = self.twistd.getHeader('If-Modified-Since')- self.if_none_match = self.twistd.getHeader('If-None-Match') - + # Copy values from twisted request self.server_protocol = self.twistd.clientproto self.server_name = self.twistd.getRequestHostname().split(':')[0] @@ -1599,8 +1551,6 @@ self.http_host = 'localhost' self.http_referer = '' self.script_name = '.' - self.if_modified_since = None - self.if_none_match = None RequestBase.__init__(self, properties) self.cfg.caching_formats = [] # don't spoil the cache self.initTheme() # usually request.run() does this, but we don't use it@@ -1682,10 +1632,6 @@ self.http_user_agent = sa.headers.getheader('user-agent', '') co = filter(None, sa.headers.getheaders('cookie')) self.saved_cookie = ', '.join(co) or '' - self.if_modified_since = (sa.headers.getheader('if-modified-since')- or self.if_modified_since) - self.if_none_match = (sa.headers.getheader('if-none-match') - or self.if_none_match) # Copy rest from standalone request self.server_name = sa.server.server_name @@ -1810,6 +1756,10 @@ else: env=req.subprocess_env self._setup_vars_from_std_env(env) + #DSS Patch: + self.if_modified_since = None + self.if_none_match = None + #End DSS Patch RequestBase.__init__(self) except Exception, err: root@dss2 /usr/lib/python/site-packages>