import sys import traceback import cgi try: from cStringIO import StringIO except ImportError: from StringIO import StringIO from paste.exceptions import formatter, collector, reporter from paste import wsgilib class ErrorMiddleware(object): def __init__(self, application, show_exceptions=True, email_exceptions_to=[], smtp_server='localhost'): self.application = application self.show_exceptions = show_exceptions self.email_exceptions_to = email_exceptions_to self.smtp_server = smtp_server def __call__(self, environ, start_response): # We want to be careful about not sending headers twice, # and the content type that the app has committed to (if there # is an exception in the iterator body of the response) started = [] def detect_start_response(status, headers): started.append(True) return start_response(status, headers) try: __traceback_supplement__ = Supplement, self, environ app_iter = self.application(environ, detect_start_response) return self.catching_iter(app_iter, environ) except: if not started: start_response('500 Internal Server Error', [('content-type', 'text/html')]) # @@: it would be nice to deal with bad content types here dummy_file = StringIO() response = self.exception_handler(sys.exc_info(), environ) return [response] def catching_iter(self, iter, environ): __traceback_supplement__ = Supplement, self, environ if not iter: raise StopIteration error_on_close = False try: for v in iter: yield v if hasattr(iter, 'close'): error_on_close = True iter.close() except: response = self.exception_handler(sys.exc_info(), environ) if not error_on_close and hasattr(iter, 'close'): try: iter.close() except: close_response = self.exception_handler( sys.exc_info(), environ) response += ( '
Additionally an error occurred while sending the %s report:
%s""" % ( cgi.escape(str(reporter)), output.getvalue()) else: return '' class Supplement(object): def __init__(self, middleware, environ): self.middleware = middleware self.environ = environ self.source_url = wsgilib.construct_url(environ) def extraData(self): data = {} cgi_vars = data[('extra', 'CGI Variables')] = {} wsgi_vars = data[('extra', 'WSGI Variables')] = {} hide_vars = ['paste.config', 'wsgi.errors', 'wsgi.input', 'wsgi.multithread', 'wsgi.multiprocess', 'wsgi.run_once', 'wsgi.version', 'wsgi.url_scheme'] for name, value in self.environ.items(): if name.upper() == name: if value: cgi_vars[name] = value elif name not in hide_vars: wsgi_vars[name] = value if self.environ['wsgi.version'] != (1, 0): wsgi_vars['wsgi.version'] = self.environ['wsgi.version'] proc_desc = tuple([int(bool(self.environ[key])) for key in ('wsgi.multiprocess', 'wsgi.multithread', 'wsgi.run_once')]) wsgi_vars['wsgi process'] = self.process_combos[proc_desc] data[('extra', 'Configuration')] = dict(self.environ['paste.config']) return data process_combos = { # multiprocess, multithread, run_once (0, 0, 0): 'Non-concurrent server', (0, 1, 0): 'Multithreaded', (1, 0, 0): 'Multiprocess', (1, 1, 0): 'Multi process AND threads (?)', (0, 0, 1): 'Non-concurrent CGI', (0, 1, 1): 'Multithread CGI (?)', (1, 0, 1): 'CGI', (1, 1, 1): 'Multi thread/process CGI (?)', } css = """ table { width: 100%; } tr.header { background-color: #006; color: #fff; } tr.even { background-color: #ddd; } table.variables td { verticle-align: top; overflow: auto; } a.button { background-color: #ccc; border: 2px outset #aaa; color: #000; text-decoration: none; } a.button:hover { background-color: #ddd; } """