1package CGI::Carp; 2 3=head1 NAME 4 5B<CGI::Carp> - CGI routines for writing to the HTTPD (or other) error log 6 7=head1 SYNOPSIS 8 9 use CGI::Carp; 10 11 croak "We're outta here!"; 12 confess "It was my fault: $!"; 13 carp "It was your fault!"; 14 warn "I'm confused"; 15 die "I'm dying.\n"; 16 17 use CGI::Carp qw(cluck); 18 cluck "I wouldn't do that if I were you"; 19 20 use CGI::Carp qw(fatalsToBrowser); 21 die "Fatal error messages are now sent to browser"; 22 23=head1 DESCRIPTION 24 25CGI scripts have a nasty habit of leaving warning messages in the error 26logs that are neither time stamped nor fully identified. Tracking down 27the script that caused the error is a pain. This fixes that. Replace 28the usual 29 30 use Carp; 31 32with 33 34 use CGI::Carp 35 36And the standard warn(), die (), croak(), confess() and carp() calls 37will automagically be replaced with functions that write out nicely 38time-stamped messages to the HTTP server error log. 39 40For example: 41 42 [Fri Nov 17 21:40:43 1995] test.pl: I'm confused at test.pl line 3. 43 [Fri Nov 17 21:40:43 1995] test.pl: Got an error message: Permission denied. 44 [Fri Nov 17 21:40:43 1995] test.pl: I'm dying. 45 46=head1 REDIRECTING ERROR MESSAGES 47 48By default, error messages are sent to STDERR. Most HTTPD servers 49direct STDERR to the server's error log. Some applications may wish 50to keep private error logs, distinct from the server's error log, or 51they may wish to direct error messages to STDOUT so that the browser 52will receive them. 53 54The C<carpout()> function is provided for this purpose. Since 55carpout() is not exported by default, you must import it explicitly by 56saying 57 58 use CGI::Carp qw(carpout); 59 60The carpout() function requires one argument, which should be a 61reference to an open filehandle for writing errors. It should be 62called in a C<BEGIN> block at the top of the CGI application so that 63compiler errors will be caught. Example: 64 65 BEGIN { 66 use CGI::Carp qw(carpout); 67 open(LOG, ">>/usr/local/cgi-logs/mycgi-log") or 68 die("Unable to open mycgi-log: $!\n"); 69 carpout(LOG); 70 } 71 72carpout() does not handle file locking on the log for you at this point. 73 74The real STDERR is not closed -- it is moved to CGI::Carp::SAVEERR. Some 75servers, when dealing with CGI scripts, close their connection to the 76browser when the script closes STDOUT and STDERR. CGI::Carp::SAVEERR is there to 77prevent this from happening prematurely. 78 79You can pass filehandles to carpout() in a variety of ways. The "correct" 80way according to Tom Christiansen is to pass a reference to a filehandle 81GLOB: 82 83 carpout(\*LOG); 84 85This looks weird to mere mortals however, so the following syntaxes are 86accepted as well: 87 88 carpout(LOG); 89 carpout(main::LOG); 90 carpout(main'LOG); 91 carpout(\LOG); 92 carpout(\'main::LOG'); 93 94 ... and so on 95 96FileHandle and other objects work as well. 97 98Use of carpout() is not great for performance, so it is recommended 99for debugging purposes or for moderate-use applications. A future 100version of this module may delay redirecting STDERR until one of the 101CGI::Carp methods is called to prevent the performance hit. 102 103=head1 MAKING PERL ERRORS APPEAR IN THE BROWSER WINDOW 104 105If you want to send fatal (die, confess) errors to the browser, ask to 106import the special "fatalsToBrowser" subroutine: 107 108 use CGI::Carp qw(fatalsToBrowser); 109 die "Bad error here"; 110 111Fatal errors will now be echoed to the browser as well as to the log. CGI::Carp 112arranges to send a minimal HTTP header to the browser so that even errors that 113occur in the early compile phase will be seen. 114Nonfatal errors will still be directed to the log file only (unless redirected 115with carpout). 116 117Note that fatalsToBrowser does B<not> work with mod_perl version 2.0 118and higher. 119 120=head2 Changing the default message 121 122By default, the software error message is followed by a note to 123contact the Webmaster by e-mail with the time and date of the error. 124If this message is not to your liking, you can change it using the 125set_message() routine. This is not imported by default; you should 126import it on the use() line: 127 128 use CGI::Carp qw(fatalsToBrowser set_message); 129 set_message("It's not a bug, it's a feature!"); 130 131You may also pass in a code reference in order to create a custom 132error message. At run time, your code will be called with the text 133of the error message that caused the script to die. Example: 134 135 use CGI::Carp qw(fatalsToBrowser set_message); 136 BEGIN { 137 sub handle_errors { 138 my $msg = shift; 139 print "<h1>Oh gosh</h1>"; 140 print "<p>Got an error: $msg</p>"; 141 } 142 set_message(\&handle_errors); 143 } 144 145In order to correctly intercept compile-time errors, you should call 146set_message() from within a BEGIN{} block. 147 148=head1 DOING MORE THAN PRINTING A MESSAGE IN THE EVENT OF PERL ERRORS 149 150If fatalsToBrowser in conjunction with set_message does not provide 151you with all of the functionality you need, you can go one step 152further by specifying a function to be executed any time a script 153calls "die", has a syntax error, or dies unexpectedly at runtime 154with a line like "undef->explode();". 155 156 use CGI::Carp qw(set_die_handler); 157 BEGIN { 158 sub handle_errors { 159 my $msg = shift; 160 print "content-type: text/html\n\n"; 161 print "<h1>Oh gosh</h1>"; 162 print "<p>Got an error: $msg</p>"; 163 164 #proceed to send an email to a system administrator, 165 #write a detailed message to the browser and/or a log, 166 #etc.... 167 } 168 set_die_handler(\&handle_errors); 169 } 170 171Notice that if you use set_die_handler(), you must handle sending 172HTML headers to the browser yourself if you are printing a message. 173 174If you use set_die_handler(), you will most likely interfere with 175the behavior of fatalsToBrowser, so you must use this or that, not 176both. 177 178Using set_die_handler() sets SIG{__DIE__} (as does fatalsToBrowser), 179and there is only one SIG{__DIE__}. This means that if you are 180attempting to set SIG{__DIE__} yourself, you may interfere with 181this module's functionality, or this module may interfere with 182your module's functionality. 183 184=head1 MAKING WARNINGS APPEAR AS HTML COMMENTS 185 186It is now also possible to make non-fatal errors appear as HTML 187comments embedded in the output of your program. To enable this 188feature, export the new "warningsToBrowser" subroutine. Since sending 189warnings to the browser before the HTTP headers have been sent would 190cause an error, any warnings are stored in an internal buffer until 191you call the warningsToBrowser() subroutine with a true argument: 192 193 use CGI::Carp qw(fatalsToBrowser warningsToBrowser); 194 use CGI qw(:standard); 195 print header(); 196 warningsToBrowser(1); 197 198You may also give a false argument to warningsToBrowser() to prevent 199warnings from being sent to the browser while you are printing some 200content where HTML comments are not allowed: 201 202 warningsToBrowser(0); # disable warnings 203 print "<script type=\"text/javascript\"><!--\n"; 204 print_some_javascript_code(); 205 print "//--></script>\n"; 206 warningsToBrowser(1); # re-enable warnings 207 208Note: In this respect warningsToBrowser() differs fundamentally from 209fatalsToBrowser(), which you should never call yourself! 210 211=head1 OVERRIDING THE NAME OF THE PROGRAM 212 213CGI::Carp includes the name of the program that generated the error or 214warning in the messages written to the log and the browser window. 215Sometimes, Perl can get confused about what the actual name of the 216executed program was. In these cases, you can override the program 217name that CGI::Carp will use for all messages. 218 219The quick way to do that is to tell CGI::Carp the name of the program 220in its use statement. You can do that by adding 221"name=cgi_carp_log_name" to your "use" statement. For example: 222 223 use CGI::Carp qw(name=cgi_carp_log_name); 224 225. If you want to change the program name partway through the program, 226you can use the C<set_progname()> function instead. It is not 227exported by default, you must import it explicitly by saying 228 229 use CGI::Carp qw(set_progname); 230 231Once you've done that, you can change the logged name of the program 232at any time by calling 233 234 set_progname(new_program_name); 235 236You can set the program back to the default by calling 237 238 set_progname(undef); 239 240Note that this override doesn't happen until after the program has 241compiled, so any compile-time errors will still show up with the 242non-overridden program name 243 244=head1 CHANGE LOG 245 2461.29 Patch from Peter Whaite to fix the unfixable problem of CGI::Carp 247 not behaving correctly in an eval() context. 248 2491.05 carpout() added and minor corrections by Marc Hedlund 250 <hedlund@best.com> on 11/26/95. 251 2521.06 fatalsToBrowser() no longer aborts for fatal errors within 253 eval() statements. 254 2551.08 set_message() added and carpout() expanded to allow for FileHandle 256 objects. 257 2581.09 set_message() now allows users to pass a code REFERENCE for 259 really custom error messages. croak and carp are now 260 exported by default. Thanks to Gunther Birznieks for the 261 patches. 262 2631.10 Patch from Chris Dean (ctdean@cogit.com) to allow 264 module to run correctly under mod_perl. 265 2661.11 Changed order of > and < escapes. 267 2681.12 Changed die() on line 217 to CORE::die to avoid B<-w> warning. 269 2701.13 Added cluck() to make the module orthogonal with Carp. 271 More mod_perl related fixes. 272 2731.20 Patch from Ilmari Karonen (perl@itz.pp.sci.fi): Added 274 warningsToBrowser(). Replaced <CODE> tags with <PRE> in 275 fatalsToBrowser() output. 276 2771.23 ineval() now checks both $^S and inspects the message for the "eval" pattern 278 (hack alert!) in order to accomodate various combinations of Perl and 279 mod_perl. 280 2811.24 Patch from Scott Gifford (sgifford@suspectclass.com): Add support 282 for overriding program name. 283 2841.26 Replaced CORE::GLOBAL::die with the evil $SIG{__DIE__} because the 285 former isn't working in some people's hands. There is no such thing 286 as reliable exception handling in Perl. 287 2881.27 Replaced tell STDOUT with bytes=tell STDOUT. 289 290=head1 AUTHORS 291 292Copyright 1995-2002, Lincoln D. Stein. All rights reserved. 293 294This library is free software; you can redistribute it and/or modify 295it under the same terms as Perl itself. 296 297Address bug reports and comments to: lstein@cshl.org 298 299=head1 SEE ALSO 300 301Carp, CGI::Base, CGI::BasePlus, CGI::Request, CGI::MiniSvr, CGI::Form, 302CGI::Response 303 if (defined($CGI::Carp::PROGNAME)) 304 { 305 $file = $CGI::Carp::PROGNAME; 306 } 307 308=cut 309 310require 5.000; 311use Exporter; 312#use Carp; 313BEGIN { 314 require Carp; 315 *CORE::GLOBAL::die = \&CGI::Carp::die; 316} 317 318use File::Spec; 319 320@ISA = qw(Exporter); 321@EXPORT = qw(confess croak carp); 322@EXPORT_OK = qw(carpout fatalsToBrowser warningsToBrowser wrap set_message set_die_handler set_progname cluck ^name= die); 323 324$main::SIG{__WARN__}=\&CGI::Carp::warn; 325 326$CGI::Carp::VERSION = '1.30'; 327$CGI::Carp::CUSTOM_MSG = undef; 328$CGI::Carp::DIE_HANDLER = undef; 329 330 331# fancy import routine detects and handles 'errorWrap' specially. 332sub import { 333 my $pkg = shift; 334 my(%routines); 335 my(@name); 336 if (@name=grep(/^name=/,@_)) 337 { 338 my($n) = (split(/=/,$name[0]))[1]; 339 set_progname($n); 340 @_=grep(!/^name=/,@_); 341 } 342 343 grep($routines{$_}++,@_,@EXPORT); 344 $WRAP++ if $routines{'fatalsToBrowser'} || $routines{'wrap'}; 345 $WARN++ if $routines{'warningsToBrowser'}; 346 my($oldlevel) = $Exporter::ExportLevel; 347 $Exporter::ExportLevel = 1; 348 Exporter::import($pkg,keys %routines); 349 $Exporter::ExportLevel = $oldlevel; 350 $main::SIG{__DIE__} =\&CGI::Carp::die if $routines{'fatalsToBrowser'}; 351# $pkg->export('CORE::GLOBAL','die'); 352} 353 354# These are the originals 355sub realwarn { CORE::warn(@_); } 356sub realdie { CORE::die(@_); } 357 358sub id { 359 my $level = shift; 360 my($pack,$file,$line,$sub) = caller($level); 361 my($dev,$dirs,$id) = File::Spec->splitpath($file); 362 return ($file,$line,$id); 363} 364 365sub stamp { 366 my $time = scalar(localtime); 367 my $frame = 0; 368 my ($id,$pack,$file,$dev,$dirs); 369 if (defined($CGI::Carp::PROGNAME)) { 370 $id = $CGI::Carp::PROGNAME; 371 } else { 372 do { 373 $id = $file; 374 ($pack,$file) = caller($frame++); 375 } until !$file; 376 } 377 ($dev,$dirs,$id) = File::Spec->splitpath($id); 378 return "[$time] $id: "; 379} 380 381sub set_progname { 382 $CGI::Carp::PROGNAME = shift; 383 return $CGI::Carp::PROGNAME; 384} 385 386 387sub warn { 388 my $message = shift; 389 my($file,$line,$id) = id(1); 390 $message .= " at $file line $line.\n" unless $message=~/\n$/; 391 _warn($message) if $WARN; 392 my $stamp = stamp; 393 $message=~s/^/$stamp/gm; 394 realwarn $message; 395} 396 397sub _warn { 398 my $msg = shift; 399 if ($EMIT_WARNINGS) { 400 # We need to mangle the message a bit to make it a valid HTML 401 # comment. This is done by substituting similar-looking ISO 402 # 8859-1 characters for <, > and -. This is a hack. 403 $msg =~ tr/<>-/\253\273\255/; 404 chomp $msg; 405 print STDOUT "<!-- warning: $msg -->\n"; 406 } else { 407 push @WARNINGS, $msg; 408 } 409} 410 411 412# The mod_perl package Apache::Registry loads CGI programs by calling 413# eval. These evals don't count when looking at the stack backtrace. 414sub _longmess { 415 my $message = Carp::longmess(); 416 $message =~ s,eval[^\n]+(ModPerl|Apache)/(?:Registry|Dispatch)\w*\.pm.*,,s 417 if exists $ENV{MOD_PERL}; 418 return $message; 419} 420 421sub ineval { 422 (exists $ENV{MOD_PERL} ? 0 : $^S) || _longmess() =~ /eval [\{\']/m 423} 424 425sub die { 426 my ($arg,@rest) = @_; 427 428 if ($DIE_HANDLER) { 429 &$DIE_HANDLER($arg,@rest); 430 } 431 432 if ( ineval() ) { 433 if (!ref($arg)) { 434 $arg = join("",($arg,@rest)) || "Died"; 435 my($file,$line,$id) = id(1); 436 $arg .= " at $file line $line.\n" unless $arg=~/\n$/; 437 realdie($arg); 438 } 439 else { 440 realdie($arg,@rest); 441 } 442 } 443 444 if (!ref($arg)) { 445 $arg = join("", ($arg,@rest)); 446 my($file,$line,$id) = id(1); 447 $arg .= " at $file line $line." unless $arg=~/\n$/; 448 &fatalsToBrowser($arg) if $WRAP; 449 if (($arg =~ /\n$/) || !exists($ENV{MOD_PERL})) { 450 my $stamp = stamp; 451 $arg=~s/^/$stamp/gm; 452 } 453 if ($arg !~ /\n$/) { 454 $arg .= "\n"; 455 } 456 } 457 realdie $arg; 458} 459 460sub set_message { 461 $CGI::Carp::CUSTOM_MSG = shift; 462 return $CGI::Carp::CUSTOM_MSG; 463} 464 465sub set_die_handler { 466 467 my ($handler) = shift; 468 469 #setting SIG{__DIE__} here is necessary to catch runtime 470 #errors which are not called by literally saying "die", 471 #such as the line "undef->explode();". however, doing this 472 #will interfere with fatalsToBrowser, which also sets 473 #SIG{__DIE__} in the import() function above (or the 474 #import() function above may interfere with this). for 475 #this reason, you should choose to either set the die 476 #handler here, or use fatalsToBrowser, not both. 477 $main::SIG{__DIE__} = $handler; 478 479 $CGI::Carp::DIE_HANDLER = $handler; 480 481 return $CGI::Carp::DIE_HANDLER; 482} 483 484sub confess { CGI::Carp::die Carp::longmess @_; } 485sub croak { CGI::Carp::die Carp::shortmess @_; } 486sub carp { CGI::Carp::warn Carp::shortmess @_; } 487sub cluck { CGI::Carp::warn Carp::longmess @_; } 488 489# We have to be ready to accept a filehandle as a reference 490# or a string. 491sub carpout { 492 my($in) = @_; 493 my($no) = fileno(to_filehandle($in)); 494 realdie("Invalid filehandle $in\n") unless defined $no; 495 496 open(SAVEERR, ">&STDERR"); 497 open(STDERR, ">&$no") or 498 ( print SAVEERR "Unable to redirect STDERR: $!\n" and exit(1) ); 499} 500 501sub warningsToBrowser { 502 $EMIT_WARNINGS = @_ ? shift : 1; 503 _warn(shift @WARNINGS) while $EMIT_WARNINGS and @WARNINGS; 504} 505 506# headers 507sub fatalsToBrowser { 508 my($msg) = @_; 509 $msg=~s/&/&/g; 510 $msg=~s/>/>/g; 511 $msg=~s/</</g; 512 $msg=~s/\"/"/g; 513 my($wm) = $ENV{SERVER_ADMIN} ? 514 qq[the webmaster (<a href="mailto:$ENV{SERVER_ADMIN}">$ENV{SERVER_ADMIN}</a>)] : 515 "this site's webmaster"; 516 my ($outer_message) = <<END; 517For help, please send mail to $wm, giving this error message 518and the time and date of the error. 519END 520 ; 521 my $mod_perl = exists $ENV{MOD_PERL}; 522 523 if ($CUSTOM_MSG) { 524 if (ref($CUSTOM_MSG) eq 'CODE') { 525 print STDOUT "Content-type: text/html\n\n" 526 unless $mod_perl; 527 &$CUSTOM_MSG($msg); # nicer to perl 5.003 users 528 return; 529 } else { 530 $outer_message = $CUSTOM_MSG; 531 } 532 } 533 534 my $mess = <<END; 535<h1>Software error:</h1> 536<pre>$msg</pre> 537<p> 538$outer_message 539</p> 540END 541 ; 542 543 if ($mod_perl) { 544 my $r; 545 if ($ENV{MOD_PERL_API_VERSION} && $ENV{MOD_PERL_API_VERSION} == 2) { 546 $mod_perl = 2; 547 require Apache2::RequestRec; 548 require Apache2::RequestIO; 549 require Apache2::RequestUtil; 550 require APR::Pool; 551 require ModPerl::Util; 552 require Apache2::Response; 553 $r = Apache2::RequestUtil->request; 554 } 555 else { 556 $r = Apache->request; 557 } 558 # If bytes have already been sent, then 559 # we print the message out directly. 560 # Otherwise we make a custom error 561 # handler to produce the doc for us. 562 if ($r->bytes_sent) { 563 $r->print($mess); 564 $mod_perl == 2 ? ModPerl::Util::exit(0) : $r->exit; 565 } else { 566 # MSIE won't display a custom 500 response unless it is >512 bytes! 567 if ($ENV{HTTP_USER_AGENT} =~ /MSIE/) { 568 $mess = "<!-- " . (' ' x 513) . " -->\n$mess"; 569 } 570 $r->custom_response(500,$mess); 571 } 572 } else { 573 my $bytes_written = eval{tell STDOUT}; 574 if (defined $bytes_written && $bytes_written > 0) { 575 print STDOUT $mess; 576 } 577 else { 578 print STDOUT "Status: 500\n"; 579 print STDOUT "Content-type: text/html\n\n"; 580 print STDOUT $mess; 581 } 582 } 583 584 warningsToBrowser(1); # emit warnings before dying 585} 586 587# Cut and paste from CGI.pm so that we don't have the overhead of 588# always loading the entire CGI module. 589sub to_filehandle { 590 my $thingy = shift; 591 return undef unless $thingy; 592 return $thingy if UNIVERSAL::isa($thingy,'GLOB'); 593 return $thingy if UNIVERSAL::isa($thingy,'FileHandle'); 594 if (!ref($thingy)) { 595 my $caller = 1; 596 while (my $package = caller($caller++)) { 597 my($tmp) = $thingy=~/[\':]/ ? $thingy : "$package\:\:$thingy"; 598 return $tmp if defined(fileno($tmp)); 599 } 600 } 601 return undef; 602} 603 6041; 605