Porbo

 view release on metacpan or  search on metacpan

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

        $$listen_port_r = $port;
        $self->{server_ready}->({
            host => $host,
            port => $port,
            server_software => 'Porbo',
        }) if $self->{server_ready};

        return $self->{backlog} || 0;
    };
}

sub _accept_handler {
    my ($self, $app, $listen_host_r, $listen_port_r, $ssl) = @_;

    $app = Plack::Middleware::ContentLength->wrap($app);

    return sub {
        my ( $sock, $peer_host, $peer_port ) = @_;

        DEBUG && warn "$sock Accepted connection from $peer_host:$peer_port\n";
        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 %args;
        if ($ssl) {
            $args{tls} = 'accept';
            $args{tls_ctx} = {
                key_file => $self->{ssl_key_file},
                cert_file  => $self->{ssl_cert_file},
            };
        }

        my $handle; $handle = AnyEvent::Handle->new(
            fh => $sock,
            on_error => sub {
                if ($handle) {
                    $handle->destroy;
                    $self->{exit_guard}->end;
                }
            },
            %args,
        );

        $handle->push_read(line => "\015\012\015\012", sub {
            my ($hdl, $header) = @_;

            my $env = {
                SERVER_NAME => $$listen_host_r,
                SERVER_PORT => $$listen_port_r,
                SCRIPT_NAME => '',
                REMOTE_ADDR => $peer_host,
                'psgi.version' => [ 1, 0 ],
                'psgi.errors'  => *STDERR,
                'psgi.url_scheme' => $ssl ? 'https' : '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'        => undef, # will be set by _run_app()
                'psgix.io'          => $hdl->fh,
                'psgix.input.buffered' => Plack::Util::TRUE,
            };

            my $reqlen = parse_http_request($header."\015\012\015\012", $env);
            if ($reqlen < 0) {
                return $self->_bad_request($handle, 0);
            }

            unless ( eval {
                $self->_run_app($app, $env, $handle);
                1;
            }) {
                my $disconnected = ($@ =~ /^client disconnected/);
                $self->_bad_request($handle, $disconnected);
            }
            undef $handle;
        });
    };
}

sub _run_app {
    my ($self, $app, $env, $handle) = @_;

    unless ($env->{'psgi.input'}) {
        if ($env->{CONTENT_LENGTH}) {
            my $body;
            $handle->on_read(sub {
                $body .= $_[0]->rbuf;
                $_[0]->rbuf = "";
                if ($env->{CONTENT_LENGTH} <= length $body) {
                    open my $input, '<', \$body;
                    $env->{'psgi.input'} = $input;
                    $self->_run_app($app, $env, $handle);
                }
            });
            return;
        } else {
            $env->{'psgi.input'} = $null_io;
        }
    }

    my $res = Plack::Util::run_app $app, $env;

    if ( ref $res eq 'ARRAY' ) {
        $self->_write_psgi_response($handle, $res);
    } elsif (ref $res eq 'CODE') {
        $res->(sub {
            $self->_write_psgi_response($handle, $_[0]);
        });
    } else {
        croak("Unknown response type: $res");
    }
}

sub _bad_request {



( run in 0.849 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )