unbit/uwsgi — pull request #211 by avar (2013-04-03 16:10:46+00:00)
Title: PSGI Plugin: psgix.input.buffered should *not* be set to whatever post_b...

...uffering is set to

The psgix.input.buffered variable doesn't just mean "hey, I happen to
be buffering things internally in case you were interested". From the
PSGI spec:

If psgix.input.buffered environment is true, it MUST implement
the seek method.

While uWSGI technically complies with that with this stub method:

XS(XS_input_seek) {
dXSARGS;
psgi_check_args(1);
XSRETURN(0);
}

It doesn't actually sync, this means that the *first* thing that reads
psgi.input via uwsgi::input will get content, but everything else
doesn't. This plays very badly with
Plack::Request::_parse_request_body() which does:

my $input = $self->input;

my $buffer;
if ($self->env->{'psgix.input.buffered'}) {
# Just in case if input is read by middleware/apps beforehand
$input->seek(0, 0);
} else {
$buffer = Stream::Buffered->new($cl);
}

And later:

$buffer->print($chunk) if $buffer;

So $buffer never ends up being true if psgix.input.buffered=1, so
Plack::Request doesn't save away what it just read (since it assumes
it can get it back!), so later calling e.g. Plack::Request::raw_body()
does:

$fh->seek(0, 0); # just in case middleware/apps read it without seeking back
$fh->read(my($content), $cl, 0);
$fh->seek(0, 0);

And gets nothing! All of this fail is avoided if we just set
psgix.input.buffered=0 which'll cause Plack itself to buffer things up
via Stream::Buffered. In the future this could be set to true if uWSGI
actually implements the interface psgix.input.buffered requires.