xref: /onnv-gate/usr/src/cmd/perl/5.8.4/distrib/lib/CGI/Carp.pm (revision 6287:9a1f5d2c8dd8)
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 &gt; and &lt; 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/&/&amp;/g;
510  $msg=~s/>/&gt;/g;
511  $msg=~s/</&lt;/g;
512  $msg=~s/\"/&quot;/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