durusmail: quixote-users: cgitb patch
Misc feedback
2002-01-28
2002-01-28
2002-01-29
David Ascher (2 parts)
cgitb patch
2002-01-30
2002-01-30
2002-01-30
2002-01-30
2002-01-30
2002-01-30
2002-01-30
cgitb patch
Andrew Kuchling
2002-01-30
On Mon, Jan 28, 2002 at 09:48:32PM -0800, David Ascher wrote:
>My contribution is attached -- a patch (probably needs tweaking) to
>enable cgitb if it's been enabled.  With the patch applied, you can add

I like this patch, though I can agree with David's point about cgitb's
colour scheme.  However, the patch turns up a Quixote misdesign.
Publisher.format_internal_error() reads like this:

    def format_internal_error (self, request, error_message):
        if self.config.display_exceptions:
            # XXX note the next line!
            request.response.set_header("Content-Type", "text/plain")
            return error_message
        else:
            request.response.set_header("Content-Type", "text/html")
            admin = request.environ.get('SERVER_ADMIN',
                                   "email address unknown")
            return INTERNAL_ERROR_MESSAGE % admin

If display_exceptions is true, this always sets the content-type to
text/plain.  I submit that this is bogus; the caller is providing the
content of the message, and should therefore set the content-type to
text or HTML or whatever it sees fit.  (If you want to return a JPEG
in case of errors, go ahead!)  In the other format_*_error() methods,
the methods themselves create the message, and therefore should
specify the content-type.

A revised version of the patch is below, fixing this; it also factors
out the actual generation of error pages into separate private
methods, and adds a typo fix.  Votes?

--amk                                                  (www.amk.ca)
If I knew everything that was about to happen, where would the fun be?
    -- The Doctor, in "The Keeper of Traken"


Index: publish.py
===================================================================
RCS file: /projects/cvsroot/mems/quixote/publish.py,v
retrieving revision 1.107
diff -u -r1.107 publish.py
--- publish.py  24 Jan 2002 16:08:53 -0000      1.107
+++ publish.py  30 Jan 2002 23:00:30 -0000
@@ -7,6 +7,7 @@

 import sys, os, traceback, cStringIO
 import time, types, socket, re
+import cgitb

 from quixote import errors, fcgi
 from quixote.http_request import HTTPRequest
@@ -361,11 +362,10 @@
         Format a response after a non-PublishError exception.
         Applications may wish to subclass this method but they should do
         so carefully.  The application could be broken badly when this
-        method is called.  This probably best to keep the formatting
+        method is called.  It's probably best to keep the formatting
         simple.
         """
         if self.config.display_exceptions:
-            request.response.set_header("Content-Type", "text/plain")
             return error_message
         else:
             request.response.set_header("Content-Type", "text/html")
@@ -390,7 +390,32 @@
         error_summary = traceback.format_exception_only(exc_type, exc_value)
         error_summary = error_summary[0][0:-1] # de-listify and strip newline
         error_file = cStringIO.StringIO()
+
+        if isinstance(sys.excepthook, cgitb.Hook):
+            self._generate_cgitb_error(error_file,
+                                       request, original_response,
+                                       exc_type, exc_value, tb)
+        else:
+            self._generate_plaintext_error(error_file,
+                                           request, original_response,
+                                           exc_type, exc_value, tb)
+
+        error_msg = error_file.getvalue()
+        self.error_log.write(error_msg)
+        if request.session is not None:
+            request.session.dump(file=self.error_log)
+
+        if self.config.error_email:
+            self.mail_error(error_msg, error_summary)
+
+        request.response.set_status(500)
+        return self.format_internal_error(request, error_msg)
+

+    def _generate_plaintext_error (self,
+                                   error_file, request, original_response,
+                                   exc_type, exc_value, tb):
+        request.response.set_header("Content-Type", "text/plain")
         #self.debug("report_error: exception = %s: %s" % (exc_type, exc_value))

         # record the time of the error
@@ -409,17 +434,17 @@
                            '=================\n')
         original_response.write(error_file)
         error_file.write('='*65 + '\n')
-
-        error_msg = error_file.getvalue()
-        self.error_log.write(error_msg)
-        if request.session is not None:
-            request.session.dump(file=self.error_log)
-
-        if self.config.error_email:
-            self.mail_error(error_msg, error_summary)
-
-        request.response.set_status(500)
-        return self.format_internal_error(request, error_msg)
+
+    def _generate_cgitb_error (self, error_file, request, original_response,
+                               exc_type, exc_value, tb):
+        request.response.set_header("Content-Type", "text/html")
+        hook = cgitb.Hook(file=error_file)
+        hook(exc_type, exc_value, tb)
+        error_file.write('

Original Request

') + error_file.write(request.dump_html()) + error_file.write('

Original Response

')
+        original_response.write(error_file)
+        error_file.write('
') def mail_error (self, msg, error_summary): """Send an email notifying someone of a traceback."""
reply