blib/lib/Plack/Middleware/InteractiveDebugger/HTML.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 15 | 56 | 26.7 |
branch | 0 | 12 | 0.0 |
condition | 0 | 2 | 0.0 |
subroutine | 5 | 13 | 38.4 |
pod | 0 | 8 | 0.0 |
total | 20 | 91 | 21.9 |
line | stmt | bran | cond | sub | pod | time | code | |
---|---|---|---|---|---|---|---|---|
1 | package Plack::Middleware::InteractiveDebugger::HTML; | |||||||
2 | 1 | 1 | 7 | use strict; | ||||
1 | 1 | |||||||
1 | 32 | |||||||
3 | 1 | 1 | 11 | use warnings; | ||||
1 | 4 | |||||||
1 | 62 | |||||||
4 | ||||||||
5 | 1 | 1 | 6 | use parent qw(Exporter); | ||||
1 | 1 | |||||||
1 | 8 | |||||||
6 | our @EXPORT = qw( render_full render_source encode_html ); | |||||||
7 | ||||||||
8 | 1 | 1 | 79 | use Scalar::Util qw(refaddr); | ||||
1 | 1 | |||||||
1 | 224 | |||||||
9 | ||||||||
10 | my $header = < | |||||||
11 | ||||||||
12 | "http://www.w3.org/TR/html4/loose.dtd"> | |||||||
13 | ||||||||
14 | ||||||||
15 | |
|||||||
16 | ||||||||
17 | ||||||||
18 | ||||||||
19 | ||||||||
25 | ||||||||
26 | ||||||||
27 | |
|||||||
28 | EOF | |||||||
29 | ||||||||
30 | my $footer = < | |||||||
31 | ||||||||
32 | Brought to you by DON'T PANIC, your | |||||||
33 | friendly Plack powered stacktrace interpreter, inspired by Werkzeug. | |||||||
34 | ||||||||
35 | ||||||||
36 | ||||||||
37 | ||||||||
38 | EOF | |||||||
39 | ||||||||
40 | my $page_html = $header . < | |||||||
41 | %(exception_type) |
|||||||
42 | |
|||||||
43 | %(exception) |
|||||||
44 | ||||||||
45 | StackTrace (most recent call first) |
|||||||
46 | %(summary) | |||||||
47 | |
|||||||
48 |
|
|||||||
49 | This is the Copy/Paste friendly version of the stacktrace. | |||||||
50 | ||||||||
51 | ||||||||
52 | ||||||||
53 | ||||||||
54 | |
|||||||
55 | The debugger caught an exception in your PSGI application. You can now | |||||||
56 | look at the stacktrace which led to the error. | |||||||
57 | If you enable JavaScript you can also use additional features such as code | |||||||
58 | execution and much more. | |||||||
59 | ||||||||
60 | EOF | |||||||
61 | ||||||||
62 | my $console_html = $header . < | |||||||
63 | Interactive Console |
|||||||
64 | |
|||||||
65 | In this console you can execute Perl expressions in the context of the | |||||||
66 | application. | |||||||
67 | ||||||||
68 | The Console requires JavaScript. |
|||||||
69 | EOF | |||||||
70 | ||||||||
71 | my $summary_html = < | |||||||
72 | |
|||||||
73 | StackTrace (most recent call first) | |||||||
74 |
|
|||||||
75 | ||||||||
76 | EOF | |||||||
77 | ||||||||
78 | my $frame_html = < | |||||||
79 | |
|||||||
80 | File "%(filename)", |
|||||||
81 | line %(lineno), | |||||||
82 | in %(function_name) |
|||||||
83 | %(current_line) |
|||||||
84 | ||||||||
85 | EOF | |||||||
86 | ||||||||
87 | my $source_table_html = ' |
|||||||
88 | ||||||||
89 | my $source_line_html = < | |||||||
90 | ||||||||
91 | %(lineno) | |||||||
92 | %(code) | |||||||
93 | ||||||||
94 | EOF | |||||||
95 | ||||||||
96 | 1 | 1 | 7 | no warnings 'qw'; | ||||
1 | 2 | |||||||
1 | 773 | |||||||
97 | my %enc = qw( & & > > < < " " ' ' ); | |||||||
98 | ||||||||
99 | sub encode_html { | |||||||
100 | 0 | 0 | 0 | my $str = shift; | ||||
101 | 0 | 0 | $str =~ s/([^\x00-\x21\x23-\x25\x28-\x3b\x3d\x3f-\xff])/$enc{$1} || '' . ord($1) . ';' /ge; | |||||
0 | ||||||||
102 | 0 | utf8::downgrade($str); | ||||||
103 | 0 | $str; | ||||||
104 | } | |||||||
105 | ||||||||
106 | sub render { | |||||||
107 | 0 | 0 | 0 | my($html, $vars) = @_; | ||||
108 | 0 | $html =~ s/%\((.*?)\)/$vars->{$1}/g; | ||||||
109 | 0 | $html; | ||||||
110 | } | |||||||
111 | ||||||||
112 | sub current_line { | |||||||
113 | 0 | 0 | 0 | my $frame = shift; | ||||
114 | ||||||||
115 | 0 | 0 | open my $fh, "<", $frame->filename or return ''; | |||||
116 | 0 | my @lines = <$fh>; | ||||||
117 | ||||||||
118 | 0 | my $line = $lines[$frame->line-1]; | ||||||
119 | 0 | $line =~ s/^\s+//; | ||||||
120 | 0 | $line; | ||||||
121 | } | |||||||
122 | ||||||||
123 | sub render_frame { | |||||||
124 | 0 | 0 | 0 | my($trace, $idx) = @_; | ||||
125 | ||||||||
126 | 0 | my $frame = $trace->frame($idx); | ||||||
127 | ||||||||
128 | 0 | 0 | render $frame_html, { | |||||
129 | id => refaddr($trace) . "-" . $idx, | |||||||
130 | filename => encode_html($frame->filename), | |||||||
131 | lineno => $frame->line, | |||||||
132 | function_name => $frame->subroutine ? encode_html($frame->subroutine) : '', | |||||||
133 | current_line => current_line($frame), | |||||||
134 | }; | |||||||
135 | } | |||||||
136 | ||||||||
137 | sub render_line { | |||||||
138 | 0 | 0 | 0 | my($frame, $line, $lineno) = @_; | ||||
139 | ||||||||
140 | 0 | my @classes = ('line'); | ||||||
141 | 0 | 0 | push @classes, 'current' if $frame->line == $lineno; | |||||
142 | ||||||||
143 | 0 | render $source_line_html, { | ||||||
144 | classes => join(" ", @classes), | |||||||
145 | lineno => $lineno, | |||||||
146 | code => encode_html($line), | |||||||
147 | }; | |||||||
148 | } | |||||||
149 | ||||||||
150 | sub render_source { | |||||||
151 | 0 | 0 | 0 | my $frame = shift; | ||||
152 | ||||||||
153 | 0 | my $source; | ||||||
154 | ||||||||
155 | 0 | 0 | open my $fh, "<", $frame->filename or return ''; | |||||
156 | 0 | my @lines = <$fh>; | ||||||
157 | ||||||||
158 | 0 | my $lineno = 1; | ||||||
159 | 0 | for my $line (@lines) { | ||||||
160 | 0 | $source .= render_line $frame, $line, $lineno++; | ||||||
161 | 0 | $source .= "\n"; | ||||||
162 | } | |||||||
163 | ||||||||
164 | 0 | render $source_table_html, { source => $source }; | ||||||
165 | } | |||||||
166 | ||||||||
167 | sub render_summary { | |||||||
168 | 0 | 0 | 0 | my $trace = shift; | ||||
169 | ||||||||
170 | 0 | my @classes = ('traceback'); | ||||||
171 | 0 | 0 | unless ($trace->frames) { | |||||
172 | 0 | push @classes, 'noframe-traceback'; | ||||||
173 | } | |||||||
174 | ||||||||
175 | 0 | my $out; | ||||||
176 | 0 | for my $idx (0..$trace->frame_count-1) { | ||||||
177 | 0 | $out .= ' |
||||||
178 | } | |||||||
179 | ||||||||
180 | 0 | render $summary_html, { | ||||||
181 | classes => join(" ", @classes), | |||||||
182 | frames => $out, | |||||||
183 | }; | |||||||
184 | } | |||||||
185 | ||||||||
186 | sub render_full { | |||||||
187 | 0 | 0 | 0 | my($env, $trace) = @_; | ||||
188 | 0 | my $msg = encode_html($trace->frame(0)->as_string(1)); | ||||||
189 | 0 | 0 | render $page_html, { | |||||
190 | script_name => $env->{SCRIPT_NAME}, | |||||||
191 | evalex => 'true', | |||||||
192 | console => 'false', | |||||||
193 | title => $msg, | |||||||
194 | exception => $msg, | |||||||
195 | exception_type => ref(($trace->frame(0)->args)[0]) || "Error", | |||||||
196 | summary => render_summary($trace), | |||||||
197 | plaintext => $trace->as_string, | |||||||
198 | traceback_id => refaddr($trace), | |||||||
199 | }; | |||||||
200 | } | |||||||
201 | ||||||||
202 | 1; |