| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Mojolicious::Plugin::PlackMiddleware; | 
| 2 | 6 |  |  | 6 |  | 712425 | use strict; | 
|  | 6 |  |  |  |  | 26 |  | 
|  | 6 |  |  |  |  | 193 |  | 
| 3 | 6 |  |  | 6 |  | 39 | use warnings; | 
|  | 6 |  |  |  |  | 12 |  | 
|  | 6 |  |  |  |  | 174 |  | 
| 4 | 6 |  |  | 6 |  | 577 | use Mojo::Base 'Mojolicious::Plugin'; | 
|  | 6 |  |  |  |  | 192041 |  | 
|  | 6 |  |  |  |  | 39 |  | 
| 5 | 6 |  |  | 6 |  | 4652 | use Plack::Util; | 
|  | 6 |  |  |  |  | 11688 |  | 
|  | 6 |  |  |  |  | 199 |  | 
| 6 | 6 |  |  | 6 |  | 566 | use Mojo::Message::Request; | 
|  | 6 |  |  |  |  | 100985 |  | 
|  | 6 |  |  |  |  | 77 |  | 
| 7 | 6 |  |  | 6 |  | 762 | use Mojo::Message::Response; | 
|  | 6 |  |  |  |  | 7073 |  | 
|  | 6 |  |  |  |  | 57 |  | 
| 8 |  |  |  |  |  |  | our $VERSION = '0.37'; | 
| 9 | 6 |  |  | 6 |  | 308 | use Scalar::Util 'weaken'; | 
|  | 6 |  |  |  |  | 13 |  | 
|  | 6 |  |  |  |  | 4207 |  | 
| 10 |  |  |  |  |  |  |  | 
| 11 |  |  |  |  |  |  | ### --- | 
| 12 |  |  |  |  |  |  | ### register | 
| 13 |  |  |  |  |  |  | ### --- | 
| 14 |  |  |  |  |  |  | sub register { | 
| 15 | 17 |  |  | 17 | 1 | 183286 | my ($self, $app, $mws) = @_; | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  | my $plack_app = sub { | 
| 18 | 24 |  |  | 24 |  | 778 | my $env = shift; | 
| 19 | 24 |  |  |  |  | 81 | my $tx = $env->{'mojo.c'}->tx; | 
| 20 |  |  |  |  |  |  |  | 
| 21 | 24 |  |  |  |  | 125 | $tx->req(psgi_env_to_mojo_req($env)); | 
| 22 |  |  |  |  |  |  |  | 
| 23 | 24 | 100 |  |  |  | 228 | if ($env->{'mojo.routed'}) { | 
| 24 | 2 |  |  |  |  | 11 | my $stash = $env->{'mojo.c'}->stash; | 
| 25 | 2 |  |  |  |  | 20 | for my $key (grep {$_ =~ qr{^mojo\.}} keys %{$stash}) { | 
|  | 15 |  |  |  |  | 75 |  | 
|  | 2 |  |  |  |  | 11 |  | 
| 26 | 10 |  |  |  |  | 25 | delete $stash->{$key}; | 
| 27 |  |  |  |  |  |  | } | 
| 28 | 2 |  |  |  |  | 6 | delete $stash->{'status'}; | 
| 29 | 2 |  |  |  |  | 8 | my $sever = $tx->res->headers->header('server'); | 
| 30 | 2 |  |  |  |  | 53 | $tx->res(Mojo::Message::Response->new); | 
| 31 | 2 |  |  |  |  | 34 | $tx->res->headers->header('server', $sever); | 
| 32 | 2 |  |  |  |  | 133 | $env->{'mojo.inside_app'}->(); | 
| 33 |  |  |  |  |  |  | } else { | 
| 34 | 22 |  |  |  |  | 93 | $env->{'mojo.inside_app'}->(); | 
| 35 | 22 |  |  |  |  | 121882 | $env->{'mojo.routed'} = 1; | 
| 36 |  |  |  |  |  |  | } | 
| 37 |  |  |  |  |  |  |  | 
| 38 | 24 |  |  |  |  | 2802 | return mojo_res_to_psgi_res($tx->res); | 
| 39 | 17 |  |  |  |  | 95 | }; | 
| 40 |  |  |  |  |  |  |  | 
| 41 | 17 |  |  |  |  | 60 | my @mws = reverse @$mws; | 
| 42 | 17 |  |  |  |  | 69 | while (scalar @mws) { | 
| 43 | 20 | 100 |  |  |  | 205 | my $args = (ref $mws[0] eq 'HASH') ? shift @mws : undef; | 
| 44 | 20 | 100 |  |  |  | 59 | my $cond = (ref $mws[0] eq 'CODE') ? shift @mws : undef; | 
| 45 | 20 |  |  |  |  | 65 | my $e = _load_class(shift @mws, 'Plack::Middleware'); | 
| 46 |  |  |  |  |  |  | $plack_app = Mojolicious::Plugin::PlackMiddleware::_Cond->wrap( | 
| 47 |  |  |  |  |  |  | $plack_app, | 
| 48 |  |  |  |  |  |  | condition => $cond, | 
| 49 | 20 |  |  | 20 |  | 1237 | builder => sub {$e->wrap($_[0], %$args)}, | 
| 50 | 20 |  |  |  |  | 205 | ); | 
| 51 |  |  |  |  |  |  | } | 
| 52 |  |  |  |  |  |  |  | 
| 53 |  |  |  |  |  |  | $app->hook('around_dispatch' => sub { | 
| 54 | 23 |  |  | 23 |  | 220903 | my ($next, $c) = @_; | 
| 55 |  |  |  |  |  |  |  | 
| 56 | 23 | 50 |  |  |  | 101 | return $next->() if ($c->tx->req->error); | 
| 57 |  |  |  |  |  |  |  | 
| 58 | 23 |  |  |  |  | 378 | my $plack_env = mojo_req_to_psgi_env($c->req); | 
| 59 | 23 |  |  |  |  | 7107 | $plack_env->{'mojo.c'} = $c; | 
| 60 | 23 |  |  |  |  | 59 | $plack_env->{'mojo.inside_app'} = $next; | 
| 61 |  |  |  |  |  |  | $plack_env->{'psgi.errors'} = | 
| 62 |  |  |  |  |  |  | Mojolicious::Plugin::PlackMiddleware::_EH->new(sub { | 
| 63 | 0 |  |  |  |  | 0 | $c->app->log->debug(shift); | 
| 64 | 23 |  |  |  |  | 212 | }); | 
| 65 |  |  |  |  |  |  |  | 
| 66 | 23 |  |  |  |  | 226 | $c->tx->res(psgi_res_to_mojo_res($plack_app->($plack_env))); | 
| 67 | 23 | 100 |  |  |  | 495 | $c->rendered if (! $plack_env->{'mojo.routed'}); | 
| 68 | 17 |  |  |  |  | 924 | }); | 
| 69 |  |  |  |  |  |  | } | 
| 70 |  |  |  |  |  |  |  | 
| 71 |  |  |  |  |  |  | ### --- | 
| 72 |  |  |  |  |  |  | ### chunk size | 
| 73 |  |  |  |  |  |  | ### --- | 
| 74 | 6 |  | 50 | 6 |  | 49 | use constant CHUNK_SIZE => $ENV{MOJO_CHUNK_SIZE} || 131072; | 
|  | 6 |  |  |  |  | 17 |  | 
|  | 6 |  |  |  |  | 7156 |  | 
| 75 |  |  |  |  |  |  |  | 
| 76 |  |  |  |  |  |  | ### --- | 
| 77 |  |  |  |  |  |  | ### convert psgi env to mojo req | 
| 78 |  |  |  |  |  |  | ### --- | 
| 79 |  |  |  |  |  |  | sub psgi_env_to_mojo_req { | 
| 80 |  |  |  |  |  |  |  | 
| 81 | 25 |  |  | 25 | 1 | 1223 | my $env = shift; | 
| 82 | 25 |  |  |  |  | 87 | my $req = Mojo::Message::Request->new->parse($env); | 
| 83 |  |  |  |  |  |  |  | 
| 84 | 25 |  |  |  |  | 17684 | $req->reverse_proxy($env->{MOJO_REVERSE_PROXY}); | 
| 85 |  |  |  |  |  |  |  | 
| 86 |  |  |  |  |  |  | # Request body | 
| 87 | 25 |  |  |  |  | 228 | my $len = $env->{CONTENT_LENGTH}; | 
| 88 | 25 |  |  |  |  | 76 | while (!$req->is_finished) { | 
| 89 | 4 | 50 | 33 |  |  | 41 | my $chunk = ($len && $len < CHUNK_SIZE) ? $len : CHUNK_SIZE; | 
| 90 | 4 |  |  |  |  | 16 | my $read = $env->{'psgi.input'}->read(my $buffer, $chunk, 0); | 
| 91 | 4 | 100 |  |  |  | 14 | last unless $read; | 
| 92 | 3 |  |  |  |  | 12 | $req->parse($buffer); | 
| 93 | 3 |  |  |  |  | 1515 | $len -= $read; | 
| 94 | 3 | 50 |  |  |  | 13 | last if $len <= 0; | 
| 95 |  |  |  |  |  |  | } | 
| 96 |  |  |  |  |  |  |  | 
| 97 | 25 |  |  |  |  | 207 | return $req; | 
| 98 |  |  |  |  |  |  | } | 
| 99 |  |  |  |  |  |  |  | 
| 100 |  |  |  |  |  |  | ### --- | 
| 101 |  |  |  |  |  |  | ### convert mojo tx to psgi env | 
| 102 |  |  |  |  |  |  | ### --- | 
| 103 |  |  |  |  |  |  | sub mojo_req_to_psgi_env { | 
| 104 |  |  |  |  |  |  |  | 
| 105 | 24 |  |  | 24 | 1 | 2882 | my $mojo_req = shift; | 
| 106 | 24 |  |  |  |  | 69 | my $url = $mojo_req->url; | 
| 107 | 24 |  |  |  |  | 143 | my $base = $url->base; | 
| 108 | 24 |  |  |  |  | 168 | my $body = | 
| 109 |  |  |  |  |  |  | Mojolicious::Plugin::PlackMiddleware::_PSGIInput->new($mojo_req->build_body); | 
| 110 |  |  |  |  |  |  |  | 
| 111 | 24 |  |  |  |  | 53 | my %headers_org = %{$mojo_req->headers->to_hash}; | 
|  | 24 |  |  |  |  | 78 |  | 
| 112 | 24 |  |  |  |  | 1763 | my %headers; | 
| 113 | 24 |  |  |  |  | 88 | for my $key (keys %headers_org) { | 
| 114 |  |  |  |  |  |  |  | 
| 115 | 99 |  |  |  |  | 228 | my $value = $headers_org{$key}; | 
| 116 | 99 |  |  |  |  | 272 | $key =~ s{-}{_}g; | 
| 117 | 99 |  |  |  |  | 208 | $key = uc $key; | 
| 118 | 99 | 100 |  |  |  | 380 | $key = "HTTP_$key" if ($key !~ /^(?:CONTENT_LENGTH|CONTENT_TYPE)$/); | 
| 119 | 99 |  |  |  |  | 305 | $headers{$key} = $value; | 
| 120 |  |  |  |  |  |  | } | 
| 121 |  |  |  |  |  |  |  | 
| 122 |  |  |  |  |  |  | return { | 
| 123 | 24 |  |  |  |  | 362 | %ENV, | 
| 124 |  |  |  |  |  |  | %headers, | 
| 125 |  |  |  |  |  |  | 'SERVER_PROTOCOL'   => $base->protocol. '/'. $mojo_req->version, | 
| 126 |  |  |  |  |  |  | 'SERVER_NAME'       => $base->host, | 
| 127 |  |  |  |  |  |  | 'SERVER_PORT'       => $base->port, | 
| 128 |  |  |  |  |  |  | 'REQUEST_METHOD'    => $mojo_req->method, | 
| 129 |  |  |  |  |  |  | 'SCRIPT_NAME'       => '', | 
| 130 |  |  |  |  |  |  | 'PATH_INFO'         => $url->path->to_string, | 
| 131 |  |  |  |  |  |  | 'REQUEST_URI'       => $url->to_string, | 
| 132 |  |  |  |  |  |  | 'QUERY_STRING'      => $url->query->to_string, | 
| 133 |  |  |  |  |  |  | 'psgi.url_scheme'   => $base->scheme, | 
| 134 |  |  |  |  |  |  | 'psgi.version'      => [1,1], | 
| 135 |  |  |  |  |  |  | 'psgi.errors'       => *STDERR, | 
| 136 |  |  |  |  |  |  | 'psgi.input'        => $body, | 
| 137 |  |  |  |  |  |  | 'psgi.multithread'  => Plack::Util::FALSE, | 
| 138 |  |  |  |  |  |  | 'psgi.multiprocess' => Plack::Util::TRUE, | 
| 139 |  |  |  |  |  |  | 'psgi.run_once'     => Plack::Util::FALSE, | 
| 140 |  |  |  |  |  |  | 'psgi.streaming'    => Plack::Util::TRUE, | 
| 141 |  |  |  |  |  |  | 'psgi.nonblocking'  => Plack::Util::FALSE, | 
| 142 |  |  |  |  |  |  | }; | 
| 143 |  |  |  |  |  |  | } | 
| 144 |  |  |  |  |  |  |  | 
| 145 |  |  |  |  |  |  | ### --- | 
| 146 |  |  |  |  |  |  | ### convert psgi res to mojo res | 
| 147 |  |  |  |  |  |  | ### --- | 
| 148 |  |  |  |  |  |  | sub psgi_res_to_mojo_res { | 
| 149 | 24 |  |  | 24 | 1 | 11771 | my $psgi_res = shift; | 
| 150 | 24 |  |  |  |  | 147 | my $mojo_res = Mojo::Message::Response->new; | 
| 151 | 24 |  |  |  |  | 247 | $mojo_res->code($psgi_res->[0]); | 
| 152 | 24 |  |  |  |  | 223 | my $headers = $mojo_res->headers; | 
| 153 | 24 |  |  |  |  | 900 | while (scalar @{$psgi_res->[1]}) { | 
|  | 82 |  |  |  |  | 1030 |  | 
| 154 | 58 |  |  |  |  | 114 | $headers->add(shift @{$psgi_res->[1]} => shift @{$psgi_res->[1]}); | 
|  | 58 |  |  |  |  | 130 |  | 
|  | 58 |  |  |  |  | 156 |  | 
| 155 |  |  |  |  |  |  | } | 
| 156 |  |  |  |  |  |  |  | 
| 157 | 24 |  |  |  |  | 94 | $headers->remove('Content-Length'); # should be set by mojolicious later | 
| 158 |  |  |  |  |  |  |  | 
| 159 | 24 |  |  |  |  | 193 | my $asset = $mojo_res->content->asset; | 
| 160 | 24 |  |  | 23 |  | 476 | Plack::Util::foreach($psgi_res->[2], sub {$asset->add_chunk($_[0])}); | 
|  | 23 |  |  |  |  | 446 |  | 
| 161 | 24 |  |  |  |  | 868 | weaken($psgi_res); | 
| 162 | 24 |  |  |  |  | 97 | return $mojo_res; | 
| 163 |  |  |  |  |  |  | } | 
| 164 |  |  |  |  |  |  |  | 
| 165 |  |  |  |  |  |  | ### --- | 
| 166 |  |  |  |  |  |  | ### convert mojo res to psgi res | 
| 167 |  |  |  |  |  |  | ### --- | 
| 168 |  |  |  |  |  |  | sub mojo_res_to_psgi_res { | 
| 169 | 24 |  |  | 24 | 1 | 141 | my $mojo_res = shift; | 
| 170 | 24 |  |  |  |  | 72 | my $status = $mojo_res->code; | 
| 171 | 24 |  |  |  |  | 158 | my $headers = $mojo_res->content->headers; | 
| 172 | 24 |  |  |  |  | 163 | my @headers; | 
| 173 | 24 |  |  |  |  | 51 | push @headers, $_ => $headers->header($_) for (@{$headers->names}); | 
|  | 24 |  |  |  |  | 85 |  | 
| 174 | 24 |  |  |  |  | 846 | my @body; | 
| 175 | 24 |  |  |  |  | 55 | my $offset = 0; | 
| 176 |  |  |  |  |  |  |  | 
| 177 |  |  |  |  |  |  | # don't know why but this block makes long polling tests to pass | 
| 178 | 24 | 0 | 33 |  |  | 66 | if ($mojo_res->content->is_dynamic && $mojo_res->content->{delay}) { | 
| 179 | 0 |  |  |  |  | 0 | $mojo_res->get_body_chunk(0); | 
| 180 |  |  |  |  |  |  | } | 
| 181 |  |  |  |  |  |  |  | 
| 182 | 24 |  |  |  |  | 263 | while (length(my $chunk = $mojo_res->get_body_chunk($offset))) { | 
| 183 | 24 |  |  |  |  | 1215 | push(@body, $chunk); | 
| 184 | 24 |  |  |  |  | 76 | $offset += length $chunk; | 
| 185 |  |  |  |  |  |  | } | 
| 186 | 24 |  |  |  |  | 1441 | return [$status, \@headers, \@body]; | 
| 187 |  |  |  |  |  |  | } | 
| 188 |  |  |  |  |  |  |  | 
| 189 |  |  |  |  |  |  | ### --- | 
| 190 |  |  |  |  |  |  | ### load mw class | 
| 191 |  |  |  |  |  |  | ### --- | 
| 192 |  |  |  |  |  |  | sub _load_class { | 
| 193 | 20 |  |  | 20 |  | 50 | my($class, $prefix) = @_; | 
| 194 |  |  |  |  |  |  |  | 
| 195 | 20 | 50 |  |  |  | 60 | if ($prefix) { | 
| 196 | 20 | 50 | 33 |  |  | 214 | unless ($class =~ s/^\+// || $class =~ /^$prefix/) { | 
| 197 | 20 |  |  |  |  | 84 | $class = "$prefix\::$class"; | 
| 198 |  |  |  |  |  |  | } | 
| 199 |  |  |  |  |  |  | } | 
| 200 | 20 | 100 |  |  |  | 234 | if ($class->can('call')) { | 
| 201 | 16 |  |  |  |  | 49 | return $class; | 
| 202 |  |  |  |  |  |  | } | 
| 203 | 4 |  |  |  |  | 10 | my $file = $class; | 
| 204 | 4 |  |  |  |  | 19 | $file =~ s!::!/!g; | 
| 205 | 4 |  |  |  |  | 2182 | require "$file.pm"; ## no critic | 
| 206 |  |  |  |  |  |  |  | 
| 207 | 4 |  |  |  |  | 14814 | return $class; | 
| 208 |  |  |  |  |  |  | } | 
| 209 |  |  |  |  |  |  |  | 
| 210 |  |  |  |  |  |  |  | 
| 211 |  |  |  |  |  |  | ### --- | 
| 212 |  |  |  |  |  |  | ### Error Handler | 
| 213 |  |  |  |  |  |  | ### --- | 
| 214 |  |  |  |  |  |  | package Mojolicious::Plugin::PlackMiddleware::_EH; | 
| 215 | 6 |  |  | 6 |  | 72 | use Mojo::Base -base; | 
|  | 6 |  |  |  |  | 15 |  | 
|  | 6 |  |  |  |  | 35 |  | 
| 216 |  |  |  |  |  |  |  | 
| 217 |  |  |  |  |  |  | __PACKAGE__->attr('handler'); | 
| 218 |  |  |  |  |  |  |  | 
| 219 |  |  |  |  |  |  | sub new { | 
| 220 | 23 |  |  | 23 |  | 71 | my ($class, $handler) = @_; | 
| 221 | 23 |  |  |  |  | 92 | my $self = $class->SUPER::new; | 
| 222 | 23 |  |  |  |  | 203 | $self->handler($handler); | 
| 223 |  |  |  |  |  |  | } | 
| 224 |  |  |  |  |  |  |  | 
| 225 |  |  |  |  |  |  | sub print { | 
| 226 | 0 |  |  | 0 |  | 0 | my ($self, $error) = @_; | 
| 227 | 0 |  |  |  |  | 0 | $self->handler->($error); | 
| 228 |  |  |  |  |  |  | } | 
| 229 |  |  |  |  |  |  |  | 
| 230 |  |  |  |  |  |  | ### --- | 
| 231 |  |  |  |  |  |  | ### Port of Plack::Middleware::Conditional with mojolicious controller | 
| 232 |  |  |  |  |  |  | ### --- | 
| 233 |  |  |  |  |  |  | package Mojolicious::Plugin::PlackMiddleware::_Cond; | 
| 234 | 6 |  |  | 6 |  | 1604 | use strict; | 
|  | 6 |  |  |  |  | 17 |  | 
|  | 6 |  |  |  |  | 174 |  | 
| 235 | 6 |  |  | 6 |  | 43 | use warnings; | 
|  | 6 |  |  |  |  | 15 |  | 
|  | 6 |  |  |  |  | 214 |  | 
| 236 | 6 |  |  | 6 |  | 37 | use parent qw(Plack::Middleware::Conditional); | 
|  | 6 |  |  |  |  | 13 |  | 
|  | 6 |  |  |  |  | 33 |  | 
| 237 |  |  |  |  |  |  |  | 
| 238 |  |  |  |  |  |  | sub call { | 
| 239 | 29 |  |  | 29 |  | 680 | my($self, $env) = @_; | 
| 240 | 29 |  |  |  |  | 116 | my $cond = $self->condition; | 
| 241 | 29 | 100 | 100 |  |  | 221 | if (! $cond || $cond->($env->{'mojo.c'}, $env)) { | 
| 242 | 28 |  |  |  |  | 487 | return $self->middleware->($env); | 
| 243 |  |  |  |  |  |  | } else { | 
| 244 | 1 |  |  |  |  | 9 | return $self->app->($env); | 
| 245 |  |  |  |  |  |  | } | 
| 246 |  |  |  |  |  |  | } | 
| 247 |  |  |  |  |  |  |  | 
| 248 |  |  |  |  |  |  | ### --- | 
| 249 |  |  |  |  |  |  | ### PSGI Input handler | 
| 250 |  |  |  |  |  |  | ### --- | 
| 251 |  |  |  |  |  |  | package Mojolicious::Plugin::PlackMiddleware::_PSGIInput; | 
| 252 | 6 |  |  | 6 |  | 15959 | use strict; | 
|  | 6 |  |  |  |  | 61 |  | 
|  | 6 |  |  |  |  | 130 |  | 
| 253 | 6 |  |  | 6 |  | 33 | use warnings; | 
|  | 6 |  |  |  |  | 13 |  | 
|  | 6 |  |  |  |  | 1170 |  | 
| 254 |  |  |  |  |  |  |  | 
| 255 |  |  |  |  |  |  | sub new { | 
| 256 | 27 |  |  | 27 |  | 3555 | my ($class, $content) = @_; | 
| 257 | 27 |  |  |  |  | 114 | return bless [$content, 0, length($content)], $class; | 
| 258 |  |  |  |  |  |  | } | 
| 259 |  |  |  |  |  |  |  | 
| 260 |  |  |  |  |  |  | sub read { | 
| 261 | 13 |  |  | 13 |  | 3393 | my $self = shift; | 
| 262 | 13 |  | 100 |  |  | 69 | my $offset = ($_[2] || $self->[1]); | 
| 263 | 13 | 50 |  |  |  | 42 | if ($offset <= $self->[2]) { | 
| 264 | 13 | 100 |  |  |  | 51 | if ($_[0] = substr($self->[0], $offset, $_[1])) { | 
| 265 | 10 |  |  |  |  | 23 | $self->[1] = $offset + length($_[0]); | 
| 266 | 10 |  |  |  |  | 24 | return 1; | 
| 267 |  |  |  |  |  |  | } | 
| 268 |  |  |  |  |  |  | } | 
| 269 |  |  |  |  |  |  | } | 
| 270 |  |  |  |  |  |  |  | 
| 271 |  |  |  |  |  |  | 1; | 
| 272 |  |  |  |  |  |  |  | 
| 273 |  |  |  |  |  |  | __END__ |