Changeset 1075
- Timestamp:
- 04/26/06 02:28:59
- Files:
-
- trunk/cherrypy/_cprequest.py (modified) (4 diffs)
- trunk/cherrypy/lib/caching.py (modified) (2 diffs)
- trunk/cherrypy/lib/sessions.py (modified) (1 diff)
- trunk/cherrypy/lib/static.py (modified) (2 diffs)
- trunk/cherrypy/lib/xmlrpc.py (modified) (2 diffs)
- trunk/cherrypy/test/test_core.py (modified) (1 diff)
- trunk/cherrypy/tools.py (modified) (9 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/cherrypy/_cprequest.py
r1074 r1075 27 27 28 28 self.scheme = scheme 29 self.execute_main = True30 29 self.closed = False 31 30 … … 88 87 # right away. 89 88 self.processRequestLine() 89 self.dispatch = cherrypy.config.get("dispatch") or dispatch 90 90 self.hooks.setup() 91 91 … … 104 104 try: 105 105 self.hooks.run('before_main') 106 if self. execute_main:107 self. main()106 if self.dispatch: 107 self.dispatch(self.object_path) 108 108 break 109 109 except cherrypy.InternalRedirect, ir: … … 168 168 server_v = httptools.Version.from_http(server_v) 169 169 cherrypy.response.version = min(self.version, server_v) 170 171 def main(self, path=None):172 """Obtain and set cherrypy.response.body from a page handler."""173 if path is None:174 path = self.object_path175 _dispatch = cherrypy.config.get("dispatcher") or dispatch176 _dispatch(path)177 170 178 171 def processHeaders(self): trunk/cherrypy/lib/caching.py
r1057 r1075 142 142 """Caching decorator.""" 143 143 def wrapper(*a, **kw): 144 # There's are no parameters to get(), so there's no need 145 # to merge values from config. 144 146 if not get(): 145 147 f(*a, **kw) … … 153 155 def wrapper(): 154 156 if get(): 155 cherrypy.request. execute_main = False157 cherrypy.request.dispatch = None 156 158 else: 157 159 # Note the devious technique here of adding hooks on the fly trunk/cherrypy/lib/sessions.py
r1073 r1075 414 414 sess.storage = None 415 415 416 def wrap(*args, **kwargs):417 """Make a decorator for this tool."""418 def deco(f):419 def wrapper(*a, **kw):420 result = f(*a, **kw)421 save(*args, **kwargs)422 cherrypy.request.hooks.attach('on_end_request', cleanup)423 return result424 return wrapper425 return deco426 427 def setup(conf):428 """Hook this tool into cherrypy.request using the given conf.429 430 The standard CherryPy request object will automatically call this431 method when the tool is "turned on" in config.432 """433 def wrapper():434 s = cherrypy.request._session = Session()435 for k, v in conf.iteritems():436 setattr(s, str(k), v)437 s.init()438 439 if not hasattr(cherrypy, "session"):440 cherrypy.session = SessionWrapper()441 442 cherrypy.request.hooks.attach('before_request_body', wrapper)443 cherrypy.request.hooks.attach('before_finalize', save)444 cherrypy.request.hooks.attach('on_end_request', cleanup)trunk/cherrypy/lib/static.py
r1069 r1075 166 166 return False 167 167 168 def get_dir(section, dir, root="", match="", content_types=None, index=""):168 def staticdir(section, dir, root="", match="", content_types=None, index=""): 169 169 if match and not re.search(match, cherrypy.request.object_path): 170 170 return False … … 201 201 return handled 202 202 203 def get_file(filename, root=None, match="", content_types=None):203 def staticfile(filename, root=None, match="", content_types=None): 204 204 if match and not re.search(match, cherrypy.request.object_path): 205 205 return False trunk/cherrypy/lib/xmlrpc.py
r1055 r1075 6 6 7 7 def process_body(): 8 request = cherrypy.request 9 10 cl = int(request.headers.get('Content-Length') or 0) 11 data = request.rfile.read(cl) 8 """Return (params, method) from request body.""" 12 9 try: 13 params, method = xmlrpclib.loads(data)10 return xmlrpclib.loads(cherrypy.request.body.read()) 14 11 except Exception: 15 params, method = ('ERROR PARAMS', ), 'ERRORMETHOD' 16 request.rpcMethod, request.rpcParams = method, params 17 18 # patch the path. there are only a few options: 19 # - 'RPC2' + method >> method 20 # - 'someurl' + method >> someurl.method 21 # - 'someurl/someother' + method >> someurl.someother.method 22 if not request.object_path.endswith('/'): 23 request.object_path += '/' 24 if request.object_path.startswith('/RPC2/'): 12 return ('ERROR PARAMS', ), 'ERRORMETHOD' 13 14 15 def patched_path(path, method): 16 """Return 'path' with the rpcMethod appended.""" 17 if not path.endswith('/'): 18 path += '/' 19 if path.startswith('/RPC2/'): 25 20 # strip the first /rpc2 26 request.object_path = request.object_path[5:] 27 request.object_path += str(method).replace('.', '/') 28 request.paramList = list(params) 29 request.processRequestBody = False 21 path = path[5:] 22 path += str(method).replace('.', '/') 23 return path 30 24 31 def main(encoding='utf-8', allow_none=0):32 """Obtain and set cherrypy.response.body from a page handler.33 34 Python's None value cannot be used in standard XML-RPC; to allow35 using it via an extension, provide a true value for allow_none.36 """37 from cherrypy import _cprequest38 dispatch = cherrypy.config.get("dispatcher") or _cprequest.Dispatcher()39 40 request = cherrypy.request41 handler = dispatch(request.object_path)42 body = handler(*(request.virtual_path + request.paramList),43 **request.params)44 respond(xmlrpclib.dumps((body,), methodresponse=1,45 encoding=encoding, allow_none=allow_none))46 return True47 25 48 def error_response(): 49 body = str(sys.exc_info()[1]) 50 respond(xmlrpclib.dumps(xmlrpclib.Fault(1, body))) 51 52 def respond(body): 26 def _set_response(body): 53 27 # The XML-RPC spec (http://www.xmlrpc.com/spec) says: 54 28 # "Unless there's a lower-level error, always return 200 OK." … … 61 35 response.headers['Content-Length'] = len(body) 62 36 63 def setup(conf): 64 """Hook this tool into cherrypy.request using the given conf.""" 65 cherrypy.request.hooks.attach('before_request_body', process_body, conf) 66 def wrapper(): 67 if main(**conf): 68 cherrypy.request.execute_main = False 69 cherrypy.request.hooks.attach('before_main', wrapper) 70 cherrypy.request.hooks.attach('after_error_response', error_response, conf) 37 38 def respond(body, encoding='utf-8', allow_none=0): 39 _set_response(xmlrpclib.dumps((body,), methodresponse=1, 40 encoding=encoding, 41 allow_none=allow_none)) 42 43 def wrap_error(): 44 body = str(sys.exc_info()[1]) 45 _set_response(xmlrpclib.dumps(xmlrpclib.Fault(1, body))) 46 trunk/cherrypy/test/test_core.py
r1074 r1075 495 495 data = open(log_file, "rb").readlines() 496 496 self.assertEqual(data[-3], ' raise ValueError()\n') 497 # Each error should write only one traceback ( 11lines each).498 self.assertEqual(len(data), 22)497 # Each error should write only one traceback (9 lines each). 498 self.assertEqual(len(data), 18) 499 499 finally: 500 500 ignore.pop() trunk/cherrypy/tools.py
r1069 r1075 16 16 CherryPy hooks: "hooks" are points in the CherryPy request-handling 17 17 process which may hand off control to registered callbacks. The 18 Request object possesses a "hooks" attribute for manipulating 19 this. If a tool exposes a "setup" callable, this will be called 20 once per Request (if the feature is enabled via config). 18 Request object possesses a "hooks" attribute (a tools.HookMap) 19 for manipulating this. If a tool exposes a "setup" callable, 20 it will be called once per Request (if the feature is enabled 21 via config). 21 22 22 23 Tools may be implemented as any object with a namespace. The builtins … … 43 44 self.callbacks[point].append(wrapper) 44 45 45 def tool_config(self):46 toolmap = {}47 for k, v in cherrypy.config.current_config().iteritems():48 atoms = k.split(".")49 namespace = atoms.pop(0)50 if namespace == "tools":51 toolname = atoms.pop(0)52 bucket = toolmap.setdefault(toolname, {})53 bucket[".".join(atoms)] = v54 return toolmap55 56 46 def setup(self): 57 47 """Run tool.setup(conf) for each tool specified in current config.""" 58 48 g = globals() 59 for toolname, conf in self.tool_config().iteritems():49 for toolname, conf in tool_config().iteritems(): 60 50 if conf.get("on", False): 61 51 del conf["on"] 62 52 g[toolname].setup(conf) 63 53 64 # Run _cp_setup _hooksfunctions54 # Run _cp_setup functions 65 55 mounted_app_roots = cherrypy.tree.mount_points.values() 66 56 objectList = _cputil.get_object_trail() 67 57 objectList.reverse() 68 58 for objname, obj in objectList: 69 s = getattr(obj, "_cp_setup _hooks", None)59 s = getattr(obj, "_cp_setup", None) 70 60 if s: 71 61 s() … … 93 83 callback() 94 84 85 def tool_config(): 86 """Return all 'tools.*' config entries as a {toolname: {k: v}} dict.""" 87 toolmap = {} 88 for k, v in cherrypy.config.current_config().iteritems(): 89 atoms = k.split(".") 90 namespace = atoms.pop(0) 91 if namespace == "tools": 92 toolname = atoms.pop(0) 93 bucket = toolmap.setdefault(toolname, {}) 94 bucket[".".join(atoms)] = v 95 return toolmap 96 97 def merged_config(toolname, d): 98 """Merge arguments from tool config into another dict.""" 99 mergedkw = d.copy() 100 mergedkw.update(tool_config().get(toolname, {})) 101 if "on" in mergedkw: 102 del mergedkw["on"] 103 return mergedkw 104 95 105 96 106 class Tool(object): 97 107 98 def __init__(self, point, callable ):108 def __init__(self, point, callable, name=None): 99 109 self.point = point 100 110 self.callable = callable 111 if name is None: 112 name = callable.__name__ 113 self.name = name 101 114 # TODO: add an attribute to self for each arg 102 115 # in inspect.getargspec(callable) 116 ## 117 ## class ToolMixin(object): 118 ## def _cp_setup(me): 119 ## self.setup(None) 120 ## self.Mixin = ToolMixin 103 121 104 122 def __call__(self, *args, **kwargs): … … 117 135 def deco(f): 118 136 def wrapper(*a, **kw): 119 handled = self.callable(*args, ** kwargs)137 handled = self.callable(*args, **merged_config(self.name, kwargs)) 120 138 return f(*a, **kw) 121 139 return wrapper … … 138 156 """ 139 157 140 def __init__(self, callable ):158 def __init__(self, callable, name=None): 141 159 self.point = 'before_main' 142 160 self.callable = callable 161 if name is None: 162 name = callable.__name__ 163 self.name = name 143 164 144 165 def handler(self, *args, **kwargs): … … 150 171 """ 151 172 def wrapper(*a, **kw): 152 handled = self.callable(*args, ** kwargs)173 handled = self.callable(*args, **merged_config(self.name, kwargs)) 153 174 if not handled: 154 175 raise cherrypy.NotFound() … … 169 190 def deco(f): 170 191 def wrapper(*a, **kw): 171 handled = self.callable(*args, ** kwargs)192 handled = self.callable(*args, **merged_config(self.name, kwargs)) 172 193 if handled: 173 194 return cherrypy.response.body … … 185 206 def wrapper(): 186 207 if self.callable(**conf): 187 cherrypy.request. execute_main = False208 cherrypy.request.dispatch = None 188 209 # Don't pass conf (or our wrapper will get wrapped!) 189 210 cherrypy.request.hooks.attach(self.point, wrapper) … … 209 230 def setup(self, conf): 210 231 """Hook this tool into cherrypy.request using the given conf.""" 232 # Stick the section where "dir" was defined into the params 211 233 conf['section'] = cherrypy.config.get('tools.staticdir.dir', 212 234 return_section=True) 213 235 def wrapper(): 214 236 if self.callable(**conf): 215 cherrypy.request. execute_main = False237 cherrypy.request.dispatch = None 216 238 # Don't pass conf (or our wrapper will get wrapped!) 217 239 cherrypy.request.hooks.attach(self.point, wrapper) 218 staticdir = _StaticDirTool(static. get_dir)219 staticfile = MainTool(static. get_file)240 staticdir = _StaticDirTool(static.staticdir) 241 staticfile = MainTool(static.staticfile) 220 242 del static 221 243 244 from cherrypy.lib import sessions as _sessions 245 class _SessionTool(Tool): 246 def __init__(self): 247 self.point = "before_finalize" 248 self.callable = _sessions.save 249 self.name = "sessions" 250 251 def wrap(self, **kwargs): 252 """Make a decorator for this tool.""" 253 def deco(f): 254 def wrapper(*a, **kw): 255 s = cherrypy.request._session = _sessions.Session() 256 for k, v in merged_config(self.name, kwargs).iteritems(): 257 setattr(s, str(k), v) 258 s.init() 259 if not hasattr(cherrypy, "session"): 260 cherrypy.session = _sessions.SessionWrapper() 261 262 result = f(*a, **kw) 263 _sessions.save() 264 cherrypy.request.hooks.attach('on_end_request', _sessions.cleanup) 265 return result 266 return wrapper 267 return deco 268 269 def setup(self, conf): 270 """Hook this tool into cherrypy.request using the given conf. 271 272 The standard CherryPy request object will automatically call this 273 method when the tool is "turned on" in config. 274 """ 275 def init(): 276 s = cherrypy.request._session = _sessions.Session() 277 for k, v in conf.iteritems(): 278 setattr(s, str(k), v) 279 s.init() 280 281 if not hasattr(cherrypy, "session"): 282 cherrypy.session = _sessions.SessionWrapper() 283 cherrypy.request.hooks.attach('before_request_body', init) 284 285 cherrypy.request.hooks.attach('before_finalize', _sessions.save) 286 cherrypy.request.hooks.attach('on_end_request', _sessions.cleanup) 287 sessions = _SessionTool() 288 289 from cherrypy.lib import xmlrpc as _xmlrpc 290 class _XMLRPCTool(object): 291 """Tool for using XMLRPC over HTTP. 292 293 Python's None value cannot be used in standard XML-RPC; to allow 294 using it via an extension, provide a true value for allow_none. 295 """ 296 297 def dispatch(self, path): 298 """Use this tool for cherrypy.request dispatch. 299 300 For example: 301 [/rpc] 302 dispatch = tools.xmlrpc.dispatch 303 """ 304 request.hooks.attach('after_error_response', _xmlrpc.wrap_error) 305 306 rpcparams, rpcmethod = _xmlrpc.process_body() 307 path = _xmlrpc.patched_path(path, rpcmethod) 308 309 from cherrypy import _cprequest 310 handler, opath, vpath = _cprequest.find(path) 311 312 # Decode any leftover %2F in the virtual_path atoms. 313 vpath = tuple([x.replace("%2F", "/") for x in vpath]) 314 315 request = cherrypy.request 316 body = handler(*(vpath + rpcparams), **request.params) 317 conf = tool_config().get("xmlrpc", {}) 318 _xmlrpc.respond(body, 319 conf.get('encoding', 'utf-8'), 320 conf.get('allow_none', 0)) 321 322 def setup(self, conf): 323 """Hook this tool into cherrypy.request using the given conf.""" 324 cherrypy.request.dispatch = self.dispatch 325 xmlrpc = _XMLRPCTool() 326 327 222 328 # These modules are themselves Tools 223 from cherrypy.lib import caching , sessions, xmlrpc329 from cherrypy.lib import caching

