xref: /onnv-gate/usr/src/cmd/perl/5.8.4/distrib/lib/CGI/Carp.pm (revision 6287:9a1f5d2c8dd8)
10Sstevel@tonic-gatepackage CGI::Carp;
20Sstevel@tonic-gate
30Sstevel@tonic-gate=head1 NAME
40Sstevel@tonic-gate
50Sstevel@tonic-gateB<CGI::Carp> - CGI routines for writing to the HTTPD (or other) error log
60Sstevel@tonic-gate
70Sstevel@tonic-gate=head1 SYNOPSIS
80Sstevel@tonic-gate
90Sstevel@tonic-gate    use CGI::Carp;
100Sstevel@tonic-gate
110Sstevel@tonic-gate    croak "We're outta here!";
120Sstevel@tonic-gate    confess "It was my fault: $!";
130Sstevel@tonic-gate    carp "It was your fault!";
140Sstevel@tonic-gate    warn "I'm confused";
150Sstevel@tonic-gate    die  "I'm dying.\n";
160Sstevel@tonic-gate
170Sstevel@tonic-gate    use CGI::Carp qw(cluck);
180Sstevel@tonic-gate    cluck "I wouldn't do that if I were you";
190Sstevel@tonic-gate
200Sstevel@tonic-gate    use CGI::Carp qw(fatalsToBrowser);
210Sstevel@tonic-gate    die "Fatal error messages are now sent to browser";
220Sstevel@tonic-gate
230Sstevel@tonic-gate=head1 DESCRIPTION
240Sstevel@tonic-gate
250Sstevel@tonic-gateCGI scripts have a nasty habit of leaving warning messages in the error
260Sstevel@tonic-gatelogs that are neither time stamped nor fully identified.  Tracking down
270Sstevel@tonic-gatethe script that caused the error is a pain.  This fixes that.  Replace
280Sstevel@tonic-gatethe usual
290Sstevel@tonic-gate
300Sstevel@tonic-gate    use Carp;
310Sstevel@tonic-gate
320Sstevel@tonic-gatewith
330Sstevel@tonic-gate
340Sstevel@tonic-gate    use CGI::Carp
350Sstevel@tonic-gate
360Sstevel@tonic-gateAnd the standard warn(), die (), croak(), confess() and carp() calls
370Sstevel@tonic-gatewill automagically be replaced with functions that write out nicely
380Sstevel@tonic-gatetime-stamped messages to the HTTP server error log.
390Sstevel@tonic-gate
400Sstevel@tonic-gateFor example:
410Sstevel@tonic-gate
420Sstevel@tonic-gate   [Fri Nov 17 21:40:43 1995] test.pl: I'm confused at test.pl line 3.
430Sstevel@tonic-gate   [Fri Nov 17 21:40:43 1995] test.pl: Got an error message: Permission denied.
440Sstevel@tonic-gate   [Fri Nov 17 21:40:43 1995] test.pl: I'm dying.
450Sstevel@tonic-gate
460Sstevel@tonic-gate=head1 REDIRECTING ERROR MESSAGES
470Sstevel@tonic-gate
480Sstevel@tonic-gateBy default, error messages are sent to STDERR.  Most HTTPD servers
490Sstevel@tonic-gatedirect STDERR to the server's error log.  Some applications may wish
500Sstevel@tonic-gateto keep private error logs, distinct from the server's error log, or
510Sstevel@tonic-gatethey may wish to direct error messages to STDOUT so that the browser
520Sstevel@tonic-gatewill receive them.
530Sstevel@tonic-gate
540Sstevel@tonic-gateThe C<carpout()> function is provided for this purpose.  Since
550Sstevel@tonic-gatecarpout() is not exported by default, you must import it explicitly by
560Sstevel@tonic-gatesaying
570Sstevel@tonic-gate
580Sstevel@tonic-gate   use CGI::Carp qw(carpout);
590Sstevel@tonic-gate
600Sstevel@tonic-gateThe carpout() function requires one argument, which should be a
610Sstevel@tonic-gatereference to an open filehandle for writing errors.  It should be
620Sstevel@tonic-gatecalled in a C<BEGIN> block at the top of the CGI application so that
630Sstevel@tonic-gatecompiler errors will be caught.  Example:
640Sstevel@tonic-gate
650Sstevel@tonic-gate   BEGIN {
660Sstevel@tonic-gate     use CGI::Carp qw(carpout);
670Sstevel@tonic-gate     open(LOG, ">>/usr/local/cgi-logs/mycgi-log") or
680Sstevel@tonic-gate       die("Unable to open mycgi-log: $!\n");
690Sstevel@tonic-gate     carpout(LOG);
700Sstevel@tonic-gate   }
710Sstevel@tonic-gate
720Sstevel@tonic-gatecarpout() does not handle file locking on the log for you at this point.
730Sstevel@tonic-gate
740Sstevel@tonic-gateThe real STDERR is not closed -- it is moved to CGI::Carp::SAVEERR.  Some
750Sstevel@tonic-gateservers, when dealing with CGI scripts, close their connection to the
760Sstevel@tonic-gatebrowser when the script closes STDOUT and STDERR.  CGI::Carp::SAVEERR is there to
770Sstevel@tonic-gateprevent this from happening prematurely.
780Sstevel@tonic-gate
790Sstevel@tonic-gateYou can pass filehandles to carpout() in a variety of ways.  The "correct"
800Sstevel@tonic-gateway according to Tom Christiansen is to pass a reference to a filehandle
810Sstevel@tonic-gateGLOB:
820Sstevel@tonic-gate
830Sstevel@tonic-gate    carpout(\*LOG);
840Sstevel@tonic-gate
850Sstevel@tonic-gateThis looks weird to mere mortals however, so the following syntaxes are
860Sstevel@tonic-gateaccepted as well:
870Sstevel@tonic-gate
880Sstevel@tonic-gate    carpout(LOG);
890Sstevel@tonic-gate    carpout(main::LOG);
900Sstevel@tonic-gate    carpout(main'LOG);
910Sstevel@tonic-gate    carpout(\LOG);
920Sstevel@tonic-gate    carpout(\'main::LOG');
930Sstevel@tonic-gate
940Sstevel@tonic-gate    ... and so on
950Sstevel@tonic-gate
960Sstevel@tonic-gateFileHandle and other objects work as well.
970Sstevel@tonic-gate
980Sstevel@tonic-gateUse of carpout() is not great for performance, so it is recommended
990Sstevel@tonic-gatefor debugging purposes or for moderate-use applications.  A future
1000Sstevel@tonic-gateversion of this module may delay redirecting STDERR until one of the
1010Sstevel@tonic-gateCGI::Carp methods is called to prevent the performance hit.
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate=head1 MAKING PERL ERRORS APPEAR IN THE BROWSER WINDOW
1040Sstevel@tonic-gate
105*6287Sps156622If you want to send fatal (die, confess) errors to the browser, ask to
1060Sstevel@tonic-gateimport the special "fatalsToBrowser" subroutine:
1070Sstevel@tonic-gate
1080Sstevel@tonic-gate    use CGI::Carp qw(fatalsToBrowser);
1090Sstevel@tonic-gate    die "Bad error here";
1100Sstevel@tonic-gate
1110Sstevel@tonic-gateFatal errors will now be echoed to the browser as well as to the log.  CGI::Carp
1120Sstevel@tonic-gatearranges to send a minimal HTTP header to the browser so that even errors that
1130Sstevel@tonic-gateoccur in the early compile phase will be seen.
1140Sstevel@tonic-gateNonfatal errors will still be directed to the log file only (unless redirected
1150Sstevel@tonic-gatewith carpout).
1160Sstevel@tonic-gate
117*6287Sps156622Note that fatalsToBrowser does B<not> work with mod_perl version 2.0
118*6287Sps156622and higher.
119*6287Sps156622
1200Sstevel@tonic-gate=head2 Changing the default message
1210Sstevel@tonic-gate
1220Sstevel@tonic-gateBy default, the software error message is followed by a note to
1230Sstevel@tonic-gatecontact the Webmaster by e-mail with the time and date of the error.
1240Sstevel@tonic-gateIf this message is not to your liking, you can change it using the
1250Sstevel@tonic-gateset_message() routine.  This is not imported by default; you should
1260Sstevel@tonic-gateimport it on the use() line:
1270Sstevel@tonic-gate
1280Sstevel@tonic-gate    use CGI::Carp qw(fatalsToBrowser set_message);
1290Sstevel@tonic-gate    set_message("It's not a bug, it's a feature!");
1300Sstevel@tonic-gate
1310Sstevel@tonic-gateYou may also pass in a code reference in order to create a custom
1320Sstevel@tonic-gateerror message.  At run time, your code will be called with the text
1330Sstevel@tonic-gateof the error message that caused the script to die.  Example:
1340Sstevel@tonic-gate
1350Sstevel@tonic-gate    use CGI::Carp qw(fatalsToBrowser set_message);
1360Sstevel@tonic-gate    BEGIN {
1370Sstevel@tonic-gate       sub handle_errors {
1380Sstevel@tonic-gate          my $msg = shift;
1390Sstevel@tonic-gate          print "<h1>Oh gosh</h1>";
1400Sstevel@tonic-gate          print "<p>Got an error: $msg</p>";
1410Sstevel@tonic-gate      }
1420Sstevel@tonic-gate      set_message(\&handle_errors);
1430Sstevel@tonic-gate    }
1440Sstevel@tonic-gate
1450Sstevel@tonic-gateIn order to correctly intercept compile-time errors, you should call
1460Sstevel@tonic-gateset_message() from within a BEGIN{} block.
1470Sstevel@tonic-gate
148*6287Sps156622=head1 DOING MORE THAN PRINTING A MESSAGE IN THE EVENT OF PERL ERRORS
149*6287Sps156622
150*6287Sps156622If fatalsToBrowser in conjunction with set_message does not provide
151*6287Sps156622you with all of the functionality you need, you can go one step
152*6287Sps156622further by specifying a function to be executed any time a script
153*6287Sps156622calls "die", has a syntax error, or dies unexpectedly at runtime
154*6287Sps156622with a line like "undef->explode();".
155*6287Sps156622
156*6287Sps156622    use CGI::Carp qw(set_die_handler);
157*6287Sps156622    BEGIN {
158*6287Sps156622       sub handle_errors {
159*6287Sps156622          my $msg = shift;
160*6287Sps156622          print "content-type: text/html\n\n";
161*6287Sps156622          print "<h1>Oh gosh</h1>";
162*6287Sps156622          print "<p>Got an error: $msg</p>";
163*6287Sps156622
164*6287Sps156622          #proceed to send an email to a system administrator,
165*6287Sps156622          #write a detailed message to the browser and/or a log,
166*6287Sps156622          #etc....
167*6287Sps156622      }
168*6287Sps156622      set_die_handler(\&handle_errors);
169*6287Sps156622    }
170*6287Sps156622
171*6287Sps156622Notice that if you use set_die_handler(), you must handle sending
172*6287Sps156622HTML headers to the browser yourself if you are printing a message.
173*6287Sps156622
174*6287Sps156622If you use set_die_handler(), you will most likely interfere with
175*6287Sps156622the behavior of fatalsToBrowser, so you must use this or that, not
176*6287Sps156622both.
177*6287Sps156622
178*6287Sps156622Using set_die_handler() sets SIG{__DIE__} (as does fatalsToBrowser),
179*6287Sps156622and there is only one SIG{__DIE__}. This means that if you are
180*6287Sps156622attempting to set SIG{__DIE__} yourself, you may interfere with
181*6287Sps156622this module's functionality, or this module may interfere with
182*6287Sps156622your module's functionality.
183*6287Sps156622
1840Sstevel@tonic-gate=head1 MAKING WARNINGS APPEAR AS HTML COMMENTS
1850Sstevel@tonic-gate
1860Sstevel@tonic-gateIt is now also possible to make non-fatal errors appear as HTML
1870Sstevel@tonic-gatecomments embedded in the output of your program.  To enable this
1880Sstevel@tonic-gatefeature, export the new "warningsToBrowser" subroutine.  Since sending
1890Sstevel@tonic-gatewarnings to the browser before the HTTP headers have been sent would
1900Sstevel@tonic-gatecause an error, any warnings are stored in an internal buffer until
1910Sstevel@tonic-gateyou call the warningsToBrowser() subroutine with a true argument:
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate    use CGI::Carp qw(fatalsToBrowser warningsToBrowser);
1940Sstevel@tonic-gate    use CGI qw(:standard);
1950Sstevel@tonic-gate    print header();
1960Sstevel@tonic-gate    warningsToBrowser(1);
1970Sstevel@tonic-gate
1980Sstevel@tonic-gateYou may also give a false argument to warningsToBrowser() to prevent
1990Sstevel@tonic-gatewarnings from being sent to the browser while you are printing some
2000Sstevel@tonic-gatecontent where HTML comments are not allowed:
2010Sstevel@tonic-gate
2020Sstevel@tonic-gate    warningsToBrowser(0);    # disable warnings
2030Sstevel@tonic-gate    print "<script type=\"text/javascript\"><!--\n";
2040Sstevel@tonic-gate    print_some_javascript_code();
2050Sstevel@tonic-gate    print "//--></script>\n";
2060Sstevel@tonic-gate    warningsToBrowser(1);    # re-enable warnings
2070Sstevel@tonic-gate
2080Sstevel@tonic-gateNote: In this respect warningsToBrowser() differs fundamentally from
2090Sstevel@tonic-gatefatalsToBrowser(), which you should never call yourself!
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate=head1 OVERRIDING THE NAME OF THE PROGRAM
2120Sstevel@tonic-gate
2130Sstevel@tonic-gateCGI::Carp includes the name of the program that generated the error or
2140Sstevel@tonic-gatewarning in the messages written to the log and the browser window.
2150Sstevel@tonic-gateSometimes, Perl can get confused about what the actual name of the
2160Sstevel@tonic-gateexecuted program was.  In these cases, you can override the program
2170Sstevel@tonic-gatename that CGI::Carp will use for all messages.
2180Sstevel@tonic-gate
2190Sstevel@tonic-gateThe quick way to do that is to tell CGI::Carp the name of the program
2200Sstevel@tonic-gatein its use statement.  You can do that by adding
2210Sstevel@tonic-gate"name=cgi_carp_log_name" to your "use" statement.  For example:
2220Sstevel@tonic-gate
2230Sstevel@tonic-gate    use CGI::Carp qw(name=cgi_carp_log_name);
2240Sstevel@tonic-gate
2250Sstevel@tonic-gate.  If you want to change the program name partway through the program,
2260Sstevel@tonic-gateyou can use the C<set_progname()> function instead.  It is not
2270Sstevel@tonic-gateexported by default, you must import it explicitly by saying
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate    use CGI::Carp qw(set_progname);
2300Sstevel@tonic-gate
2310Sstevel@tonic-gateOnce you've done that, you can change the logged name of the program
2320Sstevel@tonic-gateat any time by calling
2330Sstevel@tonic-gate
2340Sstevel@tonic-gate    set_progname(new_program_name);
2350Sstevel@tonic-gate
2360Sstevel@tonic-gateYou can set the program back to the default by calling
2370Sstevel@tonic-gate
2380Sstevel@tonic-gate    set_progname(undef);
2390Sstevel@tonic-gate
2400Sstevel@tonic-gateNote that this override doesn't happen until after the program has
2410Sstevel@tonic-gatecompiled, so any compile-time errors will still show up with the
2420Sstevel@tonic-gatenon-overridden program name
2430Sstevel@tonic-gate
2440Sstevel@tonic-gate=head1 CHANGE LOG
2450Sstevel@tonic-gate
246*6287Sps1566221.29 Patch from Peter Whaite to fix the unfixable problem of CGI::Carp
247*6287Sps156622     not behaving correctly in an eval() context.
248*6287Sps156622
2490Sstevel@tonic-gate1.05 carpout() added and minor corrections by Marc Hedlund
2500Sstevel@tonic-gate     <hedlund@best.com> on 11/26/95.
2510Sstevel@tonic-gate
2520Sstevel@tonic-gate1.06 fatalsToBrowser() no longer aborts for fatal errors within
2530Sstevel@tonic-gate     eval() statements.
2540Sstevel@tonic-gate
2550Sstevel@tonic-gate1.08 set_message() added and carpout() expanded to allow for FileHandle
2560Sstevel@tonic-gate     objects.
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate1.09 set_message() now allows users to pass a code REFERENCE for
2590Sstevel@tonic-gate     really custom error messages.  croak and carp are now
2600Sstevel@tonic-gate     exported by default.  Thanks to Gunther Birznieks for the
2610Sstevel@tonic-gate     patches.
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate1.10 Patch from Chris Dean (ctdean@cogit.com) to allow
2640Sstevel@tonic-gate     module to run correctly under mod_perl.
2650Sstevel@tonic-gate
2660Sstevel@tonic-gate1.11 Changed order of &gt; and &lt; escapes.
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate1.12 Changed die() on line 217 to CORE::die to avoid B<-w> warning.
2690Sstevel@tonic-gate
2700Sstevel@tonic-gate1.13 Added cluck() to make the module orthogonal with Carp.
2710Sstevel@tonic-gate     More mod_perl related fixes.
2720Sstevel@tonic-gate
2730Sstevel@tonic-gate1.20 Patch from Ilmari Karonen (perl@itz.pp.sci.fi):  Added
2740Sstevel@tonic-gate     warningsToBrowser().  Replaced <CODE> tags with <PRE> in
2750Sstevel@tonic-gate     fatalsToBrowser() output.
2760Sstevel@tonic-gate
2770Sstevel@tonic-gate1.23 ineval() now checks both $^S and inspects the message for the "eval" pattern
2780Sstevel@tonic-gate     (hack alert!) in order to accomodate various combinations of Perl and
2790Sstevel@tonic-gate     mod_perl.
2800Sstevel@tonic-gate
2810Sstevel@tonic-gate1.24 Patch from Scott Gifford (sgifford@suspectclass.com): Add support
2820Sstevel@tonic-gate     for overriding program name.
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate1.26 Replaced CORE::GLOBAL::die with the evil $SIG{__DIE__} because the
2850Sstevel@tonic-gate     former isn't working in some people's hands.  There is no such thing
2860Sstevel@tonic-gate     as reliable exception handling in Perl.
2870Sstevel@tonic-gate
2880Sstevel@tonic-gate1.27 Replaced tell STDOUT with bytes=tell STDOUT.
2890Sstevel@tonic-gate
2900Sstevel@tonic-gate=head1 AUTHORS
2910Sstevel@tonic-gate
2920Sstevel@tonic-gateCopyright 1995-2002, Lincoln D. Stein.  All rights reserved.
2930Sstevel@tonic-gate
2940Sstevel@tonic-gateThis library is free software; you can redistribute it and/or modify
2950Sstevel@tonic-gateit under the same terms as Perl itself.
2960Sstevel@tonic-gate
2970Sstevel@tonic-gateAddress bug reports and comments to: lstein@cshl.org
2980Sstevel@tonic-gate
2990Sstevel@tonic-gate=head1 SEE ALSO
3000Sstevel@tonic-gate
3010Sstevel@tonic-gateCarp, CGI::Base, CGI::BasePlus, CGI::Request, CGI::MiniSvr, CGI::Form,
3020Sstevel@tonic-gateCGI::Response
3030Sstevel@tonic-gate    if (defined($CGI::Carp::PROGNAME))
3040Sstevel@tonic-gate    {
3050Sstevel@tonic-gate      $file = $CGI::Carp::PROGNAME;
3060Sstevel@tonic-gate    }
3070Sstevel@tonic-gate
3080Sstevel@tonic-gate=cut
3090Sstevel@tonic-gate
3100Sstevel@tonic-gaterequire 5.000;
3110Sstevel@tonic-gateuse Exporter;
3120Sstevel@tonic-gate#use Carp;
3130Sstevel@tonic-gateBEGIN {
3140Sstevel@tonic-gate  require Carp;
3150Sstevel@tonic-gate  *CORE::GLOBAL::die = \&CGI::Carp::die;
3160Sstevel@tonic-gate}
3170Sstevel@tonic-gate
3180Sstevel@tonic-gateuse File::Spec;
3190Sstevel@tonic-gate
3200Sstevel@tonic-gate@ISA = qw(Exporter);
3210Sstevel@tonic-gate@EXPORT = qw(confess croak carp);
322*6287Sps156622@EXPORT_OK = qw(carpout fatalsToBrowser warningsToBrowser wrap set_message set_die_handler set_progname cluck ^name= die);
3230Sstevel@tonic-gate
3240Sstevel@tonic-gate$main::SIG{__WARN__}=\&CGI::Carp::warn;
3250Sstevel@tonic-gate
326*6287Sps156622$CGI::Carp::VERSION     = '1.30';
327*6287Sps156622$CGI::Carp::CUSTOM_MSG  = undef;
328*6287Sps156622$CGI::Carp::DIE_HANDLER = undef;
3290Sstevel@tonic-gate
3300Sstevel@tonic-gate
3310Sstevel@tonic-gate# fancy import routine detects and handles 'errorWrap' specially.
3320Sstevel@tonic-gatesub import {
3330Sstevel@tonic-gate    my $pkg = shift;
3340Sstevel@tonic-gate    my(%routines);
3350Sstevel@tonic-gate    my(@name);
3360Sstevel@tonic-gate    if (@name=grep(/^name=/,@_))
3370Sstevel@tonic-gate      {
3380Sstevel@tonic-gate        my($n) = (split(/=/,$name[0]))[1];
3390Sstevel@tonic-gate        set_progname($n);
3400Sstevel@tonic-gate        @_=grep(!/^name=/,@_);
3410Sstevel@tonic-gate      }
3420Sstevel@tonic-gate
3430Sstevel@tonic-gate    grep($routines{$_}++,@_,@EXPORT);
3440Sstevel@tonic-gate    $WRAP++ if $routines{'fatalsToBrowser'} || $routines{'wrap'};
3450Sstevel@tonic-gate    $WARN++ if $routines{'warningsToBrowser'};
3460Sstevel@tonic-gate    my($oldlevel) = $Exporter::ExportLevel;
3470Sstevel@tonic-gate    $Exporter::ExportLevel = 1;
3480Sstevel@tonic-gate    Exporter::import($pkg,keys %routines);
3490Sstevel@tonic-gate    $Exporter::ExportLevel = $oldlevel;
3500Sstevel@tonic-gate    $main::SIG{__DIE__} =\&CGI::Carp::die if $routines{'fatalsToBrowser'};
3510Sstevel@tonic-gate#    $pkg->export('CORE::GLOBAL','die');
3520Sstevel@tonic-gate}
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate# These are the originals
3550Sstevel@tonic-gatesub realwarn { CORE::warn(@_); }
3560Sstevel@tonic-gatesub realdie { CORE::die(@_); }
3570Sstevel@tonic-gate
3580Sstevel@tonic-gatesub id {
3590Sstevel@tonic-gate    my $level = shift;
3600Sstevel@tonic-gate    my($pack,$file,$line,$sub) = caller($level);
3610Sstevel@tonic-gate    my($dev,$dirs,$id) = File::Spec->splitpath($file);
3620Sstevel@tonic-gate    return ($file,$line,$id);
3630Sstevel@tonic-gate}
3640Sstevel@tonic-gate
3650Sstevel@tonic-gatesub stamp {
3660Sstevel@tonic-gate    my $time = scalar(localtime);
3670Sstevel@tonic-gate    my $frame = 0;
3680Sstevel@tonic-gate    my ($id,$pack,$file,$dev,$dirs);
3690Sstevel@tonic-gate    if (defined($CGI::Carp::PROGNAME)) {
3700Sstevel@tonic-gate        $id = $CGI::Carp::PROGNAME;
3710Sstevel@tonic-gate    } else {
3720Sstevel@tonic-gate        do {
3730Sstevel@tonic-gate  	  $id = $file;
3740Sstevel@tonic-gate	  ($pack,$file) = caller($frame++);
3750Sstevel@tonic-gate        } until !$file;
3760Sstevel@tonic-gate    }
3770Sstevel@tonic-gate    ($dev,$dirs,$id) = File::Spec->splitpath($id);
3780Sstevel@tonic-gate    return "[$time] $id: ";
3790Sstevel@tonic-gate}
3800Sstevel@tonic-gate
3810Sstevel@tonic-gatesub set_progname {
3820Sstevel@tonic-gate    $CGI::Carp::PROGNAME = shift;
3830Sstevel@tonic-gate    return $CGI::Carp::PROGNAME;
3840Sstevel@tonic-gate}
3850Sstevel@tonic-gate
3860Sstevel@tonic-gate
3870Sstevel@tonic-gatesub warn {
3880Sstevel@tonic-gate    my $message = shift;
3890Sstevel@tonic-gate    my($file,$line,$id) = id(1);
3900Sstevel@tonic-gate    $message .= " at $file line $line.\n" unless $message=~/\n$/;
3910Sstevel@tonic-gate    _warn($message) if $WARN;
3920Sstevel@tonic-gate    my $stamp = stamp;
3930Sstevel@tonic-gate    $message=~s/^/$stamp/gm;
3940Sstevel@tonic-gate    realwarn $message;
3950Sstevel@tonic-gate}
3960Sstevel@tonic-gate
3970Sstevel@tonic-gatesub _warn {
3980Sstevel@tonic-gate    my $msg = shift;
3990Sstevel@tonic-gate    if ($EMIT_WARNINGS) {
4000Sstevel@tonic-gate	# We need to mangle the message a bit to make it a valid HTML
4010Sstevel@tonic-gate	# comment.  This is done by substituting similar-looking ISO
4020Sstevel@tonic-gate	# 8859-1 characters for <, > and -.  This is a hack.
4030Sstevel@tonic-gate	$msg =~ tr/<>-/\253\273\255/;
4040Sstevel@tonic-gate	chomp $msg;
4050Sstevel@tonic-gate	print STDOUT "<!-- warning: $msg -->\n";
4060Sstevel@tonic-gate    } else {
4070Sstevel@tonic-gate	push @WARNINGS, $msg;
4080Sstevel@tonic-gate    }
4090Sstevel@tonic-gate}
4100Sstevel@tonic-gate
4110Sstevel@tonic-gate
4120Sstevel@tonic-gate# The mod_perl package Apache::Registry loads CGI programs by calling
4130Sstevel@tonic-gate# eval.  These evals don't count when looking at the stack backtrace.
4140Sstevel@tonic-gatesub _longmess {
4150Sstevel@tonic-gate    my $message = Carp::longmess();
416667Sps156622    $message =~ s,eval[^\n]+(ModPerl|Apache)/(?:Registry|Dispatch)\w*\.pm.*,,s
4170Sstevel@tonic-gate        if exists $ENV{MOD_PERL};
4180Sstevel@tonic-gate    return $message;
4190Sstevel@tonic-gate}
4200Sstevel@tonic-gate
4210Sstevel@tonic-gatesub ineval {
4220Sstevel@tonic-gate  (exists $ENV{MOD_PERL} ? 0 : $^S) || _longmess() =~ /eval [\{\']/m
4230Sstevel@tonic-gate}
4240Sstevel@tonic-gate
4250Sstevel@tonic-gatesub die {
426667Sps156622  my ($arg,@rest) = @_;
427*6287Sps156622
428*6287Sps156622  if ($DIE_HANDLER) {
429*6287Sps156622      &$DIE_HANDLER($arg,@rest);
430*6287Sps156622  }
431*6287Sps156622
432*6287Sps156622  if ( ineval() )  {
433*6287Sps156622    if (!ref($arg)) {
434*6287Sps156622      $arg = join("",($arg,@rest)) || "Died";
435*6287Sps156622      my($file,$line,$id) = id(1);
436*6287Sps156622      $arg .= " at $file line $line.\n" unless $arg=~/\n$/;
437*6287Sps156622      realdie($arg);
438*6287Sps156622    }
439*6287Sps156622    else {
440*6287Sps156622      realdie($arg,@rest);
441*6287Sps156622    }
442*6287Sps156622  }
443667Sps156622
4440Sstevel@tonic-gate  if (!ref($arg)) {
445667Sps156622    $arg = join("", ($arg,@rest));
4460Sstevel@tonic-gate    my($file,$line,$id) = id(1);
4470Sstevel@tonic-gate    $arg .= " at $file line $line." unless $arg=~/\n$/;
4480Sstevel@tonic-gate    &fatalsToBrowser($arg) if $WRAP;
4490Sstevel@tonic-gate    if (($arg =~ /\n$/) || !exists($ENV{MOD_PERL})) {
4500Sstevel@tonic-gate      my $stamp = stamp;
4510Sstevel@tonic-gate      $arg=~s/^/$stamp/gm;
4520Sstevel@tonic-gate    }
4530Sstevel@tonic-gate    if ($arg !~ /\n$/) {
4540Sstevel@tonic-gate      $arg .= "\n";
4550Sstevel@tonic-gate    }
4560Sstevel@tonic-gate  }
4570Sstevel@tonic-gate  realdie $arg;
4580Sstevel@tonic-gate}
4590Sstevel@tonic-gate
4600Sstevel@tonic-gatesub set_message {
4610Sstevel@tonic-gate    $CGI::Carp::CUSTOM_MSG = shift;
4620Sstevel@tonic-gate    return $CGI::Carp::CUSTOM_MSG;
4630Sstevel@tonic-gate}
4640Sstevel@tonic-gate
465*6287Sps156622sub set_die_handler {
466*6287Sps156622
467*6287Sps156622    my ($handler) = shift;
468*6287Sps156622
469*6287Sps156622    #setting SIG{__DIE__} here is necessary to catch runtime
470*6287Sps156622    #errors which are not called by literally saying "die",
471*6287Sps156622    #such as the line "undef->explode();". however, doing this
472*6287Sps156622    #will interfere with fatalsToBrowser, which also sets
473*6287Sps156622    #SIG{__DIE__} in the import() function above (or the
474*6287Sps156622    #import() function above may interfere with this). for
475*6287Sps156622    #this reason, you should choose to either set the die
476*6287Sps156622    #handler here, or use fatalsToBrowser, not both.
477*6287Sps156622    $main::SIG{__DIE__} = $handler;
478*6287Sps156622
479*6287Sps156622    $CGI::Carp::DIE_HANDLER = $handler;
480*6287Sps156622
481*6287Sps156622    return $CGI::Carp::DIE_HANDLER;
482*6287Sps156622}
483*6287Sps156622
4840Sstevel@tonic-gatesub confess { CGI::Carp::die Carp::longmess @_; }
4850Sstevel@tonic-gatesub croak   { CGI::Carp::die Carp::shortmess @_; }
4860Sstevel@tonic-gatesub carp    { CGI::Carp::warn Carp::shortmess @_; }
4870Sstevel@tonic-gatesub cluck   { CGI::Carp::warn Carp::longmess @_; }
4880Sstevel@tonic-gate
4890Sstevel@tonic-gate# We have to be ready to accept a filehandle as a reference
4900Sstevel@tonic-gate# or a string.
4910Sstevel@tonic-gatesub carpout {
4920Sstevel@tonic-gate    my($in) = @_;
4930Sstevel@tonic-gate    my($no) = fileno(to_filehandle($in));
4940Sstevel@tonic-gate    realdie("Invalid filehandle $in\n") unless defined $no;
4950Sstevel@tonic-gate
4960Sstevel@tonic-gate    open(SAVEERR, ">&STDERR");
4970Sstevel@tonic-gate    open(STDERR, ">&$no") or
4980Sstevel@tonic-gate	( print SAVEERR "Unable to redirect STDERR: $!\n" and exit(1) );
4990Sstevel@tonic-gate}
5000Sstevel@tonic-gate
5010Sstevel@tonic-gatesub warningsToBrowser {
5020Sstevel@tonic-gate    $EMIT_WARNINGS = @_ ? shift : 1;
5030Sstevel@tonic-gate    _warn(shift @WARNINGS) while $EMIT_WARNINGS and @WARNINGS;
5040Sstevel@tonic-gate}
5050Sstevel@tonic-gate
5060Sstevel@tonic-gate# headers
5070Sstevel@tonic-gatesub fatalsToBrowser {
5080Sstevel@tonic-gate  my($msg) = @_;
5090Sstevel@tonic-gate  $msg=~s/&/&amp;/g;
5100Sstevel@tonic-gate  $msg=~s/>/&gt;/g;
5110Sstevel@tonic-gate  $msg=~s/</&lt;/g;
5120Sstevel@tonic-gate  $msg=~s/\"/&quot;/g;
5130Sstevel@tonic-gate  my($wm) = $ENV{SERVER_ADMIN} ?
5140Sstevel@tonic-gate    qq[the webmaster (<a href="mailto:$ENV{SERVER_ADMIN}">$ENV{SERVER_ADMIN}</a>)] :
5150Sstevel@tonic-gate      "this site's webmaster";
5160Sstevel@tonic-gate  my ($outer_message) = <<END;
5170Sstevel@tonic-gateFor help, please send mail to $wm, giving this error message
5180Sstevel@tonic-gateand the time and date of the error.
5190Sstevel@tonic-gateEND
5200Sstevel@tonic-gate  ;
5210Sstevel@tonic-gate  my $mod_perl = exists $ENV{MOD_PERL};
5220Sstevel@tonic-gate
5230Sstevel@tonic-gate  if ($CUSTOM_MSG) {
5240Sstevel@tonic-gate    if (ref($CUSTOM_MSG) eq 'CODE') {
5250Sstevel@tonic-gate      print STDOUT "Content-type: text/html\n\n"
5260Sstevel@tonic-gate        unless $mod_perl;
5270Sstevel@tonic-gate      &$CUSTOM_MSG($msg); # nicer to perl 5.003 users
5280Sstevel@tonic-gate      return;
5290Sstevel@tonic-gate    } else {
5300Sstevel@tonic-gate      $outer_message = $CUSTOM_MSG;
5310Sstevel@tonic-gate    }
5320Sstevel@tonic-gate  }
5330Sstevel@tonic-gate
5340Sstevel@tonic-gate  my $mess = <<END;
5350Sstevel@tonic-gate<h1>Software error:</h1>
5360Sstevel@tonic-gate<pre>$msg</pre>
5370Sstevel@tonic-gate<p>
5380Sstevel@tonic-gate$outer_message
5390Sstevel@tonic-gate</p>
5400Sstevel@tonic-gateEND
5410Sstevel@tonic-gate  ;
5420Sstevel@tonic-gate
5430Sstevel@tonic-gate  if ($mod_perl) {
544667Sps156622    my $r;
545*6287Sps156622    if ($ENV{MOD_PERL_API_VERSION} && $ENV{MOD_PERL_API_VERSION} == 2) {
5460Sstevel@tonic-gate      $mod_perl = 2;
547667Sps156622      require Apache2::RequestRec;
548667Sps156622      require Apache2::RequestIO;
549667Sps156622      require Apache2::RequestUtil;
5500Sstevel@tonic-gate      require APR::Pool;
5510Sstevel@tonic-gate      require ModPerl::Util;
552667Sps156622      require Apache2::Response;
553667Sps156622      $r = Apache2::RequestUtil->request;
5540Sstevel@tonic-gate    }
555667Sps156622    else {
556667Sps156622      $r = Apache->request;
557667Sps156622    }
5580Sstevel@tonic-gate    # If bytes have already been sent, then
5590Sstevel@tonic-gate    # we print the message out directly.
5600Sstevel@tonic-gate    # Otherwise we make a custom error
5610Sstevel@tonic-gate    # handler to produce the doc for us.
5620Sstevel@tonic-gate    if ($r->bytes_sent) {
5630Sstevel@tonic-gate      $r->print($mess);
5640Sstevel@tonic-gate      $mod_perl == 2 ? ModPerl::Util::exit(0) : $r->exit;
5650Sstevel@tonic-gate    } else {
5660Sstevel@tonic-gate      # MSIE won't display a custom 500 response unless it is >512 bytes!
5670Sstevel@tonic-gate      if ($ENV{HTTP_USER_AGENT} =~ /MSIE/) {
5680Sstevel@tonic-gate        $mess = "<!-- " . (' ' x 513) . " -->\n$mess";
5690Sstevel@tonic-gate      }
5700Sstevel@tonic-gate      $r->custom_response(500,$mess);
5710Sstevel@tonic-gate    }
5720Sstevel@tonic-gate  } else {
5730Sstevel@tonic-gate    my $bytes_written = eval{tell STDOUT};
5740Sstevel@tonic-gate    if (defined $bytes_written && $bytes_written > 0) {
5750Sstevel@tonic-gate        print STDOUT $mess;
5760Sstevel@tonic-gate    }
5770Sstevel@tonic-gate    else {
578*6287Sps156622        print STDOUT "Status: 500\n";
5790Sstevel@tonic-gate        print STDOUT "Content-type: text/html\n\n";
5800Sstevel@tonic-gate        print STDOUT $mess;
5810Sstevel@tonic-gate    }
5820Sstevel@tonic-gate  }
583667Sps156622
584667Sps156622  warningsToBrowser(1);    # emit warnings before dying
5850Sstevel@tonic-gate}
5860Sstevel@tonic-gate
5870Sstevel@tonic-gate# Cut and paste from CGI.pm so that we don't have the overhead of
5880Sstevel@tonic-gate# always loading the entire CGI module.
5890Sstevel@tonic-gatesub to_filehandle {
5900Sstevel@tonic-gate    my $thingy = shift;
5910Sstevel@tonic-gate    return undef unless $thingy;
5920Sstevel@tonic-gate    return $thingy if UNIVERSAL::isa($thingy,'GLOB');
5930Sstevel@tonic-gate    return $thingy if UNIVERSAL::isa($thingy,'FileHandle');
5940Sstevel@tonic-gate    if (!ref($thingy)) {
5950Sstevel@tonic-gate	my $caller = 1;
5960Sstevel@tonic-gate	while (my $package = caller($caller++)) {
5970Sstevel@tonic-gate	    my($tmp) = $thingy=~/[\':]/ ? $thingy : "$package\:\:$thingy";
5980Sstevel@tonic-gate	    return $tmp if defined(fileno($tmp));
5990Sstevel@tonic-gate	}
6000Sstevel@tonic-gate    }
6010Sstevel@tonic-gate    return undef;
6020Sstevel@tonic-gate}
6030Sstevel@tonic-gate
6040Sstevel@tonic-gate1;
605