Changeset 5
- Timestamp:
- 11/20/04 10:20:21
- Files:
-
- ChangeLog.txt (modified) (2 diffs)
- cherrypy/_cpconfig.py (modified) (7 diffs)
- cherrypy/_cpdefaults.py (modified) (1 diff)
- cherrypy/_cphttptools.py (modified) (10 diffs)
- cherrypy/_cputil.py (modified) (1 diff)
- cherrypy/cperror.py (modified) (1 diff)
- cherrypy/lib/aspect.pyc (deleted)
- cherrypy/lib/filter/encodingfilter.py (added)
- cherrypy/lib/filter/generatorfilter.py (added)
- cherrypy/lib/filter/gzipfilter.py (modified) (1 diff)
- cherrypy/lib/httptools.pyc (deleted)
- cherrypy/tutorial/tutorial09.py (modified) (1 diff)
- cherrypy/unittest/testFilter1.py (moved) (moved from cherrypy/unittest/testGzipFilter.py) (2 diffs)
- cherrypy/unittest/testsite.py (deleted)
- cherrypy/unittest/unittest.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
ChangeLog.txt
r1 r5 1 * Check that response is a string *after* filters have been applied (ticket #28) (Remi) 2 * Removed all XML-RPC references from the core: it is now a filter (ticket #30) (Remi) 3 * Removed Generator processing for the core: it is now a filter (Remi) 4 * Removed "response encoding" from the core: it is now in a filter (ticket #31) (Remi) 1 5 * Implemented filters and a couple of sample filters (Remi) 2 6 * Fixed "cleanUpOldSessions" bug (ticket #12) (Remi) … … 7 11 8 12 2004/10/13: 9 * First alpha release of CherryPy-2 13 * First alpha release of CherryPy-2 (Remi) 10 14 cherrypy/_cpconfig.py
r1 r5 59 59 cpg.configOption.sslVerifyDepth = 1 60 60 61 # Variable used to determine what types of request to accept62 cpg.configOption.typeOfRequests = ('web', )63 64 61 # Variable used to flush cache 65 62 cpg.configOption.flushCacheDelay=0 … … 77 74 cpg.configOption.sessionCookieName = "CherryPySession" 78 75 cpg.configOption.sessionStorageFileDir = "" 79 80 # Variable used to change default encoding81 cpg.configOption.encoding = "UTF-8"82 76 83 77 def parseConfigFile(configFile = None, parsedConfigFile = None): … … 115 109 ('server', 'sslCACertificateFile', 'str'), 116 110 ('server', 'sslVerifyDepth', 'int'), 117 ('server', 'typeOfRequests', 'str'),118 ('server', 'encoding', 'str'),119 111 ('session', 'storageType', 'str'), 120 112 ('session', 'timeout', 'float'), … … 156 148 _cpLogMessage(" forking: %s" % cpg.configOption.forking, 'CONFIG') 157 149 _cpLogMessage(" sslKeyFile: %s" % cpg.configOption.sslKeyFile, 'CONFIG') 158 _cpLogMessage(" encoding: %s" % cpg.configOption.encoding, 'CONFIG')159 150 if cpg.configOption.sslKeyFile: 160 151 _cpLogMessage(" sslCertificateFile: %s" % cpg.configOption.sslCertificateFile, 'CONFIG') … … 162 153 _cpLogMessage(" sslCACertificateFile: %s" % cpg.configOption.sslCACertificateFile, 'CONFIG') 163 154 _cpLogMessage(" sslVerifyDepth: %s" % cpg.configOption.sslVerifyDepth, 'CONFIG') 164 _cpLogMessage(" typeOfRequests: %s"%str(cpg.configOption.typeOfRequests), 'CONFIG')165 155 _cpLogMessage(" flushCacheDelay: %s min" % cpg.configOption.flushCacheDelay, 'CONFIG') 166 156 _cpLogMessage(" sessionStorageType: %s" % cpg.configOption.sessionStorageType, 'CONFIG') … … 185 175 from OpenSSL import SSL 186 176 except: raise "CherryError: PyOpenSSL 0.5.1 or later must be installed to use SSL. You can get it from http://pyopenssl.sourceforge.net" 187 if 'xmlRpc' in _typeOfRequests:188 try:189 global xmlrpclib190 import xmlrpclib191 except: raise "CherryError: xmlrpclib must be installed to use XML-RPC. It is included in Python-2.2 and higher, or else you can get it from http://www.pythonware.com"192 177 if _socketPort and _socketFile: raise "CherryError: In configuration file: socketPort and socketFile conflict with each other" 193 178 if not _socketFile and not _socketPort: _socketPort=8000 # Default port … … 202 187 except: pass 203 188 204 for typeOfRequest in _typeOfRequests:205 if typeOfRequest not in ('xmlRpc', 'web'): raise "CherryError: Configuration file an invalid typeOfRequest: '%s'"%typeOfRequest206 207 189 if _sessionStorageType not in ('', 'custom', 'ram', 'file', 'cookie'): raise "CherryError: Configuration file an invalid sessionStorageType: '%s'"%_sessionStorageType 208 190 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" cherrypy/_cpdefaults.py
r1 r5 42 42 cpg.response.body = bodyFile.getvalue() 43 43 cpg.response.headerMap['Content-Type'] = 'text/plain' 44 if cpg.request.isXmlRpc:45 # Special case for XML-RPC:46 cpg.response.body = xmlrpclib.dumps(xmlrpclib.Fault(1, response.body))47 cpg.response.headerMap['Content-Type'] = 'text/xml'48 49 cpg.response.headerMap["Content-Type"] = "text/plain"50 44 51 45 def _cpInitThread(numThread): pass cherrypy/_cphttptools.py
r1 r5 35 35 cpg.request.fileTypeMap = {} 36 36 cpg.request.paramTuple = () 37 cpg.request.isXmlRpc = 038 37 i = cpg.request.path.find('?') 39 38 if i != -1: … … 75 74 else: data="" 76 75 77 cpg.request.isXmlRpc=0 78 # Try to parse request body as an XML-RPC call 79 if 'xmlRpc' in cpg.configOption.typeOfRequests and data and cpg.request.headerMap.get("Content-Type","") == "text/xml": 80 xmlRpcPathList = [] 81 if cpg.request.path == 'RPC2': pass 82 elif cpg.request.path.find('/') > -1: xmlRpcPathList = cpg.request.path.split('/') 83 elif not cpg.request.path: pass 84 else: xmlRpcPathList = [request.path] 85 try: 86 try: cpg.request.paramTuple,thisXmlRpcMethod=xmlrpclib.loads(data) 87 except: raise "XML-RPC ERROR" 88 thisXmlRpcMethod = str(thisXmlRpcMethod) # Get rid of unicode 89 cpg.request.isXmlRpc=1 # If parsing worked, it is an XML-RPC request 90 xmlRpcPathList += thisXmlRpcMethod.split('.') 91 except "XML-RPC ERROR": 92 # error reading data; must not have been an xmlrpc file 93 pass 94 95 if cpg.request.isXmlRpc: 96 cpg.request.path = '/'.join(xmlRpcPathList) 97 else: 98 # It's a normal browser call 99 # Put data in a StringIO so FieldStorage can read it 100 newRfile = StringIO.StringIO(data) 101 # Create a copy of headerMap with lowercase keys because 102 # FieldStorage doesn't work otherwise 103 lowerHeaderMap = {} 104 for key, value in cpg.request.headerMap.items(): 105 lowerHeaderMap[key.lower()] = value 106 forms = cgi.FieldStorage(fp = newRfile, headers = lowerHeaderMap, environ = {'REQUEST_METHOD':'POST'}, keep_blank_values = 1) 107 for key in forms.keys(): 108 # Check if it's a list or not 109 valueList = forms[key] 110 if type(valueList) == type([]): 111 # It's a list of values 112 cpg.request.paramMap[key] = [] 113 cpg.request.filenameMap[key] = [] 114 cpg.request.fileTypeMap[key] = [] 115 for item in valueList: 116 cpg.request.paramMap[key].append(item.value) 117 cpg.request.filenameMap[key].append(item.filename) 118 cpg.request.fileTypeMap[key].append(item.type) 119 else: 120 # It's a single value 121 # In case it's a file being uploaded, we save the filename in a map (user might need it) 122 cpg.request.paramMap[key] = valueList.value 123 cpg.request.filenameMap[key] = valueList.filename 124 cpg.request.fileTypeMap[key] = valueList.type 76 # Put data in a StringIO so FieldStorage can read it 77 newRfile = StringIO.StringIO(data) 78 # Create a copy of headerMap with lowercase keys because 79 # FieldStorage doesn't work otherwise 80 lowerHeaderMap = {} 81 for key, value in cpg.request.headerMap.items(): 82 lowerHeaderMap[key.lower()] = value 83 forms = cgi.FieldStorage(fp = newRfile, headers = lowerHeaderMap, environ = {'REQUEST_METHOD':'POST'}, keep_blank_values = 1) 84 for key in forms.keys(): 85 # Check if it's a list or not 86 valueList = forms[key] 87 if type(valueList) == type([]): 88 # It's a list of values 89 cpg.request.paramMap[key] = [] 90 cpg.request.filenameMap[key] = [] 91 cpg.request.fileTypeMap[key] = [] 92 for item in valueList: 93 cpg.request.paramMap[key].append(item.value) 94 cpg.request.filenameMap[key].append(item.filename) 95 cpg.request.fileTypeMap[key].append(item.type) 96 else: 97 # It's a single value 98 # In case it's a file being uploaded, we save the filename in a map (user might need it) 99 cpg.request.paramMap[key] = valueList.value 100 cpg.request.filenameMap[key] = valueList.filename 101 cpg.request.fileTypeMap[key] = valueList.type 125 102 126 103 def applyFilterList(methodName): … … 192 169 _cputil.getSpecialFunction('_cpSaveSessionData')(sessionId, cpg.request.sessionMap, expirationTime) 193 170 171 # Set the content-length 172 if cpg.response.headerMap.has_key('Content-Length') and cpg.response.headerMap['Content-Length']==0: 173 cpg.response.headerMap['Content-Length'] = len(cpg.response.body) 174 194 175 wfile.write('%s %s\r\n' % (cpg.response.headerMap['protocolVersion'], cpg.response.headerMap['Status'])) 195 176 for key, valueList in cpg.response.headerMap.items(): … … 198 179 for value in valueList: 199 180 wfile.write('%s: %s\r\n'%(key, value)) 181 200 182 # Send response cookies 201 183 cookie = cpg.response.simpleCookie.output() 202 # print "Sending back cookie:", cookie203 184 if cookie: 204 185 wfile.write(cookie+'\r\n') … … 208 189 209 190 applyFilterList('beforeResponseFullBody') 191 192 # Check that the response body is a string 193 if type(cpg.response.body) != types.StringType: 194 raise cperror.WrongResponseType 210 195 211 196 wfile.write(cpg.response.body) … … 220 205 cpg.response.wfile = wfile 221 206 cpg.response.sendResponse = 1 222 223 # Default encoding224 cpg.response.encoding = cpg.configOption.encoding225 207 226 208 if cpg.configOption.sslKeyFile: … … 273 255 f=open(fname, 'rb') 274 256 cpg.response.body = f.read() 275 cpg.response.headerMap['Content-Length'] = len(cpg.response.body)276 257 f.close() 277 258 # Set content-type based on filename extension … … 328 309 if not path: 329 310 pathList = [] 330 elif cpg.request.isXmlRpc:331 pathList = path.split('.')332 311 else: 333 312 pathList = path.split('/') … … 397 376 raise cperror.NotFound 398 377 399 if cpg.request.isXmlRpc: 400 cpg.response.body = func(*(cpg.request.paramTuple)) 401 else: 402 # XXX 403 myPath += '/' 404 if len(myPath) > 1: 405 myPath = '/' + myPath 406 407 cpg.request.objectPath = myPath 408 cpg.request.virtualPath = cpg.request.path[len(myPath)-1:] 409 cpg.response.body = func(**(cpg.request.paramMap)) 410 411 if cpg.request.isXmlRpc: 412 # Marshall the result if it's an XML-RPC call 413 # Wrap the response into a singleton tuple 414 cpg.response.body = (response.body,) 415 cpg.response.body = xmlrpclib.dumps(response.body, methodresponse=1) 416 # Response type is text/xml for an XML-RPC call 417 cpg.response.headerMap["Content-Type"]="text/xml" 418 419 # check if results are generators 420 # don't forget that python2.1 doesn't have generators 421 if isinstance(cpg.response.body, types.GeneratorType): 422 # makes a list of the generator. it's easier but less efficient than to 423 # loop over the iterator while writing to the wfile. This code does not 424 # check if all lines are strings. 425 cpg.response.body = "".join(list(cpg.response.body)) 426 427 elif not isinstance(cpg.response.body, types.StringTypes): 428 raise "CherryError: The method didn't return a string!" # TODO 429 430 # if it's unicode, encode it and specify the encoding in the content-type header 431 elif isinstance(cpg.response.body, unicode): # Potential gotcha: on jython, type("") == type(u"") !! 432 # extract the encoding from the content-type header if present 433 contentType = cpg.response.headerMap["Content-Type"].split(";") 434 if len(contentType)>1: 435 csdef = contentType[1].split("=") 436 if len(csdef)>1 and csdef[0].strip() == "charset": 437 cpg.response.headerMap["Content-Type"] = contentType[0].strip() 438 cpg.response.encoding = csdef[1].strip() 439 440 cpg.response.body = cpg.response.body.encode(cpg.response.encoding) 441 cpg.response.headerMap["Content-Type"] += "; charset=%s" % cpg.response.encoding 442 443 # if it's something different than a string, bail out 444 elif type(cpg.response.body) != types.StringType: 445 raise "CherryError: The method didn't return a string (returned type: %s) !" % type(cpg.response.body) 446 447 if cpg.response.headerMap.has_key('Content-Length') and cpg.response.headerMap['Content-Length']==0: 448 cpg.response.headerMap['Content-Length'] = len(cpg.response.body) 378 myPath += '/' 379 if len(myPath) > 1: 380 myPath = '/' + myPath 381 382 cpg.request.objectPath = myPath 383 cpg.request.virtualPath = cpg.request.path[len(myPath)-1:] 384 cpg.response.body = func(**(cpg.request.paramMap)) 449 385 450 386 if cpg.response.sendResponse: … … 458 394 return sha.sha(s).hexdigest() 459 395 396 cherrypy/_cputil.py
r1 r5 62 62 path = '' 63 63 if path: 64 if cpg.request.isXmlRpc: 65 pathList = path.split('.') 66 else: 67 pathList = path.split('/') 64 pathList = path.split('/') 68 65 69 66 obj = cpg.root cherrypy/cperror.py
r1 r5 28 28 """ Happens when a URL couldn't be mapped to any class.method """ 29 29 pass 30 31 class WrongResponseType(Error): 32 """ Happens when the cpg.response.body is not a string """ 33 pass cherrypy/lib/filter/gzipfilter.py
r1 r5 26 26 27 27 def beforeResponse(self): 28 ct = cpg.response.headerMap.get('Content-Type') 28 ct = cpg.response.headerMap.get('Content-Type').split(';')[0] 29 29 ae = cpg.request.headerMap.get('Accept-Encoding', '') 30 30 if (ct in self.mimeTypeList) and ('gzip' in ae): cherrypy/tutorial/tutorial09.py
r1 r5 9 9 10 10 from cherrypy import cpg 11 from cherrypy.lib.filter import generatorfilter 11 12 12 13 class GeneratorDemo: 14 _cpFilterList = [generatorfilter.GeneratorFilter()] 13 15 def header(self): 14 16 return "<html><body><h2>Generators rule!</h2>" cherrypy/unittest/testFilter1.py
r4 r5 13 13 import helper, gzip, StringIO 14 14 15 code = """15 code = r""" 16 16 from cherrypy import cpg 17 17 import cherrypy.lib.filter.gzipfilter as gzipfilter 18 import cherrypy.lib.filter.encodingfilter as encodingfilter 19 import cherrypy.lib.filter.generatorfilter as generatorfilter 20 europoundUnicode = u'\x80\xa3' 18 21 class Root: 19 _cpFilterList = [gzipfilter.GzipFilter()] 22 _cpFilterList = [ 23 generatorfilter.GeneratorFilter(), 24 encodingfilter.EncodingFilter(), 25 gzipfilter.GzipFilter() 26 ] 20 27 def index(self): 21 return "Hello, world" 28 yield u"Hello," 29 yield u"world" 30 yield europoundUnicode 22 31 index.exposed = True 23 32 cpg.root = Root() … … 25 34 """ 26 35 config = "" 27 expectedResult = "" 36 europoundUnicode = u'\x80\xa3' 37 expectedResult = (u"Hello," + u"world" + europoundUnicode).encode('utf-8') 28 38 29 39 def test(infoMap, failedList, skippedList): 30 print " Testing Gzip Filter...",40 print " Testing Filters (1) ...", 31 41 zbuf = StringIO.StringIO() 32 42 zfile = gzip.GzipFile(mode='wb', fileobj = zbuf, compresslevel = 9) 33 zfile.write( "Hello, world")43 zfile.write(expectedResult) 34 44 zfile.close() 35 45 # Gzip compression doesn't always return the same exact result ! cherrypy/unittest/unittest.py
r1 r5 81 81 testList = [ 82 82 'testObjectMapping', 83 'test GzipFilter',83 'testFilter1', 84 84 ] 85 85

