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 > and < 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/&/&/g; 5100Sstevel@tonic-gate $msg=~s/>/>/g; 5110Sstevel@tonic-gate $msg=~s/</</g; 5120Sstevel@tonic-gate $msg=~s/\"/"/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