Changeset 204
- Timestamp:
- 05/22/05 16:31:26
- Files:
-
- branches/ticket-132/CHANGELOG.txt (modified) (2 diffs)
- branches/ticket-132/MANIFEST.in (modified) (1 diff)
- branches/ticket-132/README.txt (modified) (2 diffs)
- branches/ticket-132/cherrypy/__init__.py (modified) (1 diff)
- branches/ticket-132/cherrypy/_cpconfig.py (modified) (2 diffs)
- branches/ticket-132/cherrypy/_cpdefaults.py (modified) (9 diffs)
- branches/ticket-132/cherrypy/_cphttpserver.py (modified) (4 diffs)
- branches/ticket-132/cherrypy/_cphttptools.py (modified) (19 diffs)
- branches/ticket-132/cherrypy/_cpserver.py (modified) (2 diffs)
- branches/ticket-132/cherrypy/_cpthreadinglocal.py (copied) (copied from trunk/cherrypy/_cpthreadinglocal.py)
- branches/ticket-132/cherrypy/cperror.py (modified) (1 diff)
- branches/ticket-132/cherrypy/cpg.py (modified) (1 diff)
- branches/ticket-132/cherrypy/lib/csauthenticate.py (modified) (9 diffs)
- branches/ticket-132/cherrypy/lib/filter/basefilter.py (modified) (2 diffs)
- branches/ticket-132/cherrypy/lib/filter/baseurlfilter.py (modified) (2 diffs)
- branches/ticket-132/cherrypy/lib/filter/cachefilter.py (modified) (7 diffs)
- branches/ticket-132/cherrypy/lib/filter/decodingfilter.py (modified) (2 diffs)
- branches/ticket-132/cherrypy/lib/filter/encodingfilter.py (modified) (3 diffs)
- branches/ticket-132/cherrypy/lib/filter/gzipfilter.py (modified) (4 diffs)
- branches/ticket-132/cherrypy/lib/filter/logdebuginfofilter.py (modified) (2 diffs)
- branches/ticket-132/cherrypy/lib/filter/staticfilter.py (copied) (copied from trunk/cherrypy/lib/filter/staticfilter.py)
- branches/ticket-132/cherrypy/lib/filter/tidyfilter.py (modified) (5 diffs)
- branches/ticket-132/cherrypy/lib/filter/virtualhostfilter.py (modified) (2 diffs)
- branches/ticket-132/cherrypy/lib/filter/xmlrpcfilter.py (modified) (3 diffs)
- branches/ticket-132/cherrypy/lib/httptools.py (modified) (1 diff)
- branches/ticket-132/cherrypy/lib/session/basesession.py (modified) (2 diffs)
- branches/ticket-132/cherrypy/lib/session/ramsession.py (modified) (2 diffs)
- branches/ticket-132/cherrypy/test/helper.py (modified) (2 diffs)
- branches/ticket-132/cherrypy/test/static (copied) (copied from trunk/cherrypy/test/static)
- branches/ticket-132/cherrypy/test/static/index.html (copied) (copied from trunk/cherrypy/test/static/index.html)
- branches/ticket-132/cherrypy/test/style.css (copied) (copied from trunk/cherrypy/test/style.css)
- branches/ticket-132/cherrypy/test/test.py (modified) (3 diffs)
- branches/ticket-132/cherrypy/test/testBaseUrlFilter.py (copied) (copied from trunk/cherrypy/test/testBaseUrlFilter.py)
- branches/ticket-132/cherrypy/test/testCacheFilter.py (copied) (copied from trunk/cherrypy/test/testCacheFilter.py)
- branches/ticket-132/cherrypy/test/testCombinedFilters.py (copied) (copied from trunk/cherrypy/test/testCombinedFilters.py)
- branches/ticket-132/cherrypy/test/testDecodingEncodingFilter.py (copied) (copied from trunk/cherrypy/test/testDecodingEncodingFilter.py)
- branches/ticket-132/cherrypy/test/testFilter1.py (deleted)
- branches/ticket-132/cherrypy/test/testGzipFilter.py (copied) (copied from trunk/cherrypy/test/testGzipFilter.py)
- branches/ticket-132/cherrypy/test/testLogDebugInfoFilter.py (copied) (copied from trunk/cherrypy/test/testLogDebugInfoFilter.py)
- branches/ticket-132/cherrypy/test/testObjectMapping.py (modified) (4 diffs)
- branches/ticket-132/cherrypy/test/testStaticFilter.py (copied) (copied from trunk/cherrypy/test/testStaticFilter.py)
- branches/ticket-132/cherrypy/test/testVirtualHostFilter.py (modified) (1 diff)
- branches/ticket-132/cherrypy/test/testwsgiapp.py (copied) (copied from trunk/cherrypy/test/testwsgiapp.py)
- branches/ticket-132/cherrypy/tutorial/01_helloworld.py (modified) (1 diff)
- branches/ticket-132/cherrypy/tutorial/02_expose_methods.py (modified) (1 diff)
- branches/ticket-132/cherrypy/tutorial/03_get_and_post.py (modified) (1 diff)
- branches/ticket-132/cherrypy/tutorial/04_complex_site.py (modified) (1 diff)
- branches/ticket-132/cherrypy/tutorial/05_derived_objects.py (modified) (1 diff)
- branches/ticket-132/cherrypy/tutorial/06_aspects.py (modified) (1 diff)
- branches/ticket-132/cherrypy/tutorial/07_default_method.py (modified) (1 diff)
- branches/ticket-132/cherrypy/tutorial/08_sessions.py (modified) (1 diff)
- branches/ticket-132/cherrypy/tutorial/09_generators_and_yield.py (modified) (1 diff)
- branches/ticket-132/cherrypy/tutorial/README.txt (copied) (copied from trunk/cherrypy/tutorial/README.txt)
- branches/ticket-132/cherrypy/tutorial/Readme.txt (deleted)
- branches/ticket-132/cherrypy/tutorial/tutorial.conf (modified) (1 diff)
- branches/ticket-132/cherrypy/wsgiapp.py (modified) (2 diffs)
- branches/ticket-132/setup.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/ticket-132/CHANGELOG.txt
r135 r204 1 * if y is a static dir make y/a?b try and serve a file named a?b (Dan) 2 * pass threadIndex to onStartThreadList functions - ticket #91 (Remi) 3 * renamed "configDict" into "configMap" for consistency - ticket #82 (Remi) 1 * BACKWARD INCOMPATIBILITY: New config system, see http://www.cherrypy.org/wiki/ConfigSystem21 (Remi) 2 * Fixed small bug in httptools.redirect (Remi) 3 * Allow methods to return recursive generators (Remi) 4 * Methods can now return file objects which are red in 64kb chunks. (Mike) 5 6 2005-04-25: 7 * CherryPy-2.0-final released 8 * Added tests about static content and httptools.redirect (Remi) 9 * Handle %20 (and others) in static content - ticket #104 (Remi) 10 * If y is a static dir make y/a?b try and serve a file named a?b (Dan) 11 * Pass threadIndex to onStartThreadList functions - ticket #91 (Remi) 12 * Renamed "configDict" into "configMap" for consistency - ticket #82 (Remi) 4 13 * Dots in requests path are now replaced by underscores - ticket #87 (Remi) 5 14 * Improved WSGI support and added example (seems to work OK) (Peter, Remi) 6 15 * Added DecodingFilter (Remi) 7 16 * Added form module (port from CP1 Form.cpy) (Remi) 17 * Improved the way static files are being served (Remi) 8 18 9 2004 /12-29:19 2004-12-29: 10 20 * CherryPY-2.0-beta released 11 21 * xmlrpcfilter added (Remco) … … 29 39 * Fixed file upload bug (Remi) 30 40 31 2004 /10/13:41 2004-10-13: 32 42 * First alpha release of CherryPy-2 (Remi) 33 43 branches/ticket-132/MANIFEST.in
r120 r204 2 2 include CHERRYPYTEAM.txt 3 3 include *.conf 4 include cherrypy/tutorial/README.txt 5 include cherrypy/test/style.css 6 include cherrypy/test/static/index.html branches/ticket-132/README.txt
r109 r204 1 * To install, just type :1 * To install, just type (python-2.3 or later needed): 2 2 3 3 python setup.py install … … 5 5 * To learn how to use it, look at the examples under cherrypy/tutorial/ or go to http://www.cherrypy.org for more info. 6 6 7 * To run the unittest, just go to the cherrypy/test/ directory and type:7 * To run the regression tests, just go to the cherrypy/test/ directory and type: 8 8 9 9 python test.py branches/ticket-132/cherrypy/__init__.py
r101 r204 1 __version__ = '2.0.0 b'1 __version__ = '2.0.0' branches/ticket-132/cherrypy/_cpconfig.py
r194 r204 29 29 import _cputil, ConfigParser, cpg 30 30 31 from lib.unrepr import unreprWrapper 31 # Default config options 32 configMap = { 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': {} 54 }, 55 } 56 57 def update(updateMap = None, file = None): 58 if updateMap is not None: 59 for section, valueMap in updateMap.items(): 60 if section not in configMap: 61 configMap[section] = valueMap 62 else: 63 for key, value in valueMap.items(): 64 configMap[section][key] = value 65 if file is not None: 66 _load(file) 67 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 87 else: 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) 32 140 33 141 class CaseSensitiveConfigParser(ConfigParser.ConfigParser): 34 """ Sub-class of ConfigParser that keeps the case of options """ 142 """ Sub-class of ConfigParser that keeps the case of options and 143 that raises an exception if the file cannot be read 144 """ 35 145 def optionxform(self, optionstr): 36 146 return optionstr 37 38 # Known types to check types: 39 knownTypes = { 40 'server': { 41 'logToScreen': bool, 42 'socketPort' : int, 43 'reverseDNS' : bool, 44 'socketQueueSize': int, 45 'threadPool': int}, 46 'session': { 47 'sessionTimeout': int, 48 'cleanUpDelay' : bool, 49 } 50 } 51 52 53 54 def loadConfigFile(configFile = None): 147 def read(self, filenames): 148 if isinstance(filenames, basestring): 149 filenames = [filenames] 150 for filename in filenames: 151 # try: 152 # fp = open(filename) 153 # except IOError: 154 # continue 155 fp = open(filename) 156 self._read(fp, filename) 157 fp.close() 158 159 def _load(configFile = None): 55 160 """ Convert an INI file to a dictionary """ 56 161 _cpLogMessage = _cputil.getSpecialFunction('_cpLogMessage') … … 67 172 # Load INI file into cpg.configMap 68 173 for section in configParser.sections(): 69 if section not in c pg.configMap:70 c pg.configMap[section] = {}174 if section not in configMap: 175 configMap[section] = {} 71 176 for option in configParser.options(section): 72 # unrep and validate the type 73 value = unreprWrapper(configParser.get(section, option)) 74 knownType = knownTypes.get(section, {}).get(option, object) 75 if knownType == bool: 76 if value == 1 or value == 0: 77 value = bool(value) 78 79 elif value == 'on': 80 value = True 81 82 elif value == 'off': 83 value = False 84 85 if not isinstance(value, knownType): 86 raise TypeError('%s must be a %s' % (option, knownType.__name__)) 87 else: 88 cpg.configMap[section][option] = value 177 value = configParser.get(section, option) 178 configMap[section][option] = value 89 179 90 180 def outputConfigMap(): 91 181 _cpLogMessage = _cputil.getSpecialFunction('_cpLogMessage') 92 182 _cpLogMessage("Server parameters:", 'CONFIG') 93 _cpLogMessage(" server.logToScreen: %s" % cpg.getConfig('server', 'logToScreen'), 'CONFIG') 94 _cpLogMessage(" server.logFile: %s" % cpg.getConfig('server', 'logFile'), 'CONFIG') 95 _cpLogMessage(" server.protocolVersion: %s" % cpg.getConfig('server', 'protocolVersion'), 'CONFIG') 96 _cpLogMessage(" server.socketHost: %s" % cpg.getConfig('server', 'socketHost'), 'CONFIG') 97 _cpLogMessage(" server.socketPort: %s" % cpg.getConfig('server', 'socketPort'), 'CONFIG') 98 _cpLogMessage(" server.socketFile: %s" % cpg.getConfig('server', 'socketFile'), 'CONFIG') 99 _cpLogMessage(" server.reverseDNS: %s" % cpg.getConfig('server', 'reverseDNS'), 'CONFIG') 100 _cpLogMessage(" server.socketQueueSize: %s" % cpg.getConfig('server', 'socketQueueSize'), 'CONFIG') 101 _cpLogMessage(" server.threadPool: %s" % cpg.getConfig('server', 'threadPool'), 'CONFIG') 102 _cpLogMessage(" session.storageType: %s" % cpg.getConfig('session', 'storageType'), 'CONFIG') 103 if cpg.getConfig('session', 'storageType'): 104 _cpLogMessage(" session.timeout: %s min" % cpg.getConfig('session', 'timeout'), 'CONFIG') 105 _cpLogMessage(" session.cleanUpDelay: %s min" % cpg.getConfig('session', 'cleanUpDelay'), 'CONFIG') 106 _cpLogMessage(" session.cookieName: %s" % cpg.getConfig('session', 'cookieName'), 'CONFIG') 107 _cpLogMessage(" session.storageFileDir: %s" % cpg.getConfig('session', 'storageFileDir'), 'CONFIG') 108 _cpLogMessage(" staticContent: %s" % cpg.getConfig('staticContent'), 'CONFIG') 109 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') 199 _cpLogMessage(" staticContent: %s" % cpg.config.get('staticContent'), 'CONFIG') 200 201 def dummy(): 202 # Check that parameters are correct and that they don't conflict with each other 203 if _protocolVersion not in ("HTTP/1.1", "HTTP/1.0"): 204 raise "CherryError: protocolVersion must be 'HTTP/1.1' or 'HTTP/1.0'" 205 if _reverseDNS not in (0,1): raise "CherryError: reverseDNS must be '0' or '1'" 206 if _socketFile and not hasattr(socket, 'AF_UNIX'): raise "CherryError: Configuration file has socketFile, but this is only available on Unix machines" 207 if _sslKeyFile: 208 try: 209 global SSL 210 from OpenSSL import SSL 211 except: raise "CherryError: PyOpenSSL 0.5.1 or later must be installed to use SSL. You can get it from http://pyopenssl.sourceforge.net" 212 if _socketPort and _socketFile: raise "CherryError: In configuration file: socketPort and socketFile conflict with each other" 213 if not _socketFile and not _socketPort: _socketPort=8000 # Default port 214 if _sslKeyFile and not _sslCertificateFile: raise "CherryError: Configuration file has sslKeyFile but no sslCertificateFile" 215 if _sslCertificateFile and not _sslKeyFile: raise "CherryError: Configuration file has sslCertificateFile but no sslKeyFile" 216 try: sys.stdout.flush() 217 except: pass 218 219 if _sessionStorageType not in ('', 'custom', 'ram', 'file', 'cookie'): raise "CherryError: Configuration file an invalid sessionStorageType: '%s'"%_sessionStorageType 220 if _sessionStorageType in ('custom', 'ram', 'cookie') and _sessionStorageFileDir!='': raise "CherryError: Configuration file has sessionStorageType set to 'custom, 'ram' or 'cookie' but a sessionStorageFileDir is specified" 221 if _sessionStorageType=='file' and _sessionStorageFileDir=='': raise "CherryError: Configuration file has sessionStorageType set to 'file' but no sessionStorageFileDir" 222 branches/ticket-132/cherrypy/_cpdefaults.py
r203 r204 32 32 """ 33 33 34 import time, thread, os, cpg 35 #import cPickle as pickle 34 import time, thread, os 35 import cPickle as pickle 36 import cpg 36 37 37 38 def _cpLogMessage(msg, context = '', severity = 0): … … 40 41 nowTuple = time.localtime(time.time()) 41 42 nowStr = '%04d/%02d/%02d %02d:%02d:%02d' % (nowTuple[:6]) 42 if severity == 0: level = "INFO" 43 elif severity == 1: level = "WARNING" 44 elif severity == 2: level = "ERROR" 43 if severity == 0: 44 level = "INFO" 45 elif severity == 1: 46 level = "WARNING" 47 elif severity == 2: 48 level = "ERROR" 49 else: 50 lebel = "UNKNOWN" 45 51 try: 46 logToScreen = int(cpg. parsedConfigFile.get('server', 'logToScreen'))52 logToScreen = int(cpg.config.get('server.logToScreen', cast='bool')) 47 53 except: 48 54 logToScreen = True … … 50 56 if logToScreen: 51 57 print s 52 if cpg. getConfig('server', 'logFile'):53 f = open(cpg. getConfig('server','logFile'), 'ab')58 if cpg.config.get('server.logFile'): 59 f = open(cpg.config.get('server.logFile'), 'ab') 54 60 f.write(s + '\n') 55 61 f.close() … … 61 67 bodyFile = StringIO.StringIO() 62 68 traceback.print_exc(file = bodyFile) 63 cpg.response.body = bodyFile.getvalue()69 cpg.response.body = [bodyFile.getvalue()] 64 70 cpg.response.headerMap['Content-Type'] = 'text/plain' 65 71 … … 72 78 'sql' : GenericSqlSession 73 79 } 74 # robinson, this crap will be deleted soon, yay!80 # this crap will be deleted soon 75 81 ''' 76 82 def _cpSaveSessionData(sessionId, sessionData, expirationTime, … … 80 86 81 87 if threadPool is None: 82 threadPool = cpg. getConfig('server', 'threadPool')88 threadPool = cpg.config.get('server.threadPool', cast='int') 83 89 if sessionStorageType is None: 84 sessionStorageType = cpg. getConfig('session', 'storageType')90 sessionStorageType = cpg.config.get('session.storageType') 85 91 if sessionStorageFileDir is None: 86 sessionStorageFileDir = cpg. getConfig('session', 'storageFileDir')92 sessionStorageFileDir = cpg.config.get('session.storageFileDir') 87 93 88 94 t = time.localtime(expirationTime) … … 108 114 109 115 if threadPool is None: 110 threadPool = cpg. getConfig('server', 'threadPool')116 threadPool = cpg.config.get('server.threadPool', cast='int') 111 117 if sessionStorageType is None: 112 sessionStorageType = cpg. getConfig('session', 'storageType')118 sessionStorageType = cpg.config.get('session.storageType') 113 119 if sessionStorageFileDir is None: 114 sessionStorageFileDir = cpg. getConfig('session', 'storageFileDir')120 sessionStorageFileDir = cpg.config.get('session.storageFileDir') 115 121 116 122 if sessionStorageType == "ram": … … 137 143 138 144 if threadPool is None: 139 threadPool = cpg. getConfig('server', 'threadPool')145 threadPool = cpg.config.get('server.threadPool', cast='int') 140 146 if sessionStorageType is None: 141 sessionStorageType = cpg. getConfig('session', 'storageType')147 sessionStorageType = cpg.config.get('session.storageType') 142 148 if sessionStorageFileDir is None: 143 sessionStorageFileDir = cpg. getConfig('session', 'storageFileDir')149 sessionStorageFileDir = cpg.config.get('session.storageFileDir') 144 150 145 151 # Clean up old session data … … 171 177 172 178 _cpFilterList = [] 179 180 # Filters that are always included 181 from cherrypy.lib.filter import baseurlfilter, cachefilter, \ 182 decodingfilter, encodingfilter, gzipfilter, logdebuginfofilter, \ 183 staticfilter, tidyfilter, virtualhostfilter, xmlrpcfilter 184 _cpDefaultInputFilterList = [ 185 cachefilter.CacheInputFilter(), 186 logdebuginfofilter.LogDebugInfoInputFilter(), 187 virtualhostfilter.VirtualHostFilter(), 188 baseurlfilter.BaseUrlFilter(), 189 decodingfilter.DecodingFilter(), 190 staticfilter.StaticFilter(), 191 xmlrpcfilter.XmlRpcInputFilter(), 192 ] 193 _cpDefaultOutputFilterList = [ 194 xmlrpcfilter.XmlRpcOutputFilter(), 195 encodingfilter.EncodingFilter(), 196 tidyfilter.TidyFilter(), 197 logdebuginfofilter.LogDebugInfoOutputFilter(), 198 gzipfilter.GzipFilter(), 199 cachefilter.CacheOutputFilter(), 200 ] 201 branches/ticket-132/cherrypy/_cphttpserver.py
r154 r204 38 38 # If sessions are stored in files and we 39 39 # use threading, we need a lock on the file 40 if (cpg. getConfig('server', 'threadPool') > 1) and \41 cpg. getConfig('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. getConfig('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. getConfig('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. getConfig('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. getConfig('server', 'protocolVersion')59 CherryHTTPRequestHandler.protocol_version = cpg.config.get('server.protocolVersion') 60 60 61 61 run_server(CherryHTTPRequestHandler, MyCherryHTTPServer, \ 62 (cpg. getConfig('server', 'socketHost'), cpg.getConfig('server', 'socketPort')), \63 cpg. getConfig('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. getConfig('server', 'socketFile'):69 try: os.unlink(cpg. getConfig('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. getConfig('server', 'socketFile')72 if cpg. getConfig('server', 'threadPool') > 1:73 myCherryHTTPServer = ServerClass(server_address, cpg. getConfig('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. getConfig('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. getConfig('server', 'socketPort'):84 if cpg.config.get('server.socketPort', cast='int'): 85 85 onWhat = ("socket: ('%s', %s)" % 86 (cpg. getConfig('server', 'socketHost'), cpg.getConfig('server', 'socketPort')))87 else: onWhat = "socket file: %s" % cpg. getConfig('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. getConfig('server', 'reverseDNS'):115 if cpg.config.get('server.reverseDNS', cast='bool'): 116 116 return BaseHTTPServer.BaseHTTPRequestHandler.address_string(self) 117 117 else: branches/ticket-132/cherrypy/_cphttptools.py
r203 r204 28 28 29 29 import cpg, urllib, sys, time, traceback, types, StringIO, cgi, os 30 import mimetypes, sha, random, string, _cputil, cperror, Cookie 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): … … 167 160 cookHeaders(clientAddress, remoteHost, headers, requestLine) 168 161 169 cpg.request.base = "http://" + cpg.request.headerMap ['Host']162 cpg.request.base = "http://" + cpg.request.headerMap.get('Host', '') 170 163 cpg.request.browserUrl = cpg.request.base + cpg.request.browserUrl 171 164 cpg.request.isStatic = False … … 176 169 cpg.request.objectPath = None 177 170 171 applyFilterList('setConfig') 178 172 applyFilterList('afterRequestHeader') 179 173 … … 186 180 # creates some attributes on cpg.response so filters can use them 187 181 cpg.response.wfile = wfile 188 cpg.response.sendResponse = 1 189 try: 190 initRequest(clientAddress, remoteHost, requestLine, headers, rfile, wfile) 191 except basefilter.RequestHandled: 192 # request was already fully handled; it may be a cache hit 193 return 182 cpg.response.sendResponse = True 183 cpg.response.body = None 194 184 195 185 # Prepare response variables … … 198 188 date = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (weekdayname[wd], day, monthname[month], year, hh, mm, ss) 199 189 cpg.response.headerMap = { 200 "protocolVersion": cpg. getConfig('server', 'protocolVersion'),190 "protocolVersion": cpg.config.get('server.protocolVersion'), 201 191 "Status": "200 OK", 202 192 "Content-Type": "text/html", … … 209 199 210 200 try: 201 try: 202 initRequest(clientAddress, remoteHost, requestLine, headers, rfile, wfile) 203 except basefilter.RequestHandled: 204 # request was already fully handled; it may be a cache hit 205 return 206 except: 207 # exception raised in a filter. 208 # we don't have a response body yet, so create an empty one 209 cpg.response.body = [] 210 raise 211 211 handleRequest(cpg.response.wfile) 212 212 except: … … 214 214 # error reporting seems to be broken in some cases. This code is 215 215 # a helper to check it 216 print "%"*80217 traceback.print_exc()218 print "%"*80219 216 err = "" 220 217 exc_info_1 = sys.exc_info()[1] … … 226 223 227 224 # Still save session data 228 if cpg. getConfig('session', 'storageType') and not cpg.request.isStatic:225 if cpg.config.get('session.storageType') and not cpg.request.isStatic: 229 226 cpg.sessionManager.saveSessionMap() 230 227 228 applyFilterList('beforeErrorResponse') 231 229 wfile.write('%s %s\r\n' % (cpg.response.headerMap['protocolVersion'], cpg.response.headerMap['Status'])) 232 230 … … 247 245 for line in cpg.response.body: 248 246 wfile.write(line) 247 applyFilterList('afterErrorResponse') 249 248 except: 250 # TODO: in some cases exceptions and filters are conflicting;251 # error reporting seems to be broken in some cases. This code is252 # a helper to check it253 #print "%"*80254 #traceback.print_exc()255 #print "%"*80256 249 bodyFile = StringIO.StringIO() 257 250 traceback.print_exc(file = bodyFile) 258 251 body = bodyFile.getvalue() 259 wfile.write('%s 200 OK\r\n' % cpg. getConfig('server', 'protocolVersion'))252 wfile.write('%s 200 OK\r\n' % cpg.config.get('server.protocolVersion')) 260 253 wfile.write('Content-Type: text/plain\r\n') 261 254 wfile.write('Content-Length: %s\r\n' % len(body)) … … 265 258 def sendResponse(wfile): 266 259 applyFilterList('beforeResponse') 267 268 # Save session data269 if cpg.getConfig('session', 'storageType') and not cpg.request.isStatic:270 cpg.sessionManager.saveSessionMap()271 272 260 273 261 # Set the content-length … … 280 268 cpg.response.headerMap['Content-Length'] = len(cpg.response.body[0]) 281 269 270 # Save session data 271 if cpg.config.get('session.storageType') and not cpg.request.isStatic: 272 cpg.sessionManager.saveSessionMap() 273 282 274 wfile.write('%s %s\r\n' % (cpg.response.headerMap['protocolVersion'], cpg.response.headerMap['Status'])) 283 275 for key, valueList in cpg.response.headerMap.items(): … … 302 294 # Clean up expired sessions if needed: 303 295 now = time.time() 304 if (cpg. getConfig('session', 'storageType') and305 cpg. getConfig('session', 'cleanUpDelay') and306 (cpg._lastSessionCleanUpTime + cpg. getConfig('session', 'cleanUpDelay') * 60) <= now):296 if (cpg.config.get('session.storageType') and 297 cpg.config.get('session.cleanUpDelay', cast='float') and 298 (cpg._lastSessionCleanUpTime + cpg.config.get('session.cleanUpDelay', cast='float') * 60) <= now): 307 299 cpg._lastSessionCleanUpTime = now 308 300 cpg.sessionManager.cleanUpOldSessions() … … 314 306 315 307 path = cpg.request.path 316 if path.startswith('/'): path = path[1:] # Remove leading slash 317 if path.endswith('/'): path = path[:-1] # Remove trailing slash 318 319 # Handle static directories 320 for urlDir, fsDir in cpg.getConfig('staticContent').items(): 321 if path == urlDir or path[:len(urlDir)+1]==urlDir+'/': 322 323 cpg.request.isStatic = 1 324 325 fname = fsDir + path[len(urlDir):] 326 start_url_var = cpg.request.browserUrl.find('?') 327 if start_url_var != -1: fname = fname + cpg.request.browserUrl[start_url_var:] 328 try: 329 stat = os.stat(fname) 330 except OSError: 331 raise cperror.NotFound 332 modifTime = stat.st_mtime 333 334 strModifTime = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(modifTime)) 335 336 # Check if browser sent "if-modified-since" in request header 337 if cpg.request.headerMap.has_key('If-Modified-Since'): 338 # Check if if-modified-since date is the same as strModifTime 339 if cpg.request.headerMap['If-Modified-Since'] == strModifTime: 340 cpg.response.headerMap = { 341 'Status': 304, 342 'protocolVersion': cpg.configMap['server']['protocolVersion'], #robinson 343 'Date': cpg.response.headerMap['Date']} 344 cpg.response.body = [] 345 sendResponse(wfile) 346 return 347 348 cpg.response.headerMap['Last-Modified'] = strModifTime 349 # Set Content-Length and use an iterable (file object) 350 # this way CP won't load the whole file in memory 351 cpg.response.headerMap['Content-Length'] = stat[6] 352 cpg.response.body = open(fname, 'rb') 353 # Set content-type based on filename extension 354 i = path.rfind('.') 355 if i != -1: ext = path[i:] 356 else: ext = "" 357 contentType = mimetypes.types_map.get(ext, "text/plain") 358 cpg.response.headerMap['Content-Type'] = contentType 359 sendResponse(wfile) 308 if path.startswith('/'): 309 # Remove leading slash 310 path = path[1:] 311 if path.endswith('/'): 312 # Remove trailing slash 313 path = path[:-1] 314 path = urllib.unquote(path) # Replace quoted chars (eg %20) from url 315 316 # Get session data 317 if cpg.config.get('session.storageType') and not cpg.request.isStatic: 318 cpg.sessionManager.loadSessionMap() 319 if cpg.response.body is None: 320 try: 321 func, objectPathList, virtualPathList = mapPathToObject() 322 except IndexRedirect, inst: 323 # For an IndexRedirect, we don't go through the regular 324 # mechanism: we return the redirect immediately 325 newUrl = urlparse.urljoin(cpg.request.base, inst.args[0]) 326 wfile.write('%s 302\r\n' % (cpg.response.headerMap['protocolVersion'])) 327 cpg.response.headerMap['Location'] = newUrl 328 for key, valueList in cpg.response.headerMap.items(): 329 if key not in ('Status', 'protocolVersion'): 330 if type(valueList) != type([]): valueList = [valueList] 331 for value in valueList: 332 wfile.write('%s: %s\r\n'%(key, value)) 333 wfile.write('\r\n') 360 334 return 361 362 try: 363 func, objectPathList, virtualPathList = mapPathToObject() 364 except IndexRedirect, inst: 365 # For an IndexRedirect, we don't go through the regular 366 # mechanism: we return the redirect immediately 367 newUrl = canonicalizeUrl(inst.args[0]) 368 wfile.write('%s 302\r\n' % (cpg.response.headerMap['protocolVersion'])) 369 cpg.response.headerMap['Location'] = newUrl 370 for key, valueList in cpg.response.headerMap.items(): 371 if key not in ('Status', 'protocolVersion'): 372 if type(valueList) != type([]): valueList = [valueList] 373 for value in valueList: 374 wfile.write('%s: %s\r\n'%(key, value)) 375 wfile.write('\r\n') 376 return 377 378 # robinson 379 # Get session data 380 if cpg.getConfig('session', 'storageType') and not cpg.request.isStatic: 381 cpg.sessionManager.loadSessionMap() 382 383 # Remove "root" from objectPathList and join it to get objectPath 384 cpg.request.objectPath = '/' + '/'.join(objectPathList[1:]) 385 body = func(*(virtualPathList + cpg.request.paramList), **(cpg.request.paramMap)) 386 335 336 # Remove "root" from objectPathList and join it to get objectPath 337 cpg.request.objectPath = '/' + '/'.join(objectPathList[1:]) 338 body = func(*(virtualPathList + cpg.request.paramList), **(cpg.request.paramMap)) 339 else: 340 body = cpg.response.body 341 387 342 # builds a uniform return type 388 if not isinstance(body, types.GeneratorType): 343 if isinstance(body, types.FileType): 344 cpg.response.body = fileGenerator(body) 345 elif not isinstance(body, types.GeneratorType): 389 346 cpg.response.body = [body] 390 347 else: 391 cpg.response.body = body348 cpg.response.body = flattener(body) 392 349 393 350 if cpg.response.sendResponse: 394 351 sendResponse(wfile) 395 352 396 def getObjFromPath(objPathList, objCache): 353 def fileGenerator(file, chunkSize = 65536): # 65536 = 64kb 354 """ make file objects iterable generators """ 355 input = file.read(chunkSize) 356 while input: 357 yield input 358 input = file.read(chunkSize) 359 360 361 def flattener(input): 362 for x in input: 363 if not isinstance(x, types.GeneratorType): 364 yield x 365 else: 366 for y in flattener(x): 367 yield y 368 369 370 def generateSessionId(): 371 s = '' 372 for i in range(50): 373 s += random.choice(string.letters+string.digits) 374 s += '%s'%time.time() 375 return sha.sha(s).hexdigest() 376
