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

Changeset 838

Show
Ignore:
Timestamp:
11/26/05 16:22:29
Author:
fumanchu
Message:

Fix for #311 (filter method which runs after the response is completely written (or aborted)). New 'onEndRequest' filter method. HTTP SERVERS SHOULD NOW CALL request.close() when they are done writing out.

Files:

Legend:

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

    r802 r838  
    9090            for chunk in response.body: 
    9191                wfile.write(chunk) 
     92            request.close() 
    9293        except: 
    9394            s, h, b = _cputil.bareError() 
  • trunk/cherrypy/_cphttptools.py

    r837 r838  
    2828        self.scheme = scheme 
    2929        self.executeMain = True 
     30        self.closed = False 
     31     
     32    def close(self): 
     33        self.closed = True 
     34        try: 
     35            applyFilters('onEndRequest') 
     36            cherrypy.serving.request = None 
     37            cherrypy.serving.response = None 
     38        except (KeyboardInterrupt, SystemExit): 
     39            raise 
     40        except: 
     41            cherrypy.log(_cputil.formatExc()) 
     42     
     43    def __del__(self): 
     44        if not self.closed: 
     45            self.close() 
    3046     
    3147    def run(self, requestLine, headers, rfile): 
  • trunk/cherrypy/_cpwsgi.py

    r768 r838  
    5858        sys.stderr = NullWriter() 
    5959     
     60    request = None 
    6061    try: 
    6162        # LOGON_USER is served by IIS, and is the name of the 
     
    7273                               translate_headers(environ), 
    7374                               environ['wsgi.input']) 
     75        s, h, b = response.status, response.headers, response.body 
     76        exc = None 
    7477    except (KeyboardInterrupt, SystemExit): 
    7578        raise 
     
    8184        s, h, b = _cputil.bareError(tb) 
    8285        exc = sys.exc_info() 
    83     else: 
    84         s, h, b = response.status, response.headers, response.body 
    85         exc = None 
    8686     
    8787    try: 
     
    9393            chunk = str(chunk) 
    9494            yield chunk 
     95        if request: 
     96            request.close() 
    9597    except (KeyboardInterrupt, SystemExit): 
    9698        raise 
  • trunk/cherrypy/filters/__init__.py

    r814 r838  
    2929 
    3030_input_methods = ['onStartResource', 'beforeRequestBody', 'beforeMain'] 
    31 _output_methods = ['beforeFinalize', 'onEndResource', 
     31_output_methods = ['beforeFinalize', 'onEndResource', 'onEndRequest', 
    3232                   'beforeErrorResponse', 'afterErrorResponse'] 
    3333 
     
    5050        'LogDebugInfoFilter' : logdebuginfofilter.LogDebugInfoFilter, 
    5151        'NsgmlsFilter'       : nsgmlsfilter.NsgmlsFilter, 
    52         'SessionAuthenticateFilter' : sessionauthenticatefilter.SessionAuthenticateFilter, 
     52        'SessionAuthenticateFilter': 
     53                    sessionauthenticatefilter.SessionAuthenticateFilter, 
    5354        'SessionFilter'      : sessionfilter.SessionFilter, 
    5455        'StaticFilter'       : staticfilter.StaticFilter, 
  • trunk/cherrypy/filters/basefilter.py

    r808 r838  
    3434        """Called after finalizing the output (status, header, and body)""" 
    3535        pass 
     36     
     37    def onEndRequest(self): 
     38        """Called when the server closes the request.""" 
     39        pass 
    3640 
  • trunk/cherrypy/filters/cachefilter.py

    r837 r838  
    106106        cherrypy.request.cacheable = not cacheData 
    107107        if cacheData: 
     108            # found a hit! check the if-modified-since request header 
    108109            expirationTime, lastModified, obj = cacheData 
    109             # found a hit! check the if-modified-since request header 
    110110            modifiedSince = cherrypy.request.headerMap.get('If-Modified-Since', None) 
    111             # print ("Cache hit: If-Modified-Since=%s, lastModified=%s" % 
    112             #        (modifiedSince, lastModified)) 
    113111            if modifiedSince is not None and modifiedSince == lastModified: 
    114112                cherrypy._cache.totNonModified += 1 
     
    121119            raise cherrypy.RequestHandled() 
    122120     
    123     def onEndResource(self): 
    124         """Close & fix the cache entry after content was fully written""" 
    125         if not cherrypy.config.get('cacheFilter.on', False): 
     121    def beforeFinalize(self): 
     122        if not (cherrypy.config.get('cacheFilter.on', False) and 
     123                cherrypy.request.cacheable): 
    126124            return 
    127125         
    128         if cherrypy.request.cacheable: 
    129             status = cherrypy.response.status 
    130             headers = cherrypy.response.headers 
    131              
    132             # Consume the body iterable. Only do this once! 
    133             body = cherrypy.response.collapse_body() 
    134              
    135             if cherrypy.response.headerMap.get('Pragma', None) != 'no-cache': 
    136                 lastModified = cherrypy.response.headerMap.get('Last-Modified', None) 
    137                 # saves the cache data 
    138                 cherrypy._cache.put(lastModified, (status, headers, body)) 
     126        cherrypy.response._cachefilter_tee = [] 
     127        def tee(body): 
     128            """Tee response.body into response._cachefilter_tee (a list).""" 
     129            for chunk in body: 
     130                cherrypy.response._cachefilter_tee.append(chunk) 
     131                yield chunk 
     132        cherrypy.response.body = tee(cherrypy.response.body) 
     133     
     134    def onEndRequest(self): 
     135        # Close & fix the cache entry after content was fully written 
     136        if not (cherrypy.config.get('cacheFilter.on', False) and 
     137                cherrypy.request.cacheable): 
     138            return 
     139         
     140        response = cherrypy.response 
     141        status = response.status 
     142        headers = response.headers 
     143        body = ''.join([chunk for chunk in response._cachefilter_tee]) 
     144         
     145        if response.headerMap.get('Pragma', None) != 'no-cache': 
     146            lastModified = response.headerMap.get('Last-Modified', None) 
     147            # saves the cache data 
     148            cherrypy._cache.put(lastModified, (status, headers, body)) 
    139149 
    140150 
  • trunk/cherrypy/filters/sessionfilter.py

    r814 r838  
    160160        #   either before or after the body is returned 
    161161        cherrypy.response.body = saveData(cherrypy.response.body, sess) 
    162  
    163     def onEndResource(self): 
    164         self._clean() 
    165  
    166     def afterErrorResponse(self): 
    167         self._clean() 
    168      
    169     def _clean(self): 
     162     
     163    def onEndRequest(self): 
    170164        sess = cherrypy.request._session 
    171165        if not getattr(sess, 'sessionStorage', None): 
  • trunk/cherrypy/test/helper.py

    r834 r838  
    8888            for chunk in response.body: 
    8989                self.body.append(chunk) 
     90            request.close() 
    9091        except: 
    9192            if cherrypy.config.get("streamResponse", False): 
  • trunk/cherrypy/test/test_core.py

    r834 r838  
    305305 
    306306class NadsatFilter: 
     307     
    307308    def beforeFinalize(self): 
     309        self.ended = False 
    308310        def nadsat_it_up(body): 
    309311            for chunk in body: 
     
    312314                yield chunk 
    313315        cherrypy.response.body = nadsat_it_up(cherrypy.response.body) 
     316     
     317    def onEndRequest(self): 
     318        # This runs after the request has been completely written out. 
     319        cherrypy.response.body = "razdrez" 
     320        self.ended = True 
     321 
     322_nf = NadsatFilter() 
    314323 
    315324class CPFilterList(Test): 
    316325     
    317     _cpFilterList = [NadsatFilter()
     326    _cpFilterList = [_nf
    318327     
    319328    def index(self): 
     
    562571    def testCPFilterList(self): 
    563572        self.getPage("/cpfilterlist/") 
     573        # If body is "razdrez", then onEndRequest is being called too early. 
    564574        self.assertBody("A horrorshow lomtick of cherry pie") 
     575        # If this fails, then onEndRequest isn't being called at all. 
     576        self.assertEqual(_nf.ended, True) 
    565577     
    566578    def testFlatten(self): 

Hosted by WebFaction

Log in as guest/cpguest to create tickets