Changeset 202
- Timestamp:
- 05/22/05 14:10:52
- Files:
-
- trunk/cherrypy/_cpconfig.py (modified) (5 diffs)
- trunk/cherrypy/_cpdefaults.py (modified) (7 diffs)
- trunk/cherrypy/_cphttpserver.py (modified) (4 diffs)
- trunk/cherrypy/_cphttptools.py (modified) (11 diffs)
- trunk/cherrypy/_cpmagicattr.py (deleted)
- trunk/cherrypy/lib/filter/basefilter.py (modified) (2 diffs)
- trunk/cherrypy/lib/filter/baseurlfilter.py (modified) (2 diffs)
- trunk/cherrypy/lib/filter/cachefilter.py (modified) (7 diffs)
- trunk/cherrypy/lib/filter/decodingfilter.py (modified) (3 diffs)
- trunk/cherrypy/lib/filter/encodingfilter.py (modified) (3 diffs)
- trunk/cherrypy/lib/filter/gzipfilter.py (modified) (4 diffs)
- trunk/cherrypy/lib/filter/logdebuginfofilter.py (modified) (2 diffs)
- trunk/cherrypy/lib/filter/staticfilter.py (added)
- trunk/cherrypy/lib/filter/tidyfilter.py (modified) (6 diffs)
- trunk/cherrypy/lib/filter/virtualhostfilter.py (modified) (2 diffs)
- trunk/cherrypy/lib/filter/xmlrpcfilter.py (modified) (3 diffs)
- trunk/cherrypy/test/helper.py (modified) (1 diff)
- trunk/cherrypy/test/test.py (modified) (1 diff)
- trunk/cherrypy/test/testBaseUrlFilter.py (added)
- trunk/cherrypy/test/testCacheFilter.py (added)
- trunk/cherrypy/test/testCombinedFilters.py (moved) (moved from trunk/cherrypy/test/testFilter1.py) (3 diffs)
- trunk/cherrypy/test/testDecodingEncodingFilter.py (added)
- trunk/cherrypy/test/testGzipFilter.py (added)
- trunk/cherrypy/test/testLogDebugInfoFilter.py (added)
- trunk/cherrypy/test/testStaticFilter.py (moved) (moved from trunk/cherrypy/test/testStaticContent.py) (2 diffs)
- trunk/cherrypy/test/testVirtualHostFilter.py (modified) (1 diff)
- trunk/cherrypy/test/testwsgiapp.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/cherrypy/_cpconfig.py
r199 r202 31 31 # Default config options 32 32 configMap = { 33 'server': { 34 'protocolVersion': 'HTTP/1.0', 35 'logToScreen': True, 36 'logFile': '', 37 'socketHost': '', 38 'socketPort': 8080, 39 'socketFile': '', 40 'reverseDNS': False, 41 'socketQueueSize': 5, 42 'protocolVersion': 'HTTP/1.0', 43 'threadPool': 0, 44 'environment': 'dev'}, 45 'session': { 46 'storageType': 'ram', 47 'timeout': 60, 48 'cleanUpDelay': 60, 49 'cookieName': 'CherryPySession', 50 'storageFileDir': '', 33 '/': { 34 'server.socketPort': 8080, 35 'server.socketHost': '', 36 'server.socketFile': '', 37 'server.socketQueueSize': 5, 38 39 'server.env': 'dev', 40 'server.protocolVersion': 'HTTP/1.0', 41 'server.logToScreen': True, 42 'server.logFile': '', 43 'server.reverseDNS': False, 44 'server.threadPool': 0, 45 'server.environment': 'prod', 46 47 'session.storageType': 'ram', 48 'session.timeout': 60, 49 'session.cleanUpDelay': 60, 50 'session.cookieName': 'CherryPySession', 51 'session.storageFileDir': '', 52 53 'staticContent': {} 51 54 }, 52 'staticContent': {}53 55 } 54 56 … … 64 66 _load(file) 65 67 66 def get(section, attrName = None, defaultValue = None): 67 if attrName: 68 return configMap.get(section, {}).get(attrName, defaultValue) 68 def _getSlashSections(): 69 """ Return all config sections from configMap 70 that start with a slash and return them sorted by length 71 (longest first) 72 """ 73 # TODO: the result could be cached and recomputed when 74 # config.update() is called 75 sectionList = [section for section in configMap.keys() 76 if (section[0] == '/' or section.startswith('http://') or 77 section.startswith('https://'))] 78 sectionList.sort(_sortOnLength) 79 return sectionList 80 81 def _sortOnLength(a, b): 82 l1, l2 = len(a), len(b) 83 if l1 == l2: 84 return 0 85 elif l1 < l2: 86 return 1 69 87 else: 70 return configMap.get(section, defaultValue) 71 72 def getForPath(attrNam, defaultValue = None): 73 raise "TODO" 88 return -1 89 90 def _getFor(path, key, defaultValue = None, returnSection = False): 91 for section in _getSlashSections(): 92 if path.startswith(section): 93 res = configMap[section].get(key, '#NULL#') 94 if res != '#NULL#': 95 if returnSection: 96 return section 97 return res 98 return defaultValue 99 100 def _cast(type, value): 101 if type is None: 102 return value 103 if type == 'int': 104 return int(value) 105 elif type == 'float': 106 return float(value) 107 elif type == 'bool': 108 if isinstance(value, basestring): 109 value = value.lower() 110 if (not value) or (value in ('false', 'off', '0')): 111 return False 112 return True 113 elif type == 'list': 114 if isinstance(value, list): 115 return value 116 assert (not value) or ( 117 value[0] in ('(', '[') and value[-1] in (')', ']')) 118 return eval(value) # Convert value to list 119 120 def get(key, defaultValue = None, cast = None, returnSection = False): 121 # First try the whole browserUrl 122 try: 123 path = cpg.request.browserUrl 124 except: 125 # At startup, we don't have a path yet 126 path = '/' 127 res = _getFor(path, key, '#NULL#', returnSection) 128 if res != '#NULL#': 129 return _cast(cast, res) 130 # Then try just path 131 try: 132 path = cpg.request.path 133 except: 134 # At startup, we don't have a path yet 135 path = '/' 136 res = _getFor(path, key, '#NULL#', returnSection) 137 if res != '#NULL#': 138 return _cast(cast, res) 139 return _cast(cast, defaultValue) 74 140 75 141 class CaseSensitiveConfigParser(ConfigParser.ConfigParser): … … 91 157 fp.close() 92 158 93 # Known options to cast:94 cast = {95 'server': {96 'logToScreen': 'getboolean',97 'socketPort': 'getint',98 'reverseDNS': 'getboolean',99 'socketQueueSize': 'getint',100 'threadPool': 'getint'},101 'session': {102 'sessionTimeout': 'getint',103 'cleanUpDelay': 'getint',104 }105 }106 107 159 def _load(configFile = None): 108 160 """ Convert an INI file to a dictionary """ … … 123 175 configMap[section] = {} 124 176 for option in configParser.options(section): 125 # Check if we need to cast options 126 funcName = cast.get(section, {}).get(option, 'get') 127 value = getattr(configParser, funcName)(section, option) 177 value = configParser.get(section, option) 128 178 configMap[section][option] = value 129 179 … … 131 181 _cpLogMessage = _cputil.getSpecialFunction('_cpLogMessage') 132 182 _cpLogMessage("Server parameters:", 'CONFIG') 133 _cpLogMessage(" server.logToScreen: %s" % cpg.config.get('server', 'logToScreen'), 'CONFIG') 134 _cpLogMessage(" server.logFile: %s" % cpg.config.get('server', 'logFile'), 'CONFIG') 135 _cpLogMessage(" server.protocolVersion: %s" % cpg.config.get('server', 'protocolVersion'), 'CONFIG') 136 _cpLogMessage(" server.socketHost: %s" % cpg.config.get('server', 'socketHost'), 'CONFIG') 137 _cpLogMessage(" server.socketPort: %s" % cpg.config.get('server', 'socketPort'), 'CONFIG') 138 _cpLogMessage(" server.socketFile: %s" % cpg.config.get('server', 'socketFile'), 'CONFIG') 139 _cpLogMessage(" server.reverseDNS: %s" % cpg.config.get('server', 'reverseDNS'), 'CONFIG') 140 _cpLogMessage(" server.socketQueueSize: %s" % cpg.config.get('server', 'socketQueueSize'), 'CONFIG') 141 _cpLogMessage(" server.threadPool: %s" % cpg.config.get('server', 'threadPool'), 'CONFIG') 142 _cpLogMessage(" session.storageType: %s" % cpg.config.get('session', 'storageType'), 'CONFIG') 143 if cpg.config.get('session', 'storageType'): 144 _cpLogMessage(" session.timeout: %s min" % cpg.config.get('session', 'timeout'), 'CONFIG') 145 _cpLogMessage(" session.cleanUpDelay: %s min" % cpg.config.get('session', 'cleanUpDelay'), 'CONFIG') 146 _cpLogMessage(" session.cookieName: %s" % cpg.config.get('session', 'cookieName'), 'CONFIG') 147 _cpLogMessage(" session.storageFileDir: %s" % cpg.config.get('session', 'storageFileDir'), 'CONFIG') 183 _cpLogMessage(" server.env: %s" % cpg.config.get('server.env'), 'CONFIG') 184 _cpLogMessage(" server.logToScreen: %s" % cpg.config.get('server.logToScreen', cast='bool'), 'CONFIG') 185 _cpLogMessage(" server.logFile: %s" % cpg.config.get('server.logFile'), 'CONFIG') 186 _cpLogMessage(" server.protocolVersion: %s" % cpg.config.get('server.protocolVersion'), 'CONFIG') 187 _cpLogMessage(" server.socketHost: %s" % cpg.config.get('server.socketHost'), 'CONFIG') 188 _cpLogMessage(" server.socketPort: %s" % cpg.config.get('server.socketPort', cast='int'), 'CONFIG') 189 _cpLogMessage(" server.socketFile: %s" % cpg.config.get('server.socketFile'), 'CONFIG') 190 _cpLogMessage(" server.reverseDNS: %s" % cpg.config.get('server.reverseDNS', cast='bool'), 'CONFIG') 191 _cpLogMessage(" server.socketQueueSize: %s" % cpg.config.get('server.socketQueueSize', cast='int'), 'CONFIG') 192 _cpLogMessage(" server.threadPool: %s" % cpg.config.get('server.threadPool', cast='int'), 'CONFIG') 193 _cpLogMessage(" session.storageType: %s" % cpg.config.get('session.storageType'), 'CONFIG') 194 if cpg.config.get('session.storageType'): 195 _cpLogMessage(" session.timeout: %s min" % cpg.config.get('session.timeout', cast='float'), 'CONFIG') 196 _cpLogMessage(" session.cleanUpDelay: %s min" % cpg.config.get('session.cleanUpDelay', cast='float'), 'CONFIG') 197 _cpLogMessage(" session.cookieName: %s" % cpg.config.get('session.cookieName'), 'CONFIG') 198 _cpLogMessage(" session.storageFileDir: %s" % cpg.config.get('session.storageFileDir'), 'CONFIG') 148 199 _cpLogMessage(" staticContent: %s" % cpg.config.get('staticContent'), 'CONFIG') 149 200 trunk/cherrypy/_cpdefaults.py
r199 r202 32 32 """ 33 33 34 import time, thread, os , cpg34 import time, thread, os 35 35 import cPickle as pickle 36 import cpg 36 37 37 38 def _cpLogMessage(msg, context = '', severity = 0): … … 49 50 lebel = "UNKNOWN" 50 51 try: 51 logToScreen = int(cpg.config Option.logToScreen)52 logToScreen = int(cpg.config.get('server.logToScreen', cast='bool')) 52 53 except: 53 54 logToScreen = True … … 55 56 if logToScreen: 56 57 print s 57 if cpg.config.get('server ', 'logFile'):58 f = open(cpg.config.get('server ','logFile'), 'ab')58 if cpg.config.get('server.logFile'): 59 f = open(cpg.config.get('server.logFile'), 'ab') 59 60 f.write(s + '\n') 60 61 f.close() … … 75 76 76 77 if threadPool is None: 77 threadPool = cpg.config.get('server ', 'threadPool')78 threadPool = cpg.config.get('server.threadPool', cast='int') 78 79 if sessionStorageType is None: 79 sessionStorageType = cpg.config.get('session ', 'storageType')80 sessionStorageType = cpg.config.get('session.storageType') 80 81 if sessionStorageFileDir is None: 81 sessionStorageFileDir = cpg.config.get('session ', 'storageFileDir')82 sessionStorageFileDir = cpg.config.get('session.storageFileDir') 82 83 83 84 t = time.localtime(expirationTime) … … 103 104 104 105 if threadPool is None: 105 threadPool = cpg.config.get('server ', 'threadPool')106 threadPool = cpg.config.get('server.threadPool', cast='int') 106 107 if sessionStorageType is None: 107 sessionStorageType = cpg.config.get('session ', 'storageType')108 sessionStorageType = cpg.config.get('session.storageType') 108 109 if sessionStorageFileDir is None: 109 sessionStorageFileDir = cpg.config.get('session ', 'storageFileDir')110 sessionStorageFileDir = cpg.config.get('session.storageFileDir') 110 111 111 112 if sessionStorageType == "ram": … … 132 133 133 134 if threadPool is None: 134 threadPool = cpg.config.get('server ', 'threadPool')135 threadPool = cpg.config.get('server.threadPool', cast='int') 135 136 if sessionStorageType is None: 136 sessionStorageType = cpg.config.get('session ', 'storageType')137 sessionStorageType = cpg.config.get('session.storageType') 137 138 if sessionStorageFileDir is None: 138 sessionStorageFileDir = cpg.config.get('session ', 'storageFileDir')139 sessionStorageFileDir = cpg.config.get('session.storageFileDir') 139 140 140 141 # Clean up old session data … … 165 166 166 167 _cpFilterList = [] 168 169 # Filters that are always included 170 from cherrypy.lib.filter import baseurlfilter, cachefilter, \ 171 decodingfilter, encodingfilter, gzipfilter, logdebuginfofilter, \ 172 staticfilter, tidyfilter, virtualhostfilter, xmlrpcfilter 173 _cpDefaultInputFilterList = [ 174 cachefilter.CacheInputFilter(), 175 logdebuginfofilter.LogDebugInfoInputFilter(), 176 virtualhostfilter.VirtualHostFilter(), 177 baseurlfilter.BaseUrlFilter(), 178 decodingfilter.DecodingFilter(), 179 staticfilter.StaticFilter(), 180 xmlrpcfilter.XmlRpcInputFilter(), 181 ] 182 _cpDefaultOutputFilterList = [ 183 xmlrpcfilter.XmlRpcOutputFilter(), 184 encodingfilter.EncodingFilter(), 185 tidyfilter.TidyFilter(), 186 logdebuginfofilter.LogDebugInfoOutputFilter(), 187 gzipfilter.GzipFilter(), 188 cachefilter.CacheOutputFilter(), 189 ] 190 trunk/cherrypy/_cphttpserver.py
r199 r202 38 38 # If sessions are stored in files and we 39 39 # use threading, we need a lock on the file 40 if (cpg.config.get('server ', 'threadPool') > 1) and \41 cpg.config.get('session ', 'storageType') == 'file':40 if (cpg.config.get('server.threadPool', cast='int') > 1) and \ 41 cpg.config.get('session.storageType') == 'file': 42 42 cpg._sessionFileLock = threading.RLock() 43 43 44 44 45 if cpg.config.get('server ', 'socketFile'):45 if cpg.config.get('server.socketFile'): 46 46 # AF_UNIX socket 47 47 # TODO: Handle threading here … … 49 49 else: 50 50 # AF_INET socket 51 if cpg.config.get('server ', 'threadPool') > 1:51 if cpg.config.get('server.threadPool', cast='int') > 1: 52 52 MyCherryHTTPServer = PooledThreadServer 53 53 else: 54 54 MyCherryHTTPServer = CherryHTTPServer 55 55 56 MyCherryHTTPServer.request_queue_size = cpg.config.get('server ', 'socketQueueSize')56 MyCherryHTTPServer.request_queue_size = cpg.config.get('server.socketQueueSize', cast='int') 57 57 58 58 # Set protocol_version 59 CherryHTTPRequestHandler.protocol_version = cpg.config.get('server ', 'protocolVersion')59 CherryHTTPRequestHandler.protocol_version = cpg.config.get('server.protocolVersion') 60 60 61 61 run_server(CherryHTTPRequestHandler, MyCherryHTTPServer, \ 62 (cpg.config.get('server ', 'socketHost'), cpg.config.get('server', 'socketPort')), \63 cpg.config.get('server ', 'socketFile'))62 (cpg.config.get('server.socketHost'), cpg.config.get('server.socketPort', cast='int')), \ 63 cpg.config.get('server.socketFile')) 64 64 65 65 def run_server(HandlerClass, ServerClass, server_address, socketFile): 66 66 """Run the HTTP request handler class.""" 67 67 68 if cpg.config.get('server ', 'socketFile'):69 try: os.unlink(cpg.config.get('server ', 'socketFile')) # So we can reuse the socket68 if cpg.config.get('server.socketFile'): 69 try: os.unlink(cpg.config.get('server.socketFile')) # So we can reuse the socket 70 70 except: pass 71 server_address = cpg.config.get('server ', 'socketFile')72 if cpg.config.get('server ', 'threadPool') > 1:73 myCherryHTTPServer = ServerClass(server_address, cpg.config.get('server ', 'threadPool'), HandlerClass)71 server_address = cpg.config.get('server.socketFile') 72 if cpg.config.get('server.threadPool', cast='int') > 1: 73 myCherryHTTPServer = ServerClass(server_address, cpg.config.get('server.threadPool', cast='int'), HandlerClass) 74 74 else: 75 75 myCherryHTTPServer = ServerClass(server_address, HandlerClass) 76 76 cpg._server = myCherryHTTPServer 77 if cpg.config.get('server ', 'socketFile'):77 if cpg.config.get('server.socketFile'): 78 78 try: os.chmod(socketFile, 0777) # So everyone can access the socket 79 79 except: pass … … 82 82 83 83 servingWhat = "HTTP" 84 if cpg.config.get('server ', 'socketPort'):84 if cpg.config.get('server.socketPort', cast='int'): 85 85 onWhat = ("socket: ('%s', %s)" % 86 (cpg.config.get('server ', 'socketHost'), cpg.config.get('server', 'socketPort')))87 else: onWhat = "socket file: %s" % cpg.config.get('server ', 'socketFile')86 (cpg.config.get('server.socketHost'), cpg.config.get('server.socketPort', cast='int'))) 87 else: onWhat = "socket file: %s" % cpg.config.get('server.socketFile') 88 88 _cpLogMessage("Serving %s on %s" % (servingWhat, onWhat), 'HTTP') 89 89 … … 113 113 def address_string(self): 114 114 """ Try to do a reverse DNS based on [server]reverseDNS in the config file """ 115 if cpg.config.get('server ', 'reverseDNS'):115 if cpg.config.get('server.reverseDNS', cast='bool'): 116 116 return BaseHTTPServer.BaseHTTPRequestHandler.address_string(self) 117 117 else: trunk/cherrypy/_cphttptools.py
r199 r202 30 30 import mimetypes, sha, random, string, _cputil, cperror, Cookie, urlparse 31 31 from lib.filter import basefilter 32 import _cpdefaults 32 33 33 34 """ … … 143 144 144 145 def applyFilterList(methodName): 145 try: 146 filterList = _cputil.getSpecialFunction('_cpFilterList') 147 for filter in filterList: 148 method = getattr(filter, methodName, None) 149 if method: 150 method() 151 except basefilter.InternalRedirect: 152 # If we get an InternalRedirect, we start the filter list 153 # from scratch. Is cpg.request.path or cpg.request.objectPath 154 # has been modified by the hook, then a new filter list 155 # will be applied. 156 # We use recursion so if there is an infinite loop, we'll 157 # get the regular python "recursion limit exceeded" exception. 158 applyFilterList(methodName) 159 146 filterList = _cpdefaults._cpDefaultInputFilterList + \ 147 _cputil.getSpecialFunction('_cpFilterList') + \ 148 _cpdefaults._cpDefaultOutputFilterList 149 for filter in filterList: 150 method = getattr(filter, methodName, None) 151 if method: 152 method() 160 153 161 154 def insertIntoHeaderMap(key,value): … … 176 169 cpg.request.objectPath = None 177 170 171 applyFilterList('setConfig') 178 172 applyFilterList('afterRequestHeader') 179 173 … … 187 181 cpg.response.wfile = wfile 188 182 cpg.response.sendResponse = True 183 cpg.response.body = None 189 184 190 185 # Prepare response variables … … 193 188 date = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (weekdayname[wd], day, monthname[month], year, hh, mm, ss) 194 189 cpg.response.headerMap = { 195 "protocolVersion": cpg.config.get('server ', 'protocolVersion'),190 "protocolVersion": cpg.config.get('server.protocolVersion'), 196 191 "Status": "200 OK", 197 192 "Content-Type": "text/html", … … 228 223 229 224 # Still save session data 230 if cpg.config.get('session ', 'storageType') and not cpg.request.isStatic:231 sessionId = cpg.response.simpleCookie[cpg.config.get('session ', 'cookieName')].value232 expirationTime = time.time() + cpg.config.get('session ', 'timeout') * 60225 if cpg.config.get('session.storageType') and not cpg.request.isStatic: 226 sessionId = cpg.response.simpleCookie[cpg.config.get('session.cookieName')].value 227 expirationTime = time.time() + cpg.config.get('session.timeout') * 60 233 228 _cputil.getSpecialFunction('_cpSaveSessionData')(sessionId, cpg.request.sessionMap, expirationTime) 234 229 230 applyFilterList('beforeErrorResponse') 235 231 wfile.write('%s %s\r\n' % (cpg.response.headerMap['protocolVersion'], cpg.response.headerMap['Status'])) 236 232 … … 251 247 for line in cpg.response.body: 252 248 wfile.write(line) 249 applyFilterList('afterErrorResponse') 253 250 except: 254 251 bodyFile = StringIO.StringIO() 255 252 traceback.print_exc(file = bodyFile) 256 253 body = bodyFile.getvalue() 257 wfile.write('%s 200 OK\r\n' % cpg.config.get('server ', 'protocolVersion'))254 wfile.write('%s 200 OK\r\n' % cpg.config.get('server.protocolVersion')) 258 255 wfile.write('Content-Type: text/plain\r\n') 259 256 wfile.write('Content-Length: %s\r\n' % len(body)) … … 274 271 275 272 # Save session data 276 if cpg.config.get('session ', 'storageType') and not cpg.request.isStatic:277 sessionId = cpg.response.simpleCookie[cpg.config.get('session ', 'cookieName')].value278 expirationTime = time.time() + cpg.config.get('session ', 'timeout') * 60273 if cpg.config.get('session.storageType') and not cpg.request.isStatic: 274 sessionId = cpg.response.simpleCookie[cpg.config.get('session.cookieName')].value 275 expirationTime = time.time() + cpg.config.get('session.timeout', cast='float') * 60 279 276 _cputil.getSpecialFunction('_cpSaveSessionData')(sessionId, cpg.request.sessionMap, expirationTime) 280 277 … … 301 298 # Clean up expired sessions if needed: 302 299 now = time.time() 303 if (cpg.config.get('session ', 'storageType') and304 cpg.config.get('session ', 'cleanUpDelay') and305 (cpg._lastSessionCleanUpTime + cpg.config.get('session ', 'cleanUpDelay') * 60) <= now):300 if (cpg.config.get('session.storageType') and 301 cpg.config.get('session.cleanUpDelay', cast='float') and 302 (cpg._lastSessionCleanUpTime + cpg.config.get('session.cleanUpDelay', cast='float') * 60) <= now): 306 303 cpg._lastSessionCleanUpTime = now 307 304 _cputil.getSpecialFunction('_cpCleanUpOldSessions')() … … 321 318 path = urllib.unquote(path) # Replace quoted chars (eg %20) from url 322 319 323 # Handle static directories324 for urlDir, fsDir in cpg.config.get('staticContent').items():325 if path == urlDir or path[:len(urlDir)+1]==urlDir+'/':326 327 cpg.request.isStatic = 1328 329 fname = fsDir + path[len(urlDir):]330 start_url_var = cpg.request.browserUrl.find('?')331 if start_url_var != -1: fname = fname + cpg.request.browserUrl[start_url_var:]332 try:333 stat = os.stat(fname)334 except OSError:335 raise cperror.NotFound(path)336 modifTime = stat.st_mtime337 338 strModifTime = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(modifTime))339 340 # Check if browser sent "if-modified-since" in request header341 if cpg.request.headerMap.has_key('If-Modified-Since'):342 # Check if if-modified-since date is the same as strModifTime343 if cpg.request.headerMap['If-Modified-Since'] == strModifTime:344 cpg.response.headerMap = {345 'Status': 304,346 'protocolVersion': cpg.config.get('server', 'protocolVersion'),347 'Date': cpg.response.headerMap['Date']}348 cpg.response.body = []349 sendResponse(wfile)350 return351 352 cpg.response.headerMap['Last-Modified'] = strModifTime353 # Set Content-Length and use an iterable (file object)354 # this way CP won't load the whole file in memory355 cpg.response.headerMap['Content-Length'] = stat[6]356 cpg.response.body = open(fname, 'rb')357 # Set content-type based on filename extension358 i = path.rfind('.')359 if i != -1: ext = path[i:]360 else: ext = ""361 contentType = mimetypes.types_map.get(ext, "text/plain")362 cpg.response.headerMap['Content-Type'] = contentType363 sendResponse(wfile)364 return365 366 320 # Get session data 367 if cpg.config.get('session ', 'storageType') and not cpg.request.isStatic:321 if cpg.config.get('session.storageType') and not cpg.request.isStatic: 368 322 now = time.time() 369 323 # First, get sessionId from cookie 370 try: sessionId = cpg.request.simpleCookie[cpg.config.get('session ', 'cookieName')].value324 try: sessionId = cpg.request.simpleCookie[cpg.config.get('session.cookieName')].value 371 325 except: sessionId=None 372 326 if sessionId: … … 388 342 cpg.request.sessionMap['_sessionId'] = sessionId 389 343 390 cpg.response.simpleCookie[cpg.config.get('session', 'cookieName')] = sessionId 391 cpg.response.simpleCookie[cpg.config.get('session', 'cookieName')]['path'] = '/' 392 cpg.response.simpleCookie[cpg.config.get('session', 'cookieName')]['version'] = 1 393 394 try: 395 func, objectPathList, virtualPathList = mapPathToObject() 396 except IndexRedirect, inst: 397 # For an IndexRedirect, we don't go through the regular 398 # mechanism: we return the redirect immediately 399 newUrl = urlparse.urljoin(cpg.request.base, inst.args[0]) 400 wfile.write('%s 302\r\n' % (cpg.response.headerMap['protocolVersion'])) 401 cpg.response.headerMap['Location'] = newUrl 402 for key, valueList in cpg.response.headerMap.items(): 403 if key not in ('Status', 'protocolVersion'): 404 if type(valueList) != type([]): valueList = [valueList] 405 for value in valueList: 406 wfile.write('%s: %s\r\n'%(key, value)) 407 wfile.write('\r\n') 408 return 409 410 # Remove "root" from objectPathList and join it to get objectPath 411 cpg.request.objectPath = '/' + '/'.join(objectPathList[1:]) 412 body = func(*(virtualPathList + cpg.request.paramList), **(cpg.request.paramMap)) 344 cpg.response.simpleCookie[cpg.config.get('session.cookieName')] = sessionId 345 cpg.response.simpleCookie[cpg.config.get('session.cookieName')]['path'] = '/' 346 cpg.response.simpleCookie[cpg.config.get('session.cookieName')]['version'] = 1 347 348 if cpg.response.body is None: 349 try: 350 func, objectPathList, virtualPathList = mapPathToObject() 351 except IndexRedirect, inst: 352 # For an IndexRedirect, we don't go through the regular 353 # mechanism: we return the redirect immediately 354 newUrl = urlparse.urljoin(cpg.request.base, inst.args[0]) 355 wfile.write('%s 302\r\n' % (cpg.response.headerMap['protocolVersion'])) 356 cpg.response.headerMap['Location'] = newUrl 357 for key, valueList in cpg.response.headerMap.items(): 358 if key not in ('Status', 'protocolVersion'): 359 if type(valueList) != type([]): valueList = [valueList] 360 for value in valueList: 361 wfile.write('%s: %s\r\n'%(key, value)) 362 wfile.write('\r\n') 363 return 364 365 # Remove "root" from objectPathList and join it to get objectPath 366 cpg.request.objectPath = '/' + '/'.join(objectPathList[1:]) 367 body = func(*(virtualPathList + cpg.request.paramList), **(cpg.request.paramMap)) 368 else: 369 body = cpg.response.body 413 370 414 371 # builds a uniform return type trunk/cherrypy/lib/filter/basefilter.py
r141 r202 27 27 """ 28 28 29 class InternalRedirect(Exception): pass30 29 class RequestHandled(Exception): pass 31 30 … … 56 55 pass 57 56 57 def beforeErrorResponse(self): 58 """ Called before starting to write response, after _cpOnError has 59 been called 60 """ 61 pass 62 63 def afterErrorResponse(self): 64 """ Called after writing the response, after _cpOnError has 65 been called 66 """ 67 pass 68 trunk/cherrypy/lib/filter/baseurlfilter.py
r129 r202 28 28 29 29 from basefilter import BaseInputFilter 30 from cherrypy import cpg31 30 32 31 class BaseUrlFilter(BaseInputFilter): … … 36 35 """ 37 36 38 def __init__(self, baseUrl = 'http://localhost', useXForwardedHost = True): 39 # New baseUrl 40 self.baseUrl = baseUrl 41 self.useXForwardedHost = useXForwardedHost 37 # def __init__(self, baseUrl = 'http://localhost', useXForwardedHost = True): 38 # # New baseUrl 39 # self.baseUrl = baseUrl 40 # self.useXForwardedHost = useXForwardedHost 41 42 def setConfig(self): 43 # We have to dynamically import cpg because Python can't handle 44 # circular module imports :-( 45 global cpg 46 from cherrypy import cpg 47 cpg.threadData.baseUrlFilterOn = cpg.config.get('baseUrlFilter', False, cast='bool') 48 cpg.threadData.baseUrlFilterBaseUrl = cpg.config.get('baseUrlFilter.baseUrl', 'http://localhost') 49 cpg.threadData.baseUrlFilterUseXForwardedHost = cpg.config.get('baseUrlFilter.useXForwardedHost', True, cast='bool') 42 50 43 51 def afterRequestHeader(self): 44 if self.useXForwardedHost: 45 newBaseUrl = cpg.request.headerMap.get("X-Forwarded-Host", self.baseUrl) 52 if not cpg.threadData.baseUrlFilterOn: 53 return 54 if cpg.threadData.baseUrlFilterUseXForwardedHost: 55 newBaseUrl = cpg.request.headerMap.get("X-Forwarded-Host", cpg.threadData.baseUrlFilterBaseUrl) 46 56 else: 47 newBaseUrl = self.baseUrl57 newBaseUrl = cpg.threadData.baseUrlFilterBaseUrl 48 58 if newBaseUrl.find("://") == -1: 49 59 # add http:// or https:// if needed trunk/cherrypy/lib/filter/cachefilter.py
r142 r202 32 32 import cStringIO 33 33 34 from basefilter import BaseInputFilter, RequestHandled 35 from cherrypy import cpg 34 from basefilter import BaseInputFilter, BaseOutputFilter, RequestHandled 36 35 37 36 def defaultCacheKey(): … … 139 138 self.cache[objKey] = (expirationTime, lastModified, obj) 140 139 141 class CacheInputFilter(BaseInputFilter): 140 class SetConfig: 141 def setConfig(self): 142 # We have to dynamically import cpg because Python can't handle 143 # circular module imports :-( 144 global cpg 145 from cherrypy import cpg 146 cpg.threadData.cacheFilterOn = cpg.config.get('cacheFilter', False, cast='bool') 147 if cpg.threadData.cacheFilterOn and not hasattr(cpg, '_cache'): 148 cpg._cache = self.CacheClass(self.key, self.delay, 149 self.maxobjsize, self.maxsize, self.maxobjects) 150 151 152 class CacheInputFilter(BaseInputFilter, SetConfig): 142 153 """ 143 154 Works on the input chain. If the page is already stored in the cache … … 156 167 maxobjects=1000 # 1000 objects 157 168 ): 158 cpg._cache = CacheClass(key, delay, maxobjsize, maxsize, maxobjects) 169 self.CacheClass = CacheClass 170 self.key = key 171 self.delay = delay 172 self.maxobjsize = maxobjsize 173 self.maxsize = maxsize 174 self.maxobjects = maxobjects 159 175 160 176 def afterRequestBody(self): 161 177 """ Checks if the page is already in the cache """ 178 if not cpg.threadData.cacheFilterOn: 179 return 162 180 cacheData = cpg._cache.get() 163 181 if cacheData: … … 165 183 # found a hit! check the if-modified-since request header 166 184 modifiedSince = cpg.request.headerMap.get('If-Modified-Since', None) 167 print "Cache hit: If-Modified-Since=%s, lastModified=%s" % (modifiedSince, lastModified) 168 if modifiedSince == lastModified: 185 # print "Cache hit: If-Modified-Since=%s, lastModified=%s" % (modifiedSince, lastModified) 186 if (modifiedSince is not None) and \ 187 (modifiedSince == lastModified): 169 188 cpg._cache.totNonModified += 1 170 189 # the code below was borrowed from the sendResponse function 171 190 # it should be refactored & put into a function to allow reuse 172 cpg.response.wfile.write('%s %s\r\n' % (cpg.config Option.protocolVersion, 304))191 cpg.response.wfile.write('%s %s\r\n' % (cpg.config.get('server.protocolVersion'), 304)) 173 192 # the code below doesn't work because the data isn't available at this point... 174 193 #cpg.response.wfile.write('%s: %s\r\n' % ('Date', cpg.request.headerMap['Date'])) … … 185 204 cpg.threadData.cacheable = True 186 205 187 class CacheOutputFilter( object):206 class CacheOutputFilter(BaseOutputFilter, SetConfig): 188 207 """ 189 208 Works on the output chain. Stores the content of the page in the cache. … … 198 217 is written. 199 218 """ 219 if not cpg.threadData.cacheFilterOn: 220 return 200 221 if isinstance(cpg.response.wfile, Tee): 201 222 if cpg.threadData.cacheable: … … 210 231 Close & fix the cache entry after content was fully written 211 232 """ 233 if not cpg.threadData.cacheFilterOn: 234 return 212 235 if isinstance(cpg.response.wfile, Tee): 213 236 wrapper = cpg.response.wfile trunk/cherrypy/lib/filter/decodingfilter.py
r170 r202 28 28 29 29 from basefilter import BaseInputFilter 30 from cherrypy import cpg31 import types32 30 33 31 class DecodingFilter(BaseInputFilter): … … 36 34 """ 37 35 38 def __init__(self, encoding = 'utf-8'): 39 self.encoding = encoding 36 # def __init__(self, encoding = 'utf-8'): 37 # self.encoding = encoding 38 39 def setConfig(self): 40 # We have to dynamically import cpg because Python can't handle 41 # circular module imports :-( 42 global cpg 43 from cherrypy import cpg 44 cpg.threadData.decodingFilterOn = cpg.config.get('decodingFilter', False, cast='bool') 45 cpg.threadData.decodingFilterEncoding = cpg.config.get('decodingFilter.encoding', 'utf-8') 40 46 41 47 def afterRequestBody(self): 48 if not cpg.threadData.decodingFilterOn: 49 return 42 50 for key, value in cpg.request.paramMap.items(): 43 51 if cpg.request.filenameMap.get(key): … … 46 54 if isinstance(value, list): 47 55 # value is a list: decode each element 48 newValue = [v.decode( self.encoding) for v in value]56 newValue = [v.decode(cpg.threadData.decodingFilterEncoding) for v in value] 49 57 else: 50 58 # value is a regular string: decode it 51 newValue = value.decode( self.encoding)59 newValue = value.decode(cpg.threadData.decodingFilterEncoding) 52 60 cpg.request.paramMap[key] = newValue 53 61 trunk/cherrypy/lib/filter/encodingfilter.py
r141 r202 28 28 29 29 from basefilter import BaseOutputFilter 30 from cherrypy import cpg31 30 import types 32 31 … … 35 34 Filter that automatically encodes the response. 36 35 """ 37 38 def __init__(self, encoding = 'utf-8', mimeTypeList = ['text/html']): 39 self.encoding = encoding 40 self.mimeTypeList = mimeTypeList 36 def setConfig(self): 37 # We have to dynamically import cpg because Python can't handle 38 # circular module imports :-( 39 global cpg 40 from cherrypy import cpg 41 cpg.threadData.encodingFilterOn = cpg.config.get('encodingFilter', False, cast='bool') 42 cpg.threadData.encodingFilterEncoding = cpg.config.get('encodingFilter.encoding', 'utf-8') 43 cpg.threadData.encodingFilterMimeTypeList = cpg.config.get('encodingFilter.mimeTypeList', ['text/html'], cast='list') 41 44 42 45 def beforeResponse(self): 46 if not cpg.threadData.encodingFilterOn: 47 return 43 48 contentType = cpg.response.headerMap.get("Content-Type") 44 49 if contentType: 45 50 ctlist = contentType.split(';')[0] 46 if (ctlist in self.mimeTypeList):51 if (ctlist in cpg.threadData.encodingFilterMimeTypeList): 47 52 # Add "charset=..." to response Content-Type header 48 53 if contentType and 'charset' not in contentType: 49 cpg.response.headerMap["Content-Type"] += ";charset=%s" % self.encoding54 cpg.response.headerMap["Content-Type"] += ";charset=%s" % cpg.threadData.encodingFilterEncoding 50 55 # Return a generator that encodes the sequence 51 56 cpg.response.body = self.encode_body(cpg.response.body) … … 53 58 def encode_body(self, body): 54 59 for line in body: 55 yield line.encode( self.encoding)60 yield line.encode(cpg.threadData.encodingFilterEncoding) trunk/cherrypy/lib/filter/gzipfilter.py
r108 r202 31 31 import time 32 32 from basefilter import BaseOutputFilter 33 from cherrypy import cpg34 33 35 34 class GzipFilter(BaseOutputFilter): … … 37 36 Filter that gzips the response. 38 37 """ 39 40 def __init__(self, mimeTypeList = ['text/html'], compresslevel=9): 41 # List of mime-types to compress 42 self.mimeTypeList = mimeTypeList 43 self.compresslevel = compresslevel 38 def setConfig(self): 39 # We have to dynamically import cpg because Python can't handle 40 # circular module imports :-( 41 global cpg 42 from cherrypy import cpg 43 cpg.threadData.gzipFilterOn = cpg.config.get('gzipFilter', False, cast='bool') 44 cpg.threadData.gzipFilterMimeTypeList = cpg.config.get('gzipFilter.mimeTypeList', ['text/html'], cast='list') 45 cpg.threadData.gzipFilterCompressLevel = cpg.config.get('gzipFilter.compresslevel', 9, cast='int') 44 46 45 47 def beforeResponse(self): 48 if not cpg.threadData.gzipFilterOn: 49 return 46 50 if not cpg.response.body: 47 51 # Response body is empty (might be a 304 for instance) … … 49 53 ct = cpg.response.headerMap.get('Content-Type').split(';')[0] 50 54 ae = cpg.request.headerMap.get('Accept-Encoding', '') 51 if (ct in self.mimeTypeList) and ('gzip' in ae):55 if (ct in cpg.threadData.gzipFilterMimeTypeList) and ('gzip' in ae): 52 56 # Set header 53 57 cpg.response.headerMap['Content-Encoding'] = 'gzip' … … 77 81 crc = zlib.crc32("") 78 82 size = 0 79 zobj = zlib.compressobj( self.compresslevel, zlib.DEFLATED, -zlib.MAX_WBITS, zlib.DEF_MEM_LEVEL, 0)83 zobj = zlib.compressobj(cpg.threadData.gzipFilterCompressLevel, zlib.DEFLATED, -zlib.MAX_WBITS, zlib.DEF_MEM_LEVEL, 0) 80 84 for line in body: 81 85 s
