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

Changeset 1941

Show
Ignore:
Timestamp:
04/05/08 15:40:13
Author:
fumanchu
Message:

Partial fix for #800 (). I'm not yet happy with making error handler authors do all the hard work: spec conformance, be IE unfriendly, even manually set the status, etc.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/800-error-handlers/cherrypy/_cperror.py

    r1839 r1941  
    149149 
    150150 
     151def clean_headers(status): 
     152    """Remove any headers which should not apply to an error response.""" 
     153    import cherrypy 
     154     
     155    response = cherrypy.response 
     156     
     157    # Remove headers which applied to the original content, 
     158    # but do not apply to the error page. 
     159    respheaders = response.headers 
     160    for key in ["Accept-Ranges", "Age", "ETag", "Location", "Retry-After", 
     161                "Vary", "Content-Encoding", "Content-Length", "Expires", 
     162                "Content-Location", "Content-MD5", "Last-Modified"]: 
     163        if respheaders.has_key(key): 
     164            del respheaders[key] 
     165     
     166    if status != 416: 
     167        # A server sending a response with status code 416 (Requested 
     168        # range not satisfiable) SHOULD include a Content-Range field 
     169        # with a byte-range-resp-spec of "*". The instance-length 
     170        # specifies the current length of the selected resource. 
     171        # A response with status code 206 (Partial Content) MUST NOT 
     172        # include a Content-Range field with a byte-range- resp-spec of "*". 
     173        if respheaders.has_key("Content-Range"): 
     174            del respheaders["Content-Range"] 
     175 
     176 
    151177class HTTPError(CherryPyException): 
    152178    """ Exception used to return an HTTP error code (4xx-5xx) to the client. 
     
    174200        response = cherrypy.response 
    175201         
    176         # Remove headers which applied to the original content, 
    177         # but do not apply to the error page. 
    178         respheaders = response.headers 
    179         for key in ["Accept-Ranges", "Age", "ETag", "Location", "Retry-After", 
    180                     "Vary", "Content-Encoding", "Content-Length", "Expires", 
    181                     "Content-Location", "Content-MD5", "Last-Modified"]: 
    182             if respheaders.has_key(key): 
    183                 del respheaders[key] 
    184          
    185         if self.status != 416: 
    186             # A server sending a response with status code 416 (Requested 
    187             # range not satisfiable) SHOULD include a Content-Range field 
    188             # with a byte-range-resp-spec of "*". The instance-length 
    189             # specifies the current length of the selected resource. 
    190             # A response with status code 206 (Partial Content) MUST NOT 
    191             # include a Content-Range field with a byte-range- resp-spec of "*". 
    192             if respheaders.has_key("Content-Range"): 
    193                 del respheaders["Content-Range"] 
     202        clean_headers(self.status) 
    194203         
    195204        # In all cases, finalize will be called after this method, 
     
    199208        if cherrypy.request.show_tracebacks: 
    200209            tb = format_exc() 
    201         respheaders['Content-Type'] = "text/html" 
     210        response.headers['Content-Type'] = "text/html" 
    202211         
    203212        content = self.get_error_page(self.status, traceback=tb, 
    204213                                      message=self.message) 
    205214        response.body = content 
    206         respheaders['Content-Length'] = len(content) 
     215        response.headers['Content-Length'] = len(content) 
    207216         
    208217        _be_ie_unfriendly(self.status) 
  • branches/800-error-handlers/cherrypy/_cprequest.py

    r1938 r1941  
    393393    error_page = {} 
    394394    error_page__doc = """ 
    395     A dict of {error code: response filename} pairs. The named response 
    396     files should be Python string-formatting templates, and can expect by 
    397     default to receive the format values with the mapping keys 'status', 
    398     'message', 'traceback', and 'version'. The set of format mappings 
    399     can be extended by overriding HTTPError.set_response.""" 
     395    A dict of {error code: response filename or callable} pairs. 
     396    The named response files should be Python string-formatting templates, 
     397    and can expect by default to receive format values with the mapping 
     398    keys 'status', 'message', 'traceback', and 'version'. The set of 
     399    format mappings can be extended by overriding HTTPError.set_response. 
     400     
     401    If a callable is provided, it will be called with the HTTPError 
     402    instance as the only argument. The callable is expected to set 
     403    response.status, .headers and .body appropriately. 
     404     
     405    If no entry is given for an error code, the HTTPError's set_response 
     406    method will handle the error (by setting .status, .headers, and .body). 
     407    """ 
    400408     
    401409    show_tracebacks = True 
     
    592600                    cherrypy.response.finalize() 
    593601                except (cherrypy.HTTPRedirect, cherrypy.HTTPError), inst: 
    594                     inst.set_response() 
     602                    ep = self.error_page.get(inst.status, '') 
     603                    if ep and callable(ep): 
     604                        ep(inst) 
     605                    else: 
     606                        inst.set_response() 
    595607                    self.stage = 'before_finalize (HTTPError)' 
    596608                    self.hooks.run('before_finalize') 
     
    716728     
    717729    def handle_error(self, exc): 
    718         """Handle the last exception. (Core)""" 
     730        """Handle the last unanticipated exception. (Core)""" 
    719731        try: 
    720732            self.hooks.run("before_error_response") 
     
    724736            cherrypy.response.finalize() 
    725737        except cherrypy.HTTPRedirect, inst: 
    726             inst.set_response() 
     738            ep = self.error_page.get(inst.status, '') 
     739            if ep and callable(ep): 
     740                ep(inst) 
     741            else: 
     742                inst.set_response() 
    727743            cherrypy.response.finalize() 
    728744 
  • branches/800-error-handlers/cherrypy/test/test_core.py

    r1921 r1941  
    240240            for chunk in self.as_yield(): 
    241241                yield chunk 
    242  
    243  
     242     
     243     
     244    def page401(e): 
     245        cherrypy.response.status = e.status 
     246        cherrypy._cperror.clean_headers(e.status) 
     247        cherrypy.response.body = "Well, I'm very sorry but you haven't paid!" 
     248     
     249     
    244250    class Error(Test): 
    245251         
     
    247253                      } 
    248254         
    249         def custom(self): 
    250             raise cherrypy.HTTPError(404, "No, <b>really</b>, not found!") 
    251         custom._cp_config = {'error_page.404': os.path.join(localDir, "static/index.html")} 
     255        def custom(self, err='404'): 
     256            raise cherrypy.HTTPError(int(err), "No, <b>really</b>, not found!") 
     257        custom._cp_config = {'error_page.404': os.path.join(localDir, "static/index.html"), 
     258                             'error_page.401': page401, 
     259                             } 
    252260         
    253261        def noexist(self): 
     
    725733        self.assertStatus(404) 
    726734        self.assertBody("Hello, world\r\n" + (" " * 499)) 
     735         
     736        # Test custom error page. 
     737        self.getPage("/error/custom?err=401") 
     738        self.assertStatus(401) 
     739        self.assertBody("Well, I'm very sorry but you haven't paid!") 
    727740         
    728741        # Test error in custom error page (ticket #305). 

Hosted by WebFaction

Log in as guest/cpguest to create tickets