/[suikacvs]/test/lib/CGI/Carp.pm
Suika

Contents of /test/lib/CGI/Carp.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (hide annotations) (download)
Sat Jan 17 08:48:32 2004 UTC (20 years, 10 months ago) by wakaba
Branch: MAIN
1.26

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24