improved error handling for CGI/FastCGI
authorTero Marttila <terom@fixme.fi>
Mon, 16 Feb 2009 02:09:14 +0200
changeset 134 fbccc1648d79
parent 133 088aa2da1340
child 135 19ff083c2870
improved error handling for CGI/FastCGI
error.py
index.cgi
index.fcgi
wsgi.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/error.py	Mon Feb 16 02:09:14 2009 +0200
@@ -0,0 +1,36 @@
+"""
+    Build error messages
+"""
+
+import traceback, sys
+
+def build_error (exc_info=None) :
+    """
+        Dumps out a raw traceback of the given/current exception to stdout.
+
+        Returns a (status, content-type, body) tuple, with all components being non-unicode strs.
+    """
+
+
+    # default
+    if not exc_info :
+        exc_info = sys.exc_info()
+
+    # return
+    return ('500 Internal Server Error', 'text/html; charset=UTF-8', ("""\
+<html><head><title>500 Internal Server Error</title></head><body>
+<h1>Oops!</h1>
+<p>
+    An error occured, which was not logged, and will not be reported to anybody. It might be your fault, or it might be
+    the programmer's, but it's probably not mine. If you think you really care, you can try poking the administrator of
+    this site to see if they respond. 
+</p>
+<p>
+    If you do so, please include the following information:
+</p>
+<h2>Details:</h2>
+<pre>%(traceback)s</pre>
+</body></html>""" % dict(
+        traceback   = ''.join(traceback.format_exception(*exc_info))
+    )).encode('utf-8'))
+
--- a/index.cgi	Mon Feb 16 01:03:23 2009 +0200
+++ b/index.cgi	Mon Feb 16 02:09:14 2009 +0200
@@ -6,30 +6,22 @@
 
 def error () :
     """
-        Dumps out a raw traceback of the current exception to stdout, call from except
-    """
+        Dumps out a raw traceback of the current exception to stdout, call from except.
 
-    import traceback, sys
+        Used for low-level ImportError's
+    """
     
-    # HTTP headers
-    sys.stdout.write('Status: 500 Internal Server Error\r\n')
-    sys.stdout.write('Content-type: text/html\r\n')
+    # if this import fails, we're doomed
+    import sys, error
+    
+    # format info
+    status, content_type, body = error.build_error()
+    
+    # HTTP headers+body
+    sys.stdout.write('Status: %s\r\n' % status)
+    sys.stdout.write('Content-type: %s\r\n' % content_type)
     sys.stdout.write('\r\n')
-    sys.stdout.write("""\
-<html><head><title>500 Internal Server Error</title></head><body>
-<h1>Oops!</h1>
-<p>
-    An error occured, which was not logged, and will not be reported to anybody. It might be your fault, or it might be
-    the programmer's, but it's probably not mine. If you think you really care, you can try poking the administrator of
-    this site to see if they respond. 
-</p>
-<p>
-    If you do so, please include the following information:
-</p>
-<h2>Details:</h2>
-<pre>%(traceback)s</pre>
-</body></html>
-""" % dict(traceback=traceback.format_exc()))
+    sys.stdout.write(body)
     
 def main () :
     """
@@ -37,11 +29,11 @@
     """
 
     try :
-        from qmsk.web import wsgi, cgi_main
-        import urls
+        from qmsk.web import cgi_main
+        import wsgi
 
         # create app
-        app = wsgi.Application(urls.mapper)
+        app = wsgi.Application()
         
         # run once
         cgi_main.run(app)
--- a/index.fcgi	Mon Feb 16 01:03:23 2009 +0200
+++ b/index.fcgi	Mon Feb 16 02:09:14 2009 +0200
@@ -2,28 +2,25 @@
 # :set filetype=py
 
 """
-    CGI mode using qmsk.web.fastcgi_main
+    FastCGI mode using qmsk.web.fastcgi_main
 """
 
+from qmsk.web import fastcgi_main
+
+# XXX: error handling for imports? Lighttp sucks hard at this
+import wsgi
+
 def main () :
     """
-        Build our wsgi.Application and run
+        Build our WSGIApplication and run
     """
 
-    try :
-        from qmsk.web import wsgi, fastcgi_main
-        import urls
-
-        # create app
-        app = wsgi.Application(urls.mapper)
+    # create app
+    app = wsgi.Application()
 
-        # run once
-        fastcgi_main.run(app)
+    # run once
+    fastcgi_main.run(app)
 
-    except :
-        # display error on stdout
-        cgi_main.error()
-    
 if __name__ == '__main__' :
     main()
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wsgi.py	Mon Feb 16 02:09:14 2009 +0200
@@ -0,0 +1,31 @@
+"""
+    Our custom WSGI application
+"""
+
+from qmsk.web import wsgi
+
+import urls, error
+
+# our custom app with custom error() method
+class Application (wsgi.Application) :
+    def __init__ (self) :
+        """
+            Construct wsgi.Application with our URLMapper
+        """
+
+        super(Application, self).__init__(urls.mapper)
+    
+    def handle_error (self, exc_info, env, start_response) :
+        """
+            Use error.build_error and return that
+        """
+        
+        # get info
+        status, content_type, body = error.build_error()
+
+        # headers
+        start_response(status, [('Content-type', content_type)], exc_info)
+
+        # body
+        return body
+