_cperror.py (8696B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\cherrypy\_cperror.py 2 from cgi import escape as _escape 3 from sys import exc_info as _exc_info 4 from traceback import format_exception as _format_exception 5 from cherrypy._cpcompat import basestring, iteritems, urljoin as _urljoin 6 from cherrypy.lib import httputil as _httputil 7 8 class CherryPyException(Exception): 9 pass 10 11 12 class TimeoutError(CherryPyException): 13 pass 14 15 16 class InternalRedirect(CherryPyException): 17 18 def __init__(self, path, query_string = ''): 19 import cherrypy 20 self.request = cherrypy.serving.request 21 self.query_string = query_string 22 if '?' in path: 23 path, self.query_string = path.split('?', 1) 24 path = _urljoin(self.request.path_info, path) 25 self.path = path 26 CherryPyException.__init__(self, path, self.query_string) 27 28 29 class HTTPRedirect(CherryPyException): 30 status = None 31 urls = None 32 encoding = 'utf-8' 33 34 def __init__(self, urls, status = None, encoding = None): 35 import cherrypy 36 request = cherrypy.serving.request 37 if isinstance(urls, basestring): 38 urls = [urls] 39 abs_urls = [] 40 for url in urls: 41 if isinstance(url, unicode): 42 url = url.encode(encoding or self.encoding) 43 url = _urljoin(cherrypy.url(), url) 44 abs_urls.append(url) 45 46 self.urls = abs_urls 47 if status is None: 48 if request.protocol >= (1, 1): 49 status = 303 50 else: 51 status = 302 52 else: 53 status = int(status) 54 if status < 300 or status > 399: 55 raise ValueError('status must be between 300 and 399.') 56 self.status = status 57 CherryPyException.__init__(self, abs_urls, status) 58 59 def set_response(self): 60 import cherrypy 61 response = cherrypy.serving.response 62 response.status = status = self.status 63 if status in (300, 301, 302, 303, 307): 64 response.headers['Content-Type'] = 'text/html;charset=utf-8' 65 response.headers['Location'] = self.urls[0] 66 msg = {300: "This resource can be found at <a href='%s'>%s</a>.", 67 301: "This resource has permanently moved to <a href='%s'>%s</a>.", 68 302: "This resource resides temporarily at <a href='%s'>%s</a>.", 69 303: "This resource can be found at <a href='%s'>%s</a>.", 70 307: "This resource has moved temporarily to <a href='%s'>%s</a>."}[status] 71 msgs = [ msg % (u, u) for u in self.urls ] 72 response.body = '<br />\n'.join(msgs) 73 response.headers.pop('Content-Length', None) 74 elif status == 304: 75 for key in ('Allow', 'Content-Encoding', 'Content-Language', 'Content-Length', 'Content-Location', 'Content-MD5', 'Content-Range', 'Content-Type', 'Expires', 'Last-Modified'): 76 if key in response.headers: 77 del response.headers[key] 78 79 response.body = None 80 response.headers.pop('Content-Length', None) 81 elif status == 305: 82 response.headers['Location'] = self.urls[0] 83 response.body = None 84 response.headers.pop('Content-Length', None) 85 else: 86 raise ValueError('The %s status code is unknown.' % status) 87 88 def __call__(self): 89 raise self 90 91 92 def clean_headers(status): 93 import cherrypy 94 response = cherrypy.serving.response 95 respheaders = response.headers 96 for key in ['Accept-Ranges', 97 'Age', 98 'ETag', 99 'Location', 100 'Retry-After', 101 'Vary', 102 'Content-Encoding', 103 'Content-Length', 104 'Expires', 105 'Content-Location', 106 'Content-MD5', 107 'Last-Modified']: 108 if key in respheaders: 109 del respheaders[key] 110 111 if status != 416: 112 if 'Content-Range' in respheaders: 113 del respheaders['Content-Range'] 114 115 116 class HTTPError(CherryPyException): 117 status = None 118 code = None 119 reason = None 120 121 def __init__(self, status = 500, message = None): 122 self.status = status 123 try: 124 self.code, self.reason, defaultmsg = _httputil.valid_status(status) 125 except ValueError as x: 126 raise self.__class__(500, x.args[0]) 127 128 if self.code < 400 or self.code > 599: 129 raise ValueError('status must be between 400 and 599.') 130 self._message = message or defaultmsg 131 CherryPyException.__init__(self, status, message) 132 133 def set_response(self): 134 import cherrypy 135 response = cherrypy.serving.response 136 clean_headers(self.code) 137 response.status = self.status 138 tb = None 139 if cherrypy.serving.request.show_tracebacks: 140 tb = format_exc() 141 response.headers['Content-Type'] = 'text/html;charset=utf-8' 142 response.headers.pop('Content-Length', None) 143 content = self.get_error_page(self.status, traceback=tb, message=self._message) 144 response.body = content 145 _be_ie_unfriendly(self.code) 146 147 def get_error_page(self, *args, **kwargs): 148 return get_error_page(*args, **kwargs) 149 150 def __call__(self): 151 raise self 152 153 154 class NotFound(HTTPError): 155 156 def __init__(self, path = None): 157 if path is None: 158 import cherrypy 159 request = cherrypy.serving.request 160 path = request.script_name + request.path_info 161 self.args = (path,) 162 HTTPError.__init__(self, 404, "The path '%s' was not found." % path) 163 164 165 _HTTPErrorTemplate = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"\n"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html>\n<head>\n <meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>\n <title>%(status)s</title>\n <style type="text/css">\n #powered_by {\n margin-top: 20px;\n border-top: 2px solid black;\n font-style: italic;\n }\n\n #traceback {\n color: red;\n }\n </style>\n</head>\n <body>\n <h2>%(status)s</h2>\n <p>%(message)s</p>\n <pre id="traceback">%(traceback)s</pre>\n <div id="powered_by">\n <span>Powered by <a href="http://www.cherrypy.org">CherryPy %(version)s</a></span>\n </div>\n </body>\n</html>\n' 166 167 def get_error_page(status, **kwargs): 168 import cherrypy 169 try: 170 code, reason, message = _httputil.valid_status(status) 171 except ValueError as x: 172 raise cherrypy.HTTPError(500, x.args[0]) 173 174 if kwargs.get('status') is None: 175 kwargs['status'] = '%s %s' % (code, reason) 176 if kwargs.get('message') is None: 177 kwargs['message'] = message 178 if kwargs.get('traceback') is None: 179 kwargs['traceback'] = '' 180 if kwargs.get('version') is None: 181 kwargs['version'] = cherrypy.__version__ 182 for k, v in iteritems(kwargs): 183 if v is None: 184 kwargs[k] = '' 185 else: 186 kwargs[k] = _escape(kwargs[k]) 187 188 pages = cherrypy.serving.request.error_page 189 error_page = pages.get(code) or pages.get('default') 190 if error_page: 191 try: 192 if hasattr(error_page, '__call__'): 193 return error_page(**kwargs) 194 return open(error_page, 'rb').read() % kwargs 195 except: 196 e = _format_exception(*_exc_info())[-1] 197 m = kwargs['message'] 198 if m: 199 m += '<br />' 200 m += 'In addition, the custom error page failed:\n<br />%s' % e 201 kwargs['message'] = m 202 203 return _HTTPErrorTemplate % kwargs 204 205 206 _ie_friendly_error_sizes = {400: 512, 207 403: 256, 208 404: 512, 209 405: 256, 210 406: 512, 211 408: 512, 212 409: 512, 213 410: 256, 214 500: 512, 215 501: 512, 216 505: 512} 217 218 def _be_ie_unfriendly(status): 219 import cherrypy 220 response = cherrypy.serving.response 221 s = _ie_friendly_error_sizes.get(status, 0) 222 if s: 223 s += 1 224 content = response.collapse_body() 225 l = len(content) 226 if l and l < s: 227 content = content + ' ' * (s - l) 228 response.body = content 229 response.headers['Content-Length'] = str(len(content)) 230 231 232 def format_exc(exc = None): 233 if exc is None: 234 exc = _exc_info() 235 if exc == (None, None, None): 236 return '' 237 import traceback 238 return ''.join(traceback.format_exception(*exc)) 239 240 241 def bare_error(extrabody = None): 242 body = 'Unrecoverable error in the server.' 243 if extrabody is not None: 244 if not isinstance(extrabody, str): 245 extrabody = extrabody.encode('utf-8') 246 body += '\n' + extrabody 247 return ('500 Internal Server Error', [('Content-Type', 'text/plain'), ('Content-Length', str(len(body)))], [body])