File Coverage

blib/lib/WebDyne/Err.pm
Criterion Covered Total %
statement 27 97 27.8
branch 0 24 0.0
condition 0 25 0.0
subroutine 9 13 69.2
pod 0 2 0.0
total 36 161 22.3


line stmt bran cond sub pod time code
1             #
2             # This file is part of WebDyne.
3             #
4             # This software is Copyright (c) 2017 by Andrew Speer .
5             #
6             # This is free software, licensed under:
7             #
8             # The GNU General Public License, Version 2, June 1991
9             #
10             # Full license text is available at:
11             #
12             #
13             #
14             package WebDyne::Err;
15              
16              
17             # Compiler Pragma
18             #
19 2     2   12 use strict qw(vars);
  2         4  
  2         75  
20 2     2   8 use vars qw($VERSION);
  2         35  
  2         90  
21 2     2   11 use warnings;
  2         3  
  2         68  
22 2     2   8 no warnings qw(uninitialized);
  2         5  
  2         78  
23              
24              
25             # Webmod Modules.
26             #
27 2     2   9 use WebDyne::Constant;
  2         4  
  2         656  
28 2     2   513 use WebDyne::Err::Constant;
  2         6  
  2         191  
29 2     2   14 use WebDyne::Base;
  2         5  
  2         14  
30              
31              
32             # External modules
33             #
34 2     2   9 use HTTP::Status qw(is_success is_error RC_INTERNAL_SERVER_ERROR);
  2         4  
  2         89  
35 2     2   10 use File::Spec;
  2         2  
  2         1487  
36              
37              
38             # Version information
39             #
40             $VERSION='1.250';
41              
42              
43             # Debug
44             #
45             0 && debug("%s loaded, version $VERSION", __PACKAGE__);
46              
47              
48             # Package wide vars
49             #
50             my %Package;
51             *debug=\&WebDyne::debug;
52              
53              
54             # Fix issues if mod_perl loads legacy Carp with modern Carp::Heavy
55             #
56             { my $cr=sub {return \@_};
57             foreach my $method (qw(shortmess_real longmess_real shortmess_heavy longmess_heavy)) {
58 0     0     *{"Carp::${method}"}=sub {return @_}
59             unless Carp->can($method);
60             }
61             }
62              
63              
64             # And done
65             #
66             1;
67              
68              
69             #------------------------------------------------------------------------------
70              
71              
72             sub err_html {
73              
74              
75             # Output errors to browser.
76             #
77 0     0 0   my ($self, $errstr)=@_;
78 0           $errstr=sprintf($errstr, @_[2..$#_]);
79              
80              
81             # Debug
82             #
83 0           0 && debug("in error routine self $self, errstr $errstr, caller %s", join(',', (caller(0))[0..3]));
84              
85              
86             # Get errstr from stack if not supplied, or add if it
87             # has been
88             #
89 0 0         if ($errstr) {err ($errstr)}
  0            
90             else {
91 0   0       $errstr=errstr() || do {err ($_='undefined error from handler'); $_}
92             }
93              
94             #$errstr ? err($errstr) : ($errstr=errstr() || do {err($_='undefined error from handler'); $_});
95 0           0 && debug("final errstr $errstr");
96              
97              
98             # Try to get request handler;
99             #
100 0           my $r;
101 0 0         if ($r=eval {$self->{'_r'}}) {
  0            
102              
103             # Get main request handler in case we are in subrequest
104             #
105 0   0       $r=$r->main() || $r;
106              
107             }
108 0           0 && debug("r $r");
109              
110              
111             # Print errstr and exit immediately if no request object yet, or in error loop - something
112             # is seriously wrong;
113             #
114 0 0         if (!$r) {
115 0           print(errdump());
116 0           CORE::exit 0;
117             }
118              
119              
120             # Try to get CGI object from class, or create if not present - may
121             # not have been initialised before error occured);
122             #
123 0   0       my $cgi_or=$self->{'_CGI'} || CGI->new();
124 0           0 && debug("cgi_or $cgi_or");
125              
126              
127             # Log the error
128             #
129 0           $r->log_error($errstr);
130              
131              
132             # Status must be internal error
133             #
134 0           $r->status(RC_INTERNAL_SERVER_ERROR);
135              
136              
137             # Do not run any more handlers
138             #
139 0           $r->set_handlers(PerlHandler => undef);
140              
141              
142             # Optionally kill this Apache process afterwards to make sure it does not behave
143             # badly after this error, if that is what the user has configured
144             #
145 0 0         if ($WEBDYNE_ERROR_EXIT) {
146 0     0     my $cr=sub {CORE::exit()};
  0            
147 0 0         $MP2 ? $r->pool->cleanup_register($cr) : $r->register_cleanup($cr);
148             }
149              
150              
151             # Error can be text or HTML, must be text if in Safe eval mode
152             #
153 0 0 0       if ($WEBDYNE_ERROR_TEXT || $WEBDYNE_EVAL_SAFE || $self->{'_error_handler_run'}++ || !$cgi_or) {
      0        
      0        
154              
155              
156             # Text error, set content type
157             #
158             0 && debug(
159             "using text error (%s:%s:%s:%s) - update $r content_type",
160 0           $WEBDYNE_ERROR_TEXT, $WEBDYNE_EVAL_SAFE, $self->{'_error_handler_run'}, $cgi_or
161             );
162 0           $r->content_type('text/plain');
163              
164              
165             # Push error
166             #
167 0           my $err_text=errdump(
168             {
169              
170             'URI' => $r->uri(),
171             'Line' => scalar $self->data_ar_html_line_no(),
172              
173             });
174              
175              
176             # Clear error stack and $@.
177             #
178 0 0         errclr(); eval {undef} if $@;
  0            
  0            
179              
180              
181             # Print error and return
182             #
183 0 0         $r->send_http_header() if !$MP2;
184 0           $r->print($err_text);
185 0           return &Apache::OK;
186              
187              
188             }
189             else {
190              
191              
192             # Get error parameters, must make copy of stack, data block - they will be erased.
193             #
194 0           0 && debug('using html error');
195 0           my @errstack=@{&errstack()};
  0            
196             my %param=(
197              
198             errstr => $errstr,
199             errstack_ar => \@errstack,
200             errperl_sr => $self->{'_err_perl_sr'},
201 0           data_ar => $self->{'_data_ar'},
202             r => $r
203              
204             );
205              
206              
207             # Clear error stack and $@ so this render works without errors
208             #
209 0 0         errclr(); eval {undef} if $@;
  0            
  0            
210              
211              
212             # Wrap everything in eval block in case this error was thrown interally by
213             # WebDyne not being able to load/start etc, in which case trying to run it
214             # again won't be helpful
215             #
216 0           my $status;
217 0           eval {
218              
219              
220             # Only compile container once if we can help it
221             #
222 0           local $SIG{__DIE__};
223 0           require WebDyne::Compile;
224             my $container_ar=(
225 0   0       $Package{'container_ar'} ||= &WebDyne::Compile::compile(
226             $self,
227             {
228              
229             srce => $WEBDYNE_ERR_TEMPLATE,
230             nofilter => 1
231              
232             })) || return $self->err_html('fatal problem in error handler during compile !');
233              
234              
235             # Get the data portion of the container (meta info not needed) and render. Bit of cheating
236             # to use internal
237             #
238 0           my $data_ar=$container_ar->[$WEBDYNE_CONTAINER_DATA_IX];
239              
240              
241             # Reset render state and render error page
242             #
243 0           $self->render_reset($data_ar);
244 0   0       my $html_sr=$self->render(
245             {
246              
247             data => $data_ar,
248             param => \%param
249              
250             }) || return $self->err_html('fatal problem in error handler during render: %s !', errstr() || 'undefined error');
251              
252              
253             # Set custom handler
254             #
255 0           $status=$r->status();
256 0           0 && debug("send custom response for status $status on r $r");
257 0           $r->custom_response($status, ${$html_sr});
  0            
258              
259              
260             # Clear error stack again, make sure all is clean before we return.
261             #
262 0 0         errclr(); eval {undef} if $@;
  0            
  0            
263              
264             };
265              
266              
267             # Check if render went OK, if not revert to text - better than
268             # showing nothing ..
269             #
270 0 0 0       if ($@ || !$status) {
271 0           0 && debug("unable to render HTML template, reverting to text");
272 0 0         err ($@) if $@;
273 0           err ('previous error stack %s', Data::Dumper::Dumper(\@errstack));
274 0           my $webdyne_error_text_save=$WEBDYNE_ERROR_TEXT;
275 0           $WEBDYNE_ERROR_TEXT=1;
276 0           $status=$self->err_html($errstr);
277 0           $WEBDYNE_ERROR_TEXT=$webdyne_error_text_save;
278              
279             }
280              
281             # Return result
282             #
283 0           return $status
284              
285             }
286              
287             }
288              
289              
290             sub err_eval {
291              
292             # Special handler for eval errors
293             #
294 0     0 0   my ($self, $message, $perl_sr)=@_;
295 0           0 && debug("err_eval $message, %s, caller %s", Dumper($perl_sr), Dumper([caller()]));
296              
297              
298             # Store away for future ref by error handler
299             #
300 0           $self->{'_err_perl_sr'}=$perl_sr;
301              
302              
303             # Send message off to main error handler and return
304             #
305 0           return &errsubst($message);
306              
307             }
308