def getErrorPage(status, **kwargs): """Return an HTML page, containing a pretty error response. status should be an int or a str. kwargs will be interpolated into the page template. """ code, reason, message = cptools.validStatus(status) # We can't use setdefault here, because some # callers send None for kwarg values. if kwargs.get('status') is None: kwargs['status'] = "%s %s" % (code, reason) if kwargs.get('message') is None: kwargs['message'] = message if kwargs.get('traceback') is None: kwargs['traceback'] = '' if kwargs.get('version') is None: kwargs['version'] = cherrypy.__version__ for k, v in kwargs.iteritems(): if v is None: kwargs[k] = "" else: kwargs[k] = cgi.escape(kwargs[k]) template = _HTTPErrorTemplate errorPageFile = cherrypy.config.get('errorPage.%s' % code, '') if errorPageFile: try: template = file(errorPageFile, 'rb').read() except: m = kwargs['message'] if m: m += "<br />" m += ("In addition, the custom error page " "failed:\n<br />%s" % (sys.exc_info()[1])) kwargs['message'] = m return template % kwargs
def finalize(): """Transform headerMap (and cookies) into cherrypy.response.headers.""" response = cherrypy.response code, reason, _ = cptools.validStatus(response.status) response.status = "%s %s" % (code, reason) if response.body is None: response.body = [] stream = cherrypy.config.get("streamResponse", False) # OPTIONS requests MUST include a Content-Length of 0 if no body. # Just punt and figure Content-Length for all OPTIONS requests. if cherrypy.request.method == "OPTIONS": stream = False if stream: try: del response.headerMap['Content-Length'] except KeyError: pass else: # Responses which are not streamed should have a Content-Length, # but allow user code to set Content-Length if desired. if response.headerMap.get('Content-Length') is None: content = ''.join([chunk for chunk in response.body]) response.body = [content] response.headerMap['Content-Length'] = len(content) # For some statuses, Internet Explorer 5+ shows "friendly error messages" # instead of our response.body if the body is smaller than a given size. # Fix this by returning a body over that size (by adding whitespace). # See http://support.microsoft.com/kb/q218155/ s = int(response.status.split(" ")[0]) s = _ie_friendly_error_sizes.get(s, 0) if s: s += 1 # Since we are issuing an HTTP error status, we assume that # the entity is short, and we should just collapse it. content = ''.join([chunk for chunk in response.body]) response.body = [content] l = len(content) if l and l < s: # IN ADDITION: the response must be written to IE # in one chunk or it will still get replaced! Bah. response.body = [response.body[0] + (" " * (s - l))] response.headerMap['Content-Length'] = s # Headers headers = [] for key, valueList in response.headerMap.iteritems(): order = _header_order_map.get(key, 3) if not isinstance(valueList, list): valueList = [valueList] for value in valueList: headers.append((order, (key, str(value)))) # RFC 2616: '... it is "good practice" to send general-header fields # first, followed by request-header or response-header fields, and # ending with the entity-header fields.' headers.sort() response.headers = [item[1] for item in headers] cookie = response.simpleCookie.output() if cookie: lines = cookie.split("\n") for line in lines: name, value = line.split(": ", 1) response.headers.append((name, value))