Plack-Server-AnyEvent
view release on metacpan or search on metacpan
lib/Plack/Server/AnyEvent.pm view on Meta::CPAN
sub new {
my($class, @args) = @_;
return bless {
host => undef,
port => undef,
no_delay => 1,
@args,
}, $class;
}
sub register_service {
my($self, $app) = @_;
$app = Plack::Middleware::ContentLength->wrap($app);
# $app = Plack::Middleware::Chunked->wrap($app);
$self->{listen_guard} = $self->_create_tcp_server($app);
}
sub _create_tcp_server {
my ( $self, $app ) = @_;
return tcp_server $self->{host}, $self->{port}, $self->_accept_handler($app), sub {
my ( $fh, $host, $port ) = @_;
$self->{prepared_host} = $host;
$self->{prepared_port} = $port;
warn "Accepting requests at http://$host:$port/\n";
return 0;
};
}
sub _accept_handler {
my ( $self, $app ) = @_;
return sub {
my ( $sock, $peer_host, $peer_port ) = @_;
return unless $sock;
$self->{exit_guard}->begin;
if ( $self->{no_delay} ) {
setsockopt($sock, IPPROTO_TCP, TCP_NODELAY, 1)
or die "setsockopt(TCP_NODELAY) failed:$!";
}
my $headers = "";
my $try_parse = sub {
if ( $self->_try_read_headers($sock, $headers) ) {
my $env = {
SERVER_PORT => $self->{prepared_port},
SERVER_NAME => $self->{prepared_host},
SCRIPT_NAME => '',
'psgi.version' => [ 1, 0 ],
'psgi.errors' => *STDERR,
'psgi.url_scheme' => 'http',
'psgi.nonblocking' => Plack::Util::TRUE,
'psgi.streaming' => Plack::Util::TRUE,
'psgi.run_once' => Plack::Util::FALSE,
'psgi.multithread' => Plack::Util::FALSE,
'psgi.multiprocess' => Plack::Util::FALSE,
'psgi.input' => $sock,
'REMOTE_ADDR' => $peer_host,
};
my $reqlen = parse_http_request($headers, $env);
if ( $reqlen < 0 ) {
die "bad request";
} else {
return $env;
}
}
return;
};
local $@;
unless ( eval {
if ( my $env = $try_parse->() ) {
# the request data is already available, no need to parse more
$self->_run_app($app, $env, $sock);
} else {
# there's not yet enough data to parse the request,
# set up a watcher
$self->_create_req_parsing_watcher( $sock, $try_parse, $app );
};
1;
}) {
$self->_bad_request($sock);
}
};
}
# returns a closure that tries to parse
# this is not a method because it needs a buffer per socket
sub _try_read_headers {
my ( $self, $sock, undef ) = @_;
# FIXME add a timer to manage read timeouts
local $/ = "\012";
read_more: for my $headers ( $_[2] ) {
if ( defined(my $line = <$sock>) ) {
$headers .= $line;
if ( $line eq "\015\012" or $line eq "\012" ) {
# got an empty line, we're done reading the headers
return 1;
} else {
# try to read more lines using buffered IO
redo read_more;
}
} elsif ($! and $! != EAGAIN && $! != EINTR && $! != WSAEWOULDBLOCK ) {
die $!;
}
}
lib/Plack/Server/AnyEvent.pm view on Meta::CPAN
$sock_handle->on_error($err);
$body_handle->on_error($err);
$body_handle->on_eof(sub {
$body_handle->destroy;
$sock_handle->on_drain(sub {
shutdown $sock_handle->fh, 1;
$sock_handle->destroy;
$cv->send(1);
});
});
$sock_handle->on_drain(sub {
$body_handle->push_read(sub {
$sock_handle->push_write($_[0]{rbuf});
$_[0]{rbuf} = '';
});
});
return $cv;
}
}
sub run {
my $self = shift;
$self->register_service(@_);
my $exit = $self->{exit_guard} = AnyEvent->condvar;
$exit->begin;
my $w; $w = AE::signal QUIT => sub { $exit->end; undef $w };
$exit->recv;
}
# ex: set sw=4 et:
1;
__END__
=head1 NAME
Plack::Server::AnyEvent - DEPRECATED. Use Twiggy
=head1 WARNING
This software is deprecated. Use L<Twiggy> instead.
=head1 SYNOPSIS
my $server = Plack::Server::AnyEvent->new(
host => $host,
port => $port,
);
$server->run($app);
=head1 DESCRIPTION
Plack::Server::AnyEvent is a Plack server implementation using
AnyEvent. This server runs in a non-blocking event loop and suitable
for event-driven web applications like streaming API servers.
=head1 LICENSE
This module is licensed under the same terms as Perl itself.
=head1 AUTHOR
Tokuhiro Matsuno
Yuval Kogman
Tatsuhiko Miyagawa
=head1 SEE ALSO
L<Twiggy>
=cut
( run in 0.766 second using v1.01-cache-2.11-cpan-39bf76dae61 )