| 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) {