Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

Changeset 1157

Show
Ignore:
Timestamp:
06/25/06 01:59:19
Author:
fumanchu
Message:

Finally a clean fix for #102 (Dispatch to different page handlers based on HTTP method).

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/cherrypy/_cprequest.py

    r1149 r1157  
    499499            # Try a "default" method on the current leaf. 
    500500            defhandler = getattr(candidate, "default", None) 
    501             if callable(defhandler) and getattr(defhandler, 'exposed', False): 
     501            if getattr(defhandler, 'exposed', False): 
    502502                # Insert any extra _cp_config from the default handler. 
    503503                conf = getattr(defhandler, "_cp_config", {}) 
     
    510510             
    511511            # Try the current leaf. 
    512             if callable(candidate) and getattr(candidate, 'exposed', False): 
     512            if getattr(candidate, 'exposed', False): 
    513513                set_conf() 
    514514                if i == len(object_trail) - 1: 
     
    528528 
    529529default_dispatch = Dispatcher() 
     530 
     531 
     532class MethodDispatcher(Dispatcher): 
     533    """Additional dispatch based on cherrypy.request.method.upper(). 
     534     
     535    Methods named GET, POST, etc will be called on an exposed class. 
     536    The method names must be all caps; the appropriate Allow header 
     537    will be output showing all capitalized method names as allowable 
     538    HTTP verbs. 
     539     
     540    Note that the containing class must be exposed, not the methods. 
     541    """ 
     542     
     543    def __call__(self, path_info): 
     544        """Set handler and config for the current request.""" 
     545        request = cherrypy.request 
     546        resource, vpath = self.find_handler(path_info) 
     547         
     548        # Decode any leftover %2F in the virtual_path atoms. 
     549        vpath = [x.replace("%2F", "/") for x in vpath] 
     550         
     551        if resource: 
     552            # Set Allow header 
     553            avail = [m for m in dir(resource) if m.isupper()] 
     554            if "GET" in avail and "HEAD" not in avail: 
     555                avail.append("HEAD") 
     556            avail.sort() 
     557            cherrypy.response.headers['Allow'] = ", ".join(avail) 
     558             
     559            # Find the subhandler 
     560            meth = cherrypy.request.method.upper() 
     561            func = getattr(resource, meth, None) 
     562            if func is None and meth == "HEAD": 
     563                func = getattr(resource, "GET", None) 
     564            if func: 
     565                def handler(): 
     566                    cherrypy.response.body = func(*vpath, **request.params) 
     567                request.handler = handler 
     568                return 
     569            else: 
     570                def notallowed(): 
     571                    raise cherrypy.HTTPError(405) 
     572                request.handler = notallowed 
     573        else: 
     574            def notfound(): 
     575                raise cherrypy.NotFound() 
     576            request.handler = notfound 
    530577 
    531578 
  • trunk/cherrypy/test/test_objectmapping.py

    r1106 r1157  
    103103        default.exposed = True 
    104104     
     105    class ByMethod: 
     106        exposed = True 
     107         
     108        def __init__(self, *things): 
     109            self.things = list(things) 
     110         
     111        def GET(self): 
     112            return repr(self.things) 
     113         
     114        def POST(self, thing): 
     115            self.things.append(thing) 
    105116     
    106117    Root.exposing = Exposing() 
     
    111122    Root.dir1.dir2.dir3.dir4 = Dir4() 
    112123    Root.defnoindex = DefNoIndex() 
    113      
     124    Root.bymethod = ByMethod('another') 
    114125     
    115126    for url in script_names: 
    116         conf = {'user': (url or "/").split("/")[-2]} 
    117         cherrypy.tree.mount(Root(), url, {'/': conf}) 
     127        d = cherrypy._cprequest.MethodDispatcher() 
     128        conf = {'/': {'user': (url or "/").split("/")[-2]}, 
     129                '/bymethod': {'dispatch': d}, 
     130                } 
     131        cherrypy.tree.mount(Root(), url, conf) 
    118132     
    119133    cherrypy.config.update({ 
     
    240254        self.getPage("/exposingnew/2") 
    241255        self.assertBody("expose works!") 
    242  
     256     
     257    def testMethodDispatch(self): 
     258        self.getPage("/bymethod") 
     259        self.assertBody("['another']") 
     260        self.assertHeader('Allow', 'GET, HEAD, POST') 
     261         
     262        self.getPage("/bymethod", method="HEAD") 
     263        self.assertBody("") 
     264        self.assertHeader('Allow', 'GET, HEAD, POST') 
     265         
     266        self.getPage("/bymethod", method="POST", body="thing=one") 
     267        self.assertBody("") 
     268        self.assertHeader('Allow', 'GET, HEAD, POST') 
     269         
     270        self.getPage("/bymethod") 
     271        self.assertBody("['another', 'one']") 
     272        self.assertHeader('Allow', 'GET, HEAD, POST') 
     273         
     274        self.getPage("/bymethod", method="PUT") 
     275        self.assertErrorPage(405) 
     276        self.assertHeader('Allow', 'GET, HEAD, POST') 
    243277 
    244278 

Hosted by WebFaction

Log in as guest/cpguest to create tickets