FCGI-EV
view release on metacpan or search on metacpan
lib/FCGI/EV.pm view on Meta::CPAN
package FCGI::EV;
use 5.010001;
use warnings;
use strict;
use utf8;
use Carp;
our $VERSION = 'v2.0.1';
use Scalar::Util qw( weaken );
use IO::Stream;
use constant FCGI_HEADER_LEN => 8;
use constant FCGI_VERSION_1 => 1;
use constant FCGI_BEGIN_REQUEST => 1;
use constant FCGI_END_REQUEST => 3;
use constant FCGI_PARAMS => 4;
use constant FCGI_STDIN => 5;
use constant FCGI_STDOUT => 6;
use constant FCGI_RESPONDER => 1;
use constant FCGI_REQUEST_COMPLETE => 0;
use constant END_REQUEST_COMPLETE =>
pack 'N C CCC', 0, FCGI_REQUEST_COMPLETE, 0, 0, 0;
use constant MAX_CONTENT_LEN => 0xFFFF;
sub new {
my ($class, $sock, $handler_class) = @_;
my $self = bless {
io => undef,
req_id => undef,
params => q{},
stdin_eof => undef,
handler => undef,
handler_class=>$handler_class,
}, $class;
$self->{io} = IO::Stream->new({
fh => $sock,
wait_for => IN|EOF,
cb => $self,
Wait_header => 1,
Need_in => FCGI_HEADER_LEN,
});
weaken($self->{io});
# It MAY have sense to add timeout between read() calls and timeout for
# overall time until EOF on STDIN will be received. First timeout
# can be about 3 minutes for slow clients, second can be about 4 hours
# for uploading huge files.
return;
}
sub DESTROY {
my ($self) = @_;
$self->{handler} = undef; # call handler's DESTROY while $self is alive
return;
}
sub stdout {
my ($self, $stdout, $is_eof) = @_;
my $io = $self->{io};
if (length $stdout) {
$io->{out_buf} .= _pack_pkt(FCGI_STDOUT, $self->{req_id}, $stdout);
}
if ($is_eof) {
$io->{out_buf} .= _pack_pkt(FCGI_STDOUT, $self->{req_id}, q{});
$io->{out_buf} .= _pack_pkt(FCGI_END_REQUEST, $self->{req_id}, END_REQUEST_COMPLETE);
$io->{wait_for} |= SENT;
}
$io->write();
return;
}
sub IO {
my ($self, $io, $e, $err) = @_;
if ($err) {
warn "FCGI::EV: IO: $err\n";
return $io->close();
}
if ($e & EOF) {
return $io->close();
}
if ($e & SENT) {
return $io->close();
}
while (length $io->{in_buf} >= $io->{Need_in}) {
if ($io->{Wait_header}) {
$io->{Wait_header} = 0;
my ($content_len, $padding_len) = unpack 'x4 n C', $io->{in_buf};
$io->{Need_in} += $content_len + $padding_len;
}
else {
my $pkt = substr $io->{in_buf}, 0, $io->{Need_in}, q{};
$io->{Wait_header} = 1;
$io->{Need_in} = FCGI_HEADER_LEN;
my $error = $self->_process($pkt);
if ($error) {
warn "FCGI::EV: $error\n";
return $io->close();
}
}
}
return;
}
sub _process {
my ($self, $pkt) = @_;
my ($ver, $type, $req_id, $content_len) = unpack 'C C n n', $pkt;
my $content = substr $pkt, FCGI_HEADER_LEN, $content_len;
if ($ver != FCGI_VERSION_1) {
return "unsupported version: $ver";
}
if (defined $self->{req_id} && $self->{req_id} != $req_id) {
return "unknown request id: $req_id";
}
( run in 2.211 seconds using v1.01-cache-2.11-cpan-d7a12ab2c7f )