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/</g; | ||||
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${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; |