blib/lib/Plack/Middleware/HTMLLint.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 89 | 90 | 98.8 |
branch | 22 | 26 | 84.6 |
condition | 4 | 5 | 80.0 |
subroutine | 15 | 15 | 100.0 |
pod | 2 | 3 | 66.6 |
total | 132 | 139 | 94.9 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | package Plack::Middleware::HTMLLint; | ||||||
2 | 2 | 2 | 90656 | use 5.008_001; | |||
2 | 8 | ||||||
2 | 93 | ||||||
3 | 2 | 2 | 12 | use strict; | |||
2 | 5 | ||||||
2 | 75 | ||||||
4 | 2 | 2 | 14 | use warnings; | |||
2 | 9 | ||||||
2 | 166 | ||||||
5 | |||||||
6 | our $VERSION = '0.02'; | ||||||
7 | |||||||
8 | 2 | 2 | 1085 | use parent qw/ Plack::Middleware /; | |||
2 | 376 | ||||||
2 | 15 | ||||||
9 | |||||||
10 | use constant +{ | ||||||
11 | 2 | 216 | PSGI_STATUS => 0, | ||||
12 | PSGI_HEADER => 1, | ||||||
13 | PSGI_BODY => 2, | ||||||
14 | 2 | 2 | 23652 | }; | |||
2 | 13 | ||||||
15 | |||||||
16 | use constant +{ | ||||||
17 | 2 | 129 | SYNTAX_HTML5 => 'html5', | ||||
18 | SYNTAX_HTML4 => 'html4', | ||||||
19 | SYNTAX_XHTML => 'xhtml', | ||||||
20 | 2 | 2 | 11 | }; | |||
2 | 5 | ||||||
21 | |||||||
22 | 2 | 2 | 11 | use Plack::Util; | |||
2 | 3 | ||||||
2 | 46 | ||||||
23 | 2 | 2 | 18 | use Plack::Util::Accessor qw/error2html/; | |||
2 | 4 | ||||||
2 | 13 | ||||||
24 | 2 | 2 | 1898 | use HTML::Lint; | |||
2 | 109225 | ||||||
2 | 77 | ||||||
25 | 2 | 2 | 2125 | use HTML::Escape qw/escape_html/; | |||
2 | 1953 | ||||||
2 | 1965 | ||||||
26 | |||||||
27 | sub prepare_app { | ||||||
28 | 2 | 2 | 1 | 665 | my $self = shift; | ||
29 | 2 | 50 | 8 | unless ($self->error2html) { | |||
30 | $self->error2html(sub { | ||||||
31 | 4 | 4 | 33 | my @errors = @_; | |||
32 | |||||||
33 | 4 | 32 | my @error_html; | ||||
34 | 4 | 8 | push @error_html => ' '; |
||||
35 | 4 | 9 | push @error_html => 'HTML Error'; |
||||
36 | 4 | 8 | push @error_html => '
|
||||
37 | 4 | 9 | foreach my $error (@errors) { | ||||
38 | 6 | 96 | push @error_html => ' |
||||
39 | 6 | 68 | push @error_html => ' |
||||
40 | } | ||||||
41 | 4 | 127 | push @error_html => ''; | ||||
42 | |||||||
43 | 4 | 9 | push @error_html => ''; | ||||
44 | |||||||
45 | 4 | 33 | return join '', @error_html; | ||||
46 | 2 | 101 | }); | ||||
47 | } | ||||||
48 | } | ||||||
49 | |||||||
50 | sub call { | ||||||
51 | 8 | 8 | 1 | 49207 | my($self, $env) = @_; | ||
52 | |||||||
53 | return $self->response_cb($self->app->($env), sub { | ||||||
54 | 8 | 8 | 904 | my $res = shift; | |||
55 | 8 | 50 | 29 | my $content_type = Plack::Util::header_get($res->[PSGI_HEADER], 'Content-Type') || ''; | |||
56 | |||||||
57 | 8 | 100 | 226 | if ($content_type =~ m{^(?:text/x?html|application/xhtml\+xml)\b}io) {# HTML/XHTML | |||
58 | my $do_lint = sub { | ||||||
59 | 6 | 11 | my $content = shift; | ||||
60 | |||||||
61 | 6 | 50 | 30 | my $syntax = ($content =~ /^$/imo) ? SYNTAX_HTML5: | |||
50 | |||||||
62 | ($content_type =~ m{^(?:text/xhtml|application/xhtml\+xml)\b}io) ? SYNTAX_XHTML: | ||||||
63 | SYNTAX_HTML4; | ||||||
64 | |||||||
65 | 6 | 100 | 18 | if (my @errors = $self->html_lint($syntax => $content)) { | |||
66 | 4 | 58 | return $self->error2html->(@errors); | ||||
67 | } | ||||||
68 | else { | ||||||
69 | 2 | 38 | return ''; | ||||
70 | } | ||||||
71 | 6 | 26 | }; | ||||
72 | |||||||
73 | 6 | 100 | 17 | if ($res->[PSGI_BODY]) { | |||
74 | 3 | 4 | my $content = ''; | ||||
75 | 3 | 16 | Plack::Util::foreach($res->[PSGI_BODY] => sub { $content .= $_[0] }); | ||||
3 | 27 | ||||||
76 | 3 | 100 | 16 | if (my $error_html = $do_lint->($content)) { | |||
77 | 2 | 100 | 20 | unless ($content =~ s{]*)>}{$error_html}i) { | |||
78 | ## fallback | ||||||
79 | 1 | 3 | $content .= $error_html; | ||||
80 | } | ||||||
81 | 2 | 15 | $res->[PSGI_BODY] = [$content]; | ||||
82 | } | ||||||
83 | } | ||||||
84 | else { | ||||||
85 | # XXX: It has become increasingly complex not to block the stream as possible. | ||||||
86 | 3 | 9 | my $buffer = ''; | ||||
87 | 3 | 4 | my $html_last_buffer = ''; | ||||
88 | 3 | 5 | my $end_of_html_body = 0; | ||||
89 | 3 | 3 | my $do_lint_finished = 0; | ||||
90 | return sub { | ||||||
91 | 33 | 1221 | my $body_chunk = shift; | ||||
92 | 33 | 100 | 58 | if (defined $body_chunk) { | |||
93 | 30 | 37 | $buffer .= $body_chunk; | ||||
94 | 30 | 100 | 100 | 116 | if ($end_of_html_body || $body_chunk =~ m{}io) { | ||
95 | 8 | 11 | $end_of_html_body = 1; | ||||
96 | 8 | 9 | $html_last_buffer .= $body_chunk; | ||||
97 | 8 | 36 | return ''; | ||||
98 | } | ||||||
99 | else { | ||||||
100 | 22 | 101 | return $body_chunk; | ||||
101 | } | ||||||
102 | } | ||||||
103 | else { | ||||||
104 | 3 | 50 | 9 | if ($do_lint_finished) { | |||
105 | 0 | 0 | return; | ||||
106 | } | ||||||
107 | else { | ||||||
108 | 3 | 7 | my $error_html = $do_lint->($buffer); | ||||
109 | 3 | 100 | 15 | if ($error_html) { | |||
110 | 2 | 100 | 15 | unless ($html_last_buffer =~ s{}{$error_html |
}i) {