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

Changeset 911

Show
Ignore:
Timestamp:
01/03/06 21:08:59
Author:
fumanchu
Message:

Fix for #362 (Filters do not guarantee all methods are run (when errors occur)).

Files:

Legend:

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

    r910 r911  
    3333        if not self.closed: 
    3434            self.closed = True 
    35             try: 
    36                 applyFilters('on_end_request') 
    37             except (KeyboardInterrupt, SystemExit): 
    38                 raise 
    39             except: 
    40                 cherrypy.log(traceback=True) 
     35            applyFilters('on_end_request', failsafe=True) 
    4136     
    4237    def run(self, requestLine, headers, rfile): 
     
    8782             
    8883            try: 
    89                 applyFilters('on_start_resource'
     84                applyFilters('on_start_resource', failsafe=True
    9085                 
    9186                try: 
     
    118113                    cherrypy.response.finalize() 
    119114            finally: 
    120                 applyFilters('on_end_resource'
     115                applyFilters('on_end_resource', failsafe=True
    121116        except (KeyboardInterrupt, SystemExit): 
    122117            raise 
  • trunk/cherrypy/filters/__init__.py

    r903 r911  
    9595 
    9696 
    97 def applyFilters(method_name): 
     97def applyFilters(method_name, failsafe=False): 
    9898    """Execute the given method for all registered filters.""" 
    9999    special_methods = [] 
     
    106106        if method: 
    107107            special_methods.append(method) 
    108  
     108     
    109109    if method_name in _input_methods: 
    110110        # Run special filters after defaults. 
    111         for method in _filterhooks[method_name] + special_methods: 
    112             method() 
     111        methods = _filterhooks[method_name] + special_methods 
    113112    else: 
    114113        # Run special filters before defaults. 
    115         for method in special_methods + _filterhooks[method_name]: 
     114        methods = special_methods + _filterhooks[method_name] 
     115 
     116    for method in methods: 
     117        # The on_start_resource, on_end_resource, and on_end_request methods 
     118        # are guaranteed to run even if other methods of the same name fail. 
     119        # We will still log the failure, but proceed on to the next method. 
     120        # The only way to stop all processing from one of these methods is 
     121        # to raise SystemExit and stop the whole server. So, trap your own 
     122        # errors in these methods! 
     123        if failsafe: 
     124            try: 
     125                method() 
     126            except (KeyboardInterrupt, SystemExit): 
     127                raise 
     128            except: 
     129                cherrypy.log(traceback=True) 
     130        else: 
    116131            method() 
     132 
  • trunk/cherrypy/test/test_custom_filters.py

    r903 r911  
    1212class Numerify(BaseFilter): 
    1313     
     14    def on_start_resource(self): 
     15        m = cherrypy.config.get("numerify_filter.map", {}) 
     16        cherrypy.request.numerify_map = m.items() 
     17     
    1418    def before_finalize(self): 
    1519        if not cherrypy.config.get("numerify_filter.on", False): 
     
    1822        def number_it(body): 
    1923            for chunk in body: 
    20                 chunk = chunk.replace("pie", "3.14159") 
     24                for k, v in cherrypy.request.numerify_map: 
     25                    chunk = chunk.replace(k, v) 
    2126                yield chunk 
    2227        cherrypy.response.body = number_it(cherrypy.response.body) 
     
    9297    def restricted(self): 
    9398        return "Welcome!" 
     99     
     100    def err_in_onstart(self): 
     101        return "success!" 
    94102 
    95103 
     
    105113    '/cpfilterlist': { 
    106114        'numerify_filter.on': True, 
     115        'numerify_filter.map': {"pie": "3.14159"} 
    107116    }, 
    108117    '/cpfilterlist/restricted': { 
     
    112121    '/cpfilterlist/errinstream': { 
    113122        'streamResponse': True, 
     123    }, 
     124    '/cpfilterlist/err_in_onstart': { 
     125        # Because this isn't a dict, on_start_resource will error. 
     126        'numerify_filter.map': "pie->3.14159" 
    114127    }, 
    115128}) 
     
    119132# You can also insert a string, but we're effectively testing 
    120133# using-a-string via the config file. 
     134filters.input_filters.insert(0, Numerify) 
    121135filters.output_filters.insert(0, Numerify) 
    122136 
     
    169183        self.getPage("/cpfilterlist/restricted") 
    170184        self.assertErrorPage(401) 
     185     
     186    def testGuaranteedFilters(self): 
     187        # The on_start_resource and on_end_request filter methods are all 
     188        # guaranteed to run, even if there are failures in other on_start 
     189        # or on_end methods. This is NOT true of the other filter methods. 
     190        # Here, we have set up a failure in NumerifyFilter.on_start_resource, 
     191        # but because that failure is logged and passed over, the error 
     192        # page we obtain in the user agent should be from before_finalize. 
     193        ignore = helper.webtest.ignored_exceptions 
     194        ignore.append(AttributeError) 
     195        try: 
     196            self.getPage("/cpfilterlist/err_in_onstart") 
     197            self.assertErrorPage(500) 
     198            self.assertInBody("AttributeError: 'Request' object has no " 
     199                              "attribute 'numerify_map'") 
     200        finally: 
     201            ignore.pop() 
    171202 
    172203 

Hosted by WebFaction

Log in as guest/cpguest to create tickets