plack/Plack

Plack::App::Cascade expects the $respond_wrapper to be called immediately

ufobat opened this issue · 0 comments

Hi,

I've been working with an async PSGI server. And i've been running into troubles with Plack::App::Cascade. I am not sure but I think that using $done (https://github.com/plack/Plack/blob/master/lib/Plack/App/Cascade.pm#L58) within the iteration is not correct. Because it requires that $respond_wrapped is called immediatly (https://github.com/plack/Plack/blob/master/lib/Plack/App/Cascade.pm#L54) and I think the spec is not requireing this, right? At least my Async PSGI implementation is not calling it immediately, but waits till the Application has fulfilled the request.

IMHO Cascade.pm needs to wait until the application is really done with the request. This is my "hack" that might solve this issue:

sub call {
    my($self, $env) = @_;

    return sub {
        my $respond = shift;
        my @try = @{$self->apps || []};
        my $tries_left = 0 + @try;

        my $respond_wrapper = sub {
            my $res = shift;

            if ($self->codes->{$res->[0]}) {
                # suppress output by giving the app an
                # output spool which drops everything on the floor
                $self->call_next_app(\@try, $env, __SUB__, $respond);
                return Plack::Util::inline_object
                    write => sub { }, close => sub { };
            } else {
                return $respond->($res);
            }
        };


        if (not $tries_left) {
            return $respond->([ 404, [ 'Content-Type' => 'text/html' ], [ '404 Not Found' ] ])
        }

        $self->call_next_app(\@try, $env, $respond_wrapper, $respond);
    };
}

sub call_next_app {
    my $self            = shift;
    my $try             = shift;
    my $env             = shift;
    my $respond_wrapper = shift;
    my $respond         = shift;

    my $app = shift @$try;
    return unless $app;

    my $res = $app->($env);
    unless (@$try) {
        $respond_wrapper = sub { $respond->(shift) };
    }

    if (ref $res eq 'CODE') {
        $res->($respond_wrapper);
    } else {
        $respond_wrapper->($res);
    }
}