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 )