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

Changeset 639

Show
Ignore:
Timestamp:
09/13/05 17:47:59
Author:
mikerobi
Message:

ticket:288 changes merged into trunk, deleted httperrors branch, added assertErrorPage to CPWebCase

Files:

Legend:

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

    r622 r639  
    99        except ValueError, ex: 
    1010            if str(ex) == 'Maximum content length exceeded': 
    11                 raise cherrypy.HTTPStatusError(status=413) 
     11                raise cherrypy.HTTPError(status=413) 
    1212            else: 
    1313                raise ex 
  • trunk/cherrypy/_cperror.py

    r613 r639  
    173173_missing = object() 
    174174 
    175 class HTTPStatusError(Error): 
    176     """Exception raised when the client has made an error in its request.""" 
    177      
    178     def __init__(self, status=400, message=_missing): 
     175class HTTPError(Error): 
     176    """ Exception raised when the client has made an error in its request. 
     177        This exception will automatically set the response status and body. 
     178         
     179        A custom body can be pased to the init method in place of the standard error page. 
     180    """ 
     181     
     182    def __init__(self, status=500, body=_missing): 
    179183        self.status = status = int(status) 
    180184        if status < 400 or status > 599: 
     
    183187        # these 4 lines might dissapear 
    184188        import cherrypy 
    185         cherrypy.response.status = status 
    186         if message is not _missing: 
    187             cherrypy.response.body=message 
    188  
    189         self.message = message 
    190      
    191     def getArgs(self): 
    192         return (self.status, self.message) 
    193  
    194  
    195 class NotFound(HTTPStatusError): 
     189        self.statusString = cherrypy._cputil.getErrorStatusAndPage(status)[0] 
     190        cherrypy.response.status = self.statusString 
     191 
     192        if body is _missing: 
     193            # because the init method is called before the exception is raised 
     194            # it is impossible to embed the traceback in the error page at this point. 
     195            # We use a generator so that the error page is generated at a later point ( 
     196            # after the exception is raised). 
     197            cherrypy.response.body = self.pageGenerator() 
     198        else: 
     199            cherrypy.response.body = body 
     200     
     201    def __str__(self): 
     202        return self.statusString 
     203 
     204    def pageGenerator(self): 
     205        import cherrypy 
     206        yield cherrypy._cputil.getErrorStatusAndPage(self.status)[1] 
     207 
     208class NotFound(HTTPError): 
    196209    """ Happens when a URL couldn't be mapped to any class.method """ 
    197210     
    198211    def __init__(self, path): 
    199212        self.args = (path,) 
    200         HTTPStatusError.__init__(self, 404) 
     213        HTTPError.__init__(self, 404) 
  • trunk/cherrypy/_cphttptools.py

    r630 r639  
    4545 
    4646import cherrypy 
    47 from cherrypy import _cputil, _cpcgifs, _cperror, _cpwsgiserve
     47from cherrypy import _cputil, _cpcgifs, _cpwsgiserver, _cperro
    4848from cherrypy.lib import cptools 
    4949 
     
    289289                applyFilters('onEndResource') 
    290290        except: 
    291             # This includes HTTPStatusError and NotFound 
     291            # This includes HTTPError and NotFound 
    292292            handleError(sys.exc_info()) 
    293293     
     
    381381        except _cpwsgiserver.MaxSizeExceeded: 
    382382            # Post data is too big 
    383             raise _cperror.HTTPStatusError(413) 
     383            raise _cperror.HTTPError(413) 
    384384         
    385385        if forms.file: 
     
    423423        applyFilters('beforeErrorResponse') 
    424424         
    425         # _cpOnError and _cpOnHTTPError will probably change cherrypy.response.body. 
     425        # _cpOnError will probably change cherrypy.response.body. 
    426426        # They may also change the headerMap, etc. 
    427         if sys.exc_info()[0] is cherrypy.HTTPStatusError: 
    428             _cputil.getSpecialAttribute('_cpOnHTTPError')() 
    429         else: 
    430             _cputil.getSpecialAttribute('_cpOnError')() 
     427        _cputil.getSpecialAttribute('_cpOnError')() 
    431428         
    432429        finalize() 
  • trunk/cherrypy/_cputil.py

    r625 r639  
    3838 
    3939import cherrypy 
    40 from cherrypy.lib import httperrors 
    41  
    4240 
    4341class EmptyClass: 
     
    153151        f.close() 
    154152 
    155 def _cpOnHTTPError(): 
    156     """ Default _cpOnHTTPError method """ 
    157     status, customMessage = sys.exc_info()[1].getArgs() 
    158     
    159     # get the error page 
    160     page = httperrors.getErrorPage(status, customMessage = customMessage) 
    161     cherrypy.response.status, cherrypy.response.body = page 
    162      
    163     if cherrypy.response.headerMap.has_key('Content-Encoding'): 
    164         del cherrypy.response.headerMap['Content-Encoding'] 
     153def _HTTPErrorTemplate(errorString, message, traceback, version): 
     154    subTuple = (errorString, errorString, message, traceback, cherrypy.__version__) 
     155     
     156    return '''<?xml version="1.0" encoding="UTF-8"?> 
     157    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
     158      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
     159    <html> 
     160    <head> 
     161        <title>%s</title> 
     162        <style type="text/css"> 
     163        #poweredBy { 
     164            margin-top: 20px; 
     165            border-top: 2px solid black; 
     166            font-style: italic; 
     167        } 
     168 
     169        #traceback { 
     170            color: red; 
     171        } 
     172        </style> 
     173    </head> 
     174        <body> 
     175            <h2>%s</h2> 
     176            <p>%s</p> 
     177            <pre id="traceback">%s</pre> 
     178        <div id="poweredBy"> 
     179        <span>Powered by <a href="http://www.cherrypy.org">Cherrypy %s</a></span> 
     180        </div> 
     181        </body> 
     182    </html> 
     183    ''' % subTuple 
     184 
     185import BaseHTTPServer 
     186_HTTPResponses = BaseHTTPServer.BaseHTTPRequestHandler.responses 
     187 
     188def getErrorStatusAndPage(status, traceback = None): 
     189    statusString, message = _HTTPResponses[status] 
     190    statusString = '%d %s' % (status, statusString) 
     191     
     192    if traceback is None: 
     193        traceback = '' 
     194        # get the traceback from formatExc 
     195        developmentMode = (cherrypy.config.get('server.environment') == 'development') 
     196        if cherrypy.config.get('server.showTracebacks') or developmentMode: 
     197            traceback = formatExc() 
     198     
     199    page = _HTTPErrorTemplate(statusString, message, traceback, cherrypy.__version__) 
     200     
     201    return statusString, page 
    165202 
    166203def formatExc(exc=None): 
     
    168205    if exc is None: 
    169206        exc = sys.exc_info() 
     207 
     208    if exc == (None, None, None): 
     209        return "" 
     210    return "".join(traceback.format_exception(*exc)) 
     211 
     212def getErrorStatusAndPage(status, traceback = None): 
     213    statusString, message = _HTTPResponses[status] 
     214    statusString = '%d %s' % (status, statusString) 
     215     
     216    if traceback is None: 
     217        traceback = '' 
     218        # get the traceback from formatExc 
     219        developmentMode = (cherrypy.config.get('server.environment') == 'development') 
     220        if cherrypy.config.get('server.showTracebacks') or developmentMode: 
     221            traceback = formatExc() 
     222     
     223    page = _HTTPErrorTemplate(statusString, message, traceback, cherrypy.__version__) 
     224     
     225    return statusString, page 
     226 
     227    """formatExc(exc=None) -> exc (or sys.exc_info), formatted.""" 
     228    if exc is None: 
     229        exc = sys.exc_info() 
     230     
     231    if exc == (None, None, None): 
     232        return "" 
     233 
    170234    return "".join(traceback.format_exception(*exc)) 
    171235 
    172236def _cpOnError(): 
    173237    """ Default _cpOnError method """ 
    174     developmentMode = cherrypy.config.get('server.environment') == 'development' 
    175     httpErrors      = cherrypy.config.get('server.httpErrors') 
    176     showTracebacks  = cherrypy.config.get('server.showTracebacks') 
    177238     
    178239    logTracebacks  = cherrypy.config.get('server.logTracebacks', True) 
     
    182243    response = cherrypy.response 
    183244     
    184     if not developmentMode and httpErrors: 
    185         # if it isn't development mode and http errors are turned on 
    186         # set the response status and render the body 
    187         if response.status == 404: 
    188             response.status, response.body = httperrors.getErrorPage(404) 
    189         else: 
    190             response.status, response.body = httperrors.getErrorPage(500) 
    191     elif developmentMode or showTracebacks: 
    192         # if it is development mode or tracebacks are turned on 
    193         # return the traceback as plaintext 
    194         response.body = [formatExc()] 
    195         response.headerMap['Content-Type'] = 'text/plain' 
     245    if isinstance(sys.exc_info()[1], cherrypy.HTTPError): 
     246        # status, body already set 
     247        pass 
    196248    else: 
    197         # If it is production mode but http errors are disabled then 
    198         # Display a simple, generic error message 
    199         response.body = "Unrecoverable error in the server" 
    200         response.headerMap['Content-Type'] = 'text/plain' 
     249        response.status, response.body = getErrorStatusAndPage(500) 
    201250     
    202251    if cherrypy.response.headerMap.has_key('Content-Encoding'): 
  • trunk/cherrypy/lib/cptools.py

    r608 r639  
    206206        cherrypy.response.headerMap['Content-Range'] = "bytes */%s" % content_length 
    207207        message = "Invalid Range (first-byte-pos greater than Content-Length)" 
    208         raise cherrypy.HTTPStatusError(416, message) 
     208        raise cherrypy.HTTPError(416, message) 
    209209     
    210210    return result 
  • trunk/cherrypy/test/helper.py

    r587 r639  
    3737import webtest 
    3838import types 
     39import re 
     40 
    3941for _x in dir(cherrypy): 
    4042    y = getattr(cherrypy, _x) 
     
    127129        else: 
    128130            webtest.WebCase.getPage(self, url, headers, method, body) 
     131  
     132    def assertErrorPage(self, errorCode, pattern = ''): 
     133        """ Compare the response body with a built in error page. 
     134            The function will optionally look for the regexp pattern,  
     135            within the exception embedded in the error page. 
     136        """ 
     137 
     138        from cherrypy._cputil import getErrorStatusAndPage 
     139        page = getErrorStatusAndPage(errorCode, '')[1] 
     140 
     141        # escape the question marks 
     142        page = page.replace('?', r'\?') 
     143         
     144        # re to find the traceback in the page 
     145        traceRe = re.compile('(<pre id="traceback">)(</pre>)') 
     146 
     147        # stick the pattern in the page so we can match everythign 
     148        # at once 
     149        page = traceRe.sub( '\g<1>.*%s.*\g<2>' % pattern, page) 
     150         
     151        # check if there is no exception 
     152        if pattern and traceRe.search(self.body): 
     153            msg = 'No match for %s in body' % `pattern` 
     154            self._handlewebError(msg) 
     155        else: 
     156            if not re.search(page, self.body, re.DOTALL): 
     157                msg = 'Error page does not match' 
     158                self._handlewebError(msg) 
    129159 
    130160CPTestLoader = webtest.ReloadingTestLoader() 
  • trunk/cherrypy/test/test_core.py

    r626 r639  
    490490        self.getPage("/error/missing") 
    491491        self.assertStatus("404 Not Found") 
    492         self.assertInBody("NotFound"
     492        self.assertErrorPage(404
    493493         
    494494        ignore = helper.webtest.ignored_exceptions 
    495495        ignore.append(ValueError) 
    496496        try: 
    497             valerr = r'\n    raise ValueError\(\)\nValueError\n$
     497            valerr = r'\n    raise ValueError\(\)\nValueError\n
    498498            self.getPage("/error/page_method") 
    499             self.assertMatchesBody(valerr) 
    500              
     499            self.assertErrorPage(500, valerr) 
     500 
    501501            import cherrypy 
    502502            proto = cherrypy.config.get("server.protocolVersion", "HTTP/1.0") 
  • trunk/cherrypy/test/test_gzip_filter.py

    r605 r639  
    4646        'server.logToScreen': False, 
    4747        'server.environment': 'production', 
    48         'server.httpErrors': False, 
    4948        'server.showTracebacks': True, 
    5049        'gzipFilter.on': True, 
     
    8382            else: 
    8483                self.assertNoHeader('Content-Encoding') 
    85                 self.assertMatchesBody(r"IndexError\n$") 
     84                self.assertStatus('500 Internal error') 
     85                self.assertErrorPage(500, "IndexError\n") 
    8686        finally: 
    8787            helper.webtest.ignored_exceptions.pop() 
  • trunk/cherrypy/tutorial/tut10_http_errors.py

    r608 r639  
    1818            <a href="toggleTracebacks">Toggle tracebacks %s</a><br/><br/> 
    1919            <a href="/doesNotExist">Click me i'm a broken link!</a> 
     20            <br/> 
     21            <a href="/customMessage">Use a custom error message</a> 
    2022            <br/><br/> 
    2123            These errors are explicitly raised by the application. 
     
    4042        # raise an error based on the get query 
    4143        code = int(code) 
    42         raise cherrypy.HTTPStatusError(status = code) 
     44        raise cherrypy.HTTPError(status = code) 
    4345    error.exposed = True 
     46 
     47    def customMessage(self): 
     48        raise cherrypy.HTTPError(500, "Plain text message") 
     49    customMessage.exposed = True 
    4450 
    4551cherrypy.root = HTTPErrorDemo() 

Hosted by WebFaction

Log in as guest/cpguest to create tickets