diff --git a/lib/Perlbal/Plugin/PSGI.pm b/lib/Perlbal/Plugin/PSGI.pm index 0f6903087..ca8d0c851 100644 --- a/lib/Perlbal/Plugin/PSGI.pm +++ b/lib/Perlbal/Plugin/PSGI.pm @@ -60,7 +60,7 @@ sub handle_request { ); }; - my $res = $app->($env, $start_response); + my $res = Plack::Util::wrap_error { $app->($env, $start_response) } $env; return 1 if @$res == 0; $start_response->($res); diff --git a/lib/Plack/Impl/AnyEvent.pm b/lib/Plack/Impl/AnyEvent.pm index 5cddf5c9d..08cd43b54 100644 --- a/lib/Plack/Impl/AnyEvent.pm +++ b/lib/Plack/Impl/AnyEvent.pm @@ -137,7 +137,7 @@ sub _response_handler { return sub { my($app, $env) = @_; - my $res = $app->($env, $start_response); + my $res = Plack::Util::wrap_error { $app->($env, $start_response) } $env; return if scalar(@$res) == 0; $start_response->($res->[0], $res->[1]); diff --git a/lib/Plack/Impl/Coro.pm b/lib/Plack/Impl/Coro.pm index 93ffeb0dc..d54e9217d 100644 --- a/lib/Plack/Impl/Coro.pm +++ b/lib/Plack/Impl/Coro.pm @@ -54,7 +54,7 @@ sub process_request { my $reqlen = parse_http_request($buf, $env); if ($reqlen >= 0) { - $res = $self->{app}->($env); + $res = Plack::Util::wrap_error { $self->{app}->($env) } $env; last; } elsif ($reqlen == -2) { # incomplete, continue diff --git a/lib/Plack/Impl/Danga/Socket.pm b/lib/Plack/Impl/Danga/Socket.pm index 8ca8ec87a..8e591b466 100644 --- a/lib/Plack/Impl/Danga/Socket.pm +++ b/lib/Plack/Impl/Danga/Socket.pm @@ -198,7 +198,7 @@ sub _response_handler { Scalar::Util::weaken($socket); return sub { my ($app, $env) = @_; - my $res = $app->($env, $state_response); + my $res = Plack::Util::wrap_error { $app->($env, $state_response) } $env; return if scalar(@$res) == 0; $state_response->($res->[0], $res->[1]); diff --git a/lib/Plack/Impl/Standalone.pm b/lib/Plack/Impl/Standalone.pm index 7b51d8f99..2a8a299b5 100644 --- a/lib/Plack/Impl/Standalone.pm +++ b/lib/Plack/Impl/Standalone.pm @@ -96,7 +96,7 @@ sub handle_connection { open my $input, "<", \$buf; $env->{'psgi.input'} = $input; - $res = $app->($env); + $res = Plack::Util::wrap_error { $app->($env) } $env; last; } if ($reqlen == -2) { diff --git a/lib/Plack/Test.pm b/lib/Plack/Test.pm index da21f86b6..285eb0879 100644 --- a/lib/Plack/Test.pm +++ b/lib/Plack/Test.pm @@ -372,7 +372,7 @@ my @TEST = ( }, sub { my $env = shift; - die "Oops"; + die "Throwing an exception from app handler. Server shouldn't crash."; }, sub { my $res = shift; diff --git a/lib/Plack/Util.pm b/lib/Plack/Util.pm index 73b23f8ca..9c7712388 100644 --- a/lib/Plack/Util.pm +++ b/lib/Plack/Util.pm @@ -47,6 +47,19 @@ sub foreach { } } +sub wrap_error(&$) { + my($code, $env) = @_; + + local $@; my $res = eval { $code->() }; + if ($@) { + my $body = "Internal Server Error"; + $env->{'psgi.errors'}->print($@); + return [ 500, [ 'Content-Type' => 'text/plain', 'Content-Length' => length($body) ], [ $body ] ]; + } + + return $res; +} + sub inline_object { my %args = @_; bless {%args}, 'Plack::Util::Prototype'; @@ -127,6 +140,27 @@ guaranteed to be a I) to the callback function. It internally sets the buffer length C<$/> to 4096 in case it reads the binary file, unless otherwise set in the caller's code. +=item wrap_error + + my $res = Plack::Util::wrap_error { $app->($env) } $env; + +Runs the code by wrapping erros and if an error is found, logs it to +C<< $env->{'psgi.errors'} >> and returns the template 500 Error response. + +=item inline_object + + my $o = Plack::Util::inline_object( + write => sub { $h->push_write(@_) }, + close => sub { $h->push_shutdown }, + ); + $o->write(@stuff); + $o->close; + +Creates an instant object that can react to methods passed in the +constructor. Handy to create when you need to create an IO stream +object for input or errors, as well as respone writer object for +L extension. + =back =cut diff --git a/t/090_impl/cgi.t b/t/090_impl/cgi.t index 071d6d931..213357d57 100644 --- a/t/090_impl/cgi.t +++ b/t/090_impl/cgi.t @@ -12,7 +12,7 @@ Plack::Test->runtests(sub { my ($name, $reqgen, $handler, $test) = @_; note $name; my $c = HTTP::Request::AsCGI->new($reqgen->())->setup; - Plack::Impl::CGI->new->run($handler); + eval { Plack::Impl::CGI->new->run($handler) }; $test->($c->response); });