package CGI::Ex::Die; =head1 NAME CGI::Ex::Die - A CGI::Carp::FatalsToBrowser type utility. =cut ###----------------------------------------------------------------### # Copyright 2007 - Paul Seamons # # Distributed under the Perl Artistic License without warranty # ###----------------------------------------------------------------### use strict; use vars qw($VERSION $no_recurse $EXTENDED_ERRORS $SHOW_TRACE $IGNORE_EVAL $ERROR_TEMPLATE $LOG_HANDLER $FINAL_HANDLER ); use CGI::Ex; use CGI::Ex::Dump qw(debug ctrace dex_html); BEGIN { $VERSION = '2.16'; $SHOW_TRACE = 0 if ! defined $SHOW_TRACE; $IGNORE_EVAL = 0 if ! defined $IGNORE_EVAL; $EXTENDED_ERRORS = 1 if ! defined $EXTENDED_ERRORS; } ###----------------------------------------------------------------### sub import { my $class = shift; if ($#_ != -1) { if (($#_ + 1) % 2) { require Carp; &Carp::croak("Usage: use ".__PACKAGE__." register => 1"); } my %args = @_; ### may be called as # use CGI::Ex::Die register => 1; # OR # use CGI::Ex::Die register => [qw(die)]; if (! ref($args{register}) || grep {/die/} @{ $args{register} }) { $SIG{__DIE__} = \&die_handler; } $SHOW_TRACE = $args{'show_trace'} if exists $args{'show_trace'}; $IGNORE_EVAL = $args{'ignore_eval'} if exists $args{'ignore_eval'}; $EXTENDED_ERRORS = $args{'extended_errors'} if exists $args{'extended_errors'}; $ERROR_TEMPLATE = $args{'error_template'} if exists $args{'error_template'}; $LOG_HANDLER = $args{'log_handler'} if exists $args{'log_handler'}; $FINAL_HANDLER = $args{'final_handler'} if exists $args{'final_handler'}; } return 1; } ###----------------------------------------------------------------### sub die_handler { my $err = shift; die $err if $no_recurse; local $no_recurse = 1; ### test for eval - if eval - propogate it up if (! $IGNORE_EVAL) { if (! $ENV{MOD_PERL}) { my $n = 0; while (my $sub = (caller(++$n))[3]) { next if $sub !~ /eval/; die $err; # die and let the eval catch it } ### test for eval in a mod_perl environment } else { my $n = 0; my $found = 0; while (my $sub = (caller(++$n))[3]) { $found = $n if ! $found && $sub =~ /eval/; last if $sub =~ /^(Apache|ModPerl)::(PerlRun|Registry)/; } if ($found && $n - 1 != $found) { die $err; } } } ### decode the message if (ref $err) { } elsif ($EXTENDED_ERRORS && $err) { my $copy = "$err"; if ($copy =~ m|^Execution of ([/\w\.\-]+) aborted due to compilation errors|si) { eval { local $SIG{__WARN__} = sub {}; require $1; }; my $error = $@ || ''; $error =~ s|Compilation failed in require at [/\w/\.\-]+/Die.pm line \d+\.\s*$||is; chomp $error; $err .= "\n($error)\n"; } elsif ($copy =~ m|^syntax error at ([/\w.\-]+) line \d+, near|mi) { } } ### prepare common args my $msg = &CGI::Ex::Dump::_html_quote("$err"); $msg = "
Error: $msg
\n"; my $ctrace = ! $SHOW_TRACE ? "" : "
"
    . dex_html(ctrace)."
"; my $args = {err => "$err", msg => $msg, ctrace => $ctrace}; &$LOG_HANDLER($args) if $LOG_HANDLER; ### web based - give more options if ($ENV{REQUEST_METHOD}) { my $cgix = CGI::Ex->new; $| = 1; ### get the template and swap it in # allow for a sub that returns the template # or a string # or a filename (string starting with /) my $out; if ($ERROR_TEMPLATE) { $out = UNIVERSAL::isa($ERROR_TEMPLATE, 'CODE') ? &$ERROR_TEMPLATE($args) # coderef : (substr($ERROR_TEMPLATE,0,1) ne '/') ? $ERROR_TEMPLATE # html string : do { # filename if (open my $fh, $ERROR_TEMPLATE) { read($fh, my $str, -s $ERROR_TEMPLATE); $str; # return of the do } }; } if ($out) { $cgix->swap_template(\$out, $args); } else { $out = $msg.'

'.$ctrace; } ### similar to CGI::Carp if (my $r = $cgix->apache_request) { if ($r->bytes_sent) { $r->print($out); } else { $r->status(500); $r->custom_response(500, $out); } } else { $cgix->print_content_type; print $out; } } else { ### command line execution } &$FINAL_HANDLER($args) if $FINAL_HANDLER; die $err; } 1; __END__ =head1 SYNOPSIS use CGI::Ex::Die; $SIG{__DIE__} = \&CGI::Ex::Die::die_handler; # OR # use CGI::Ex::Die register => 1; =head1 DESCRIPTION This module is intended for showing more useful messages to the developer, should errors occur. This is a stub phase module. More features (error notification, custom error page, etc) will be added later. =head1 LICENSE This module may distributed under the same terms as Perl itself. =head1 AUTHORS Paul Seamons =cut