Starlight

 view release on metacpan or  search on metacpan

lib/Starlight/Server.pm  view on Meta::CPAN

    local $SIG{PIPE} = 'IGNORE';

    while (!defined $max_reqs_per_child || $proc_req_count < $max_reqs_per_child) {
        my ($conn, $peer) = $self->{listen_sock}->accept or do {
            warn "failed to accept: $!\n";
            next;
        };

        my ($peerport, $peerhost, $peeraddr) = (0, undef, undef);
        if ($self->{_listen_sock_is_tcp}) {
            if (HAS_INET6 && Socket::sockaddr_family(getsockname($conn)) == AF_INET6) {
                ($peerport, $peerhost) = Socket::unpack_sockaddr_in6($peer);
                $peeraddr = Socket::inet_ntop(AF_INET6, $peerhost);
            } else {
                ($peerport, $peerhost) = Socket::unpack_sockaddr_in($peer);
                $peeraddr = Socket::inet_ntoa($peerhost);
            }
            if (try { TCP_NODELAY }) {
                $conn->setsockopt(IPPROTO_TCP, TCP_NODELAY, 1)
                    or do {
                    warn "setsockopt(TCP_NODELAY) failed for $peeraddr:$peerport: $!\n";
                    next;
                    };
            }
        }

        if ($conn->isa('IO::Socket::SSL')) {
            $conn->accept_SSL or do {
                my @err = ();
                push @err, $!                          if $!;
                push @err, $IO::Socket::SSL::SSL_ERROR if $IO::Socket::SSL::SSL_ERROR;
                warn "failed to ssl handshake with $peeraddr:$peerport: @{[join ': ', @err]}\n";
                next;
            };
        }

        $self->{_is_deferred_accept} = $self->{_using_defer_accept};
        $conn->blocking(0)
            or do {
            warn "failed to set socket to nonblocking mode for $peeraddr:$peerport: $!\n";
            next;
            };

        my $req_count = 0;
        my $pipelined_buf = '';
        while (1) {
            ++$req_count;
            ++$proc_req_count;
            my $env = {
                SERVER_PORT            => $self->{port} || 0,
                SERVER_NAME            => $self->{host} || '*',
                SCRIPT_NAME            => '',
                REMOTE_ADDR            => $peeraddr,
                REMOTE_PORT            => $peerport,
                'psgi.version'         => [1, 1],
                'psgi.errors'          => *STDERR,
                'psgi.url_scheme'      => $self->{ssl} ? 'https' : 'http',
                'psgi.run_once'        => Plack::Util::FALSE,
                'psgi.multithread'     => $self->{is_multithread},
                'psgi.multiprocess'    => $self->{is_multiprocess},
                'psgi.streaming'       => Plack::Util::TRUE,
                'psgi.nonblocking'     => Plack::Util::FALSE,
                'psgix.input.buffered' => Plack::Util::TRUE,
                'psgix.io'             => $conn,
                'psgix.harakiri'       => Plack::Util::TRUE,
            };

            my $may_keepalive = $req_count < $self->{max_keepalive_reqs};
            if ($may_keepalive && $max_reqs_per_child && $proc_req_count >= $max_reqs_per_child) {
                $may_keepalive = undef;
            }
            $may_keepalive = 1 if length $pipelined_buf;
            my $keepalive;
            ($keepalive, $pipelined_buf) = $self->handle_connection(
                $env, $conn, $app,
                $may_keepalive, $req_count != 1, $pipelined_buf
            );

            if ($env->{'psgix.harakiri.commit'}) {
                $conn->close;
                return;
            }
            last unless $keepalive;

# TODO add special cases for clients with broken keep-alive support, as well as disabling keep-alive for HTTP/1.0 proxies
        }
        $conn->close;
    }
}

my $bad_response = [400, ['Content-Type' => 'text/plain', 'Connection' => 'close'], ['Bad Request']];

sub handle_connection {
    my ($self, $env, $conn, $app, $use_keepalive, $is_keepalive, $prebuf) = @_;

    my $buf = '';
    my $pipelined_buf = '';
    my $res = $bad_response;

    local $self->{can_exit} = (defined $prebuf) ? 0 : 1;
    while (1) {
        my $rlen;
        if ($rlen = length $prebuf) {
            $buf = $prebuf;
            undef $prebuf;
        } else {
            $rlen = $self->read_timeout(
                $conn, \$buf, MAX_REQUEST_SIZE - length($buf), length($buf),
                $is_keepalive ? $self->{keepalive_timeout} : $self->{timeout},
            ) or return;
        }
        $self->{can_exit} = 0;
        my $reqlen = parse_http_request($buf, $env);
        if ($reqlen >= 0) {

            # handle request
            my $protocol = $env->{SERVER_PROTOCOL};
            if ($use_keepalive) {
                if ($protocol eq 'HTTP/1.1') {
                    if (my $c = $env->{HTTP_CONNECTION}) {
                        $use_keepalive = undef



( run in 0.506 second using v1.01-cache-2.11-cpan-437f7b0c052 )