[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[cgiapp] Exception handling in C::A modules


Hi,

I've just run into a serious flaw with CGI::Application which completely breaks my exception handling.

I'm setting up a mod_perl system using C::A, and have a handler() that looks like this:

   sub handler : method {
       my($class, $r) = @_;

       local $SIG{__DIE__} = \&catcher;
       eval {
           my $app = $class->new(QUERY => MyQuery->new($r));
           $app->run();
       };

       return suppressed>handler($r) if $@;
       return OK;
   }

The catcher() method there installs a local() $SIG{__DIE__} handler that converts any "uncaught" exceptions raised from within the $app into instances of my own exception class (a sub-class of Exception::Class); I can then simply invoke that class' handler() method on the exception object if any exception was raised.

I have two major problems with C::A in trying to do this:

1. It installs CGI-Carp by default which wreaks havoc with the whole scheme of things by playing around with $SIG{__DIE__} and/or CORE::GLBOAL::die() (the latest version of CGI.pm does both in some setups!).

I've carped on about this before. I think the best solution is to have a new import() option asking C::A to not use CGI-Carp, but leave the default behaviour unchanged for backwards compatibility.

2. It executes the run-mode within an eval {} block of its own, catches any exceptions raised and then simply throws them again after having added a bit to them ("Error executing run mode...").

This makes the gross presumption that the run-mode didn't raise an exception *object*. If it did, then it just gets stringified into C::A's string error before getting thrown again. Thus, every exception that I ever raise myself gets caught, stringified and rethrown. My catcher() method catches it, of course, but I now find that *all* my exception objects have become "uncaught [string] exceptions" that my catcher() has caught. There is no point in any of the Exception::Classes that I've been carefully building!

Why bother catching the exception at all, just to throw it again? There's no point unless you're going to *do* something with it in some circumstances. Simply prepending a string to it just screws it up when it's an object. You could catch the exception and prepend a string only if it is already a string (not an object), but even then you're screwing up Exception::Class' record of where the exception was thrown from.

The attached patch (against 3.1) fixes both of these things.

PLEEEEEASE can we have this patch, or something equivalent, applied?

Hopefully,
- Steve
--- Application.pm.orig	2003-06-02 13:43:18.000000000 +0100
+++ Application.pm	2003-09-15 10:31:09.734713000 +0100
@@ -7,7 +7,18 @@
 $CGI::Application::VERSION = '3.1';
 
 
-use CGI::Carp;
+sub import {
+	my $cgicarp = 1;
+	foreach (@_) { $cgicarp = 0 if /^-nocgicarp$/io }
+	if ($cgicarp) {
+		require CGI::Carp;
+		CGI::Carp->import();
+	}
+	else {
+		require Carp;
+		Carp->import();
+	}
+}
 
 
 ###################################
@@ -139,8 +150,7 @@
 	}
 
 	# Process run mode!
-        my $body = eval { $autoload_mode ? $self->$rmeth($rm) : $self->$rmeth() };
-        die "Error executing run mode '$rm': $@" if $@;
+        my $body = $autoload_mode ? $self->$rmeth($rm) : $self->$rmeth();
 
         # Support scalar-ref for body return
         my $bodyref = (ref($body) eq 'SCALAR') ? $body : \$body;

---------------------------------------------------------------------
Web Archive:  http://www.mail-archive.com/suppressed/
              http://marc.theaimsgroup.com/?l=cgiapp&r=1&w=2
To unsubscribe, e-mail: suppressed
For additional commands, e-mail: suppressed

Mail converted by mhonarc 2.6.15
This archive provided courtesy of JSW4.NET, Internet Hosting Services for Small Business.