File Coverage

blib/lib/CGI/ExceptionManager/StackTrace.pm
Criterion Covered Total %
statement 58 58 100.0
branch 19 24 79.1
condition 4 8 50.0
subroutine 8 8 100.0
pod 0 3 0.0
total 89 101 88.1


line stmt bran cond sub pod time code
1             package CGI::ExceptionManager::StackTrace;
2 3     3   16 use strict;
  3         7  
  3         122  
3 3     3   17 use warnings;
  3         5  
  3         2645  
4              
5             # from MENTA and NanoA
6              
7             sub _escape_html {
8 80     80   137 my $str = shift;
9 80         135 $str =~ s/&/&/g;
10 80         312 $str =~ s/>/>/g;
11 80         169 $str =~ s/
12 80         124 $str =~ s/"/"/g;
13 80         136 $str =~ s/'/'/g;
14 80         672 return $str;
15             }
16              
17             sub new {
18 4     4 0 72 my ($klass, $message) = @_;
19 4         9 my @trace;
20            
21 4         41 for (my $i = 1; my ($package, $file, $line) = caller($i); $i++) {
22 17         52 push @trace, {
23             file => $file,
24             line => $line,
25             func => undef,
26             };
27 17 100       126 if (my @c = caller($i + 1)) {
28 13 50       116 $trace[-1]->{func} = $c[3]
29             if $c[3];
30             }
31             }
32 4 100 66     81 if ($message =~ / at ([^ ]+) line (\d+)/
      33        
33             && ($1 ne $trace[0]->{file} || $2 != $trace[0]->{line})) {
34 1         7 unshift @trace, {
35             file => $1,
36             line => $2,
37             };
38             }
39            
40             bless {
41 4         27 message => $message,
42             trace => \@trace,
43             }, $klass;
44             }
45              
46             sub _build_context {
47 9     9   17 my ($file, $linenum) = @_;
48 9         11 my $code;
49 9 50       273 if (-f $file) {
50 9         21 my $start = $linenum - 3;
51 9         18 my $end = $linenum + 3;
52 9 50       22 $start = $start < 1 ? 1 : $start;
53 2 50   2   13 open my $fh, '<:encoding(utf8)', $file
  2         9  
  2         18  
  9         410  
54             or die "cannot open $file:$!";
55 9         62611 my $cur_line = 0;
56 9         602 while (my $line = <$fh>) {
57 232         734 ++$cur_line;
58 232 100       474 last if $cur_line > $end;
59 223 100       702 next if $cur_line < $start;
60 63         119 $line =~ s|\t| |g;
61 63 100       215 my @tag = $cur_line == $linenum
62             ? (q{}, '')
63             : ('', '');
64 63         419 $code .= sprintf(
65             '%s%5d: %s%s', $tag[0], $cur_line, _escape_html($line),
66             $tag[1],
67             );
68             }
69 9         283 close $file;
70             }
71 9         109 return $code;
72             }
73              
74             sub as_html {
75 2     2 0 7 my ($err, %args) = @_;
76 2         7 my $msg = _escape_html($err->{message});
77 2         30 my $out = qq{500 Internal Server Error

500 Internal Server Error

${msg}

    };
78 2         26 for my $stack (@{$err->{trace}}) {
  2         7  
79 9 100 50     59 $out .= join(
    50          
80             '',
81             '
  • ',
  • 82             $stack->{func} ? _escape_html("in $stack->{func}") : '',
    83             ' at ',
    84             $stack->{file} ? _escape_html($stack->{file}) : '',
    85             ' line ',
    86             $stack->{line},
    87             q(
    ), 
    88             _build_context($stack->{file}, $stack->{line}) || '',
    89             q(),
    90             );
    91             }
    92 2         12 $out .= qq{

    Powered by $args{powered_by}

    };
    93 2         16 $out;
    94             }
    95              
    96             sub output {
    97 3     3 0 13 my ($err, %args) = @_;
    98            
    99 3         25 warn $err->{message};
    100            
    101 3         65 print "Status: 500\r\n";
    102 3         36 print "Content-type: text/html; charset=utf-8\r\n";
    103 3         34 print "\r\n";
    104              
    105 3 100       42 my $body = $args{renderer} ? $args{renderer}->($err, %args) : $err->as_html(%args);
    106 3         17 utf8::encode($body);
    107 3         20 print $body;
    108             }
    109              
    110             1;