POEx-Role-PSGIServer

 view release on metacpan or  search on metacpan

lib/POEx/Role/PSGIServer.pm  view on Meta::CPAN

           || ($code == 304);

        if ($no_body_allowed) {
            $self->_write($c, "\r\n");
            $self->close($c);
            return Plack::Util::FALSE;
        }

        return Plack::Util::TRUE;
    }


    method respond(PSGIServerContext $c, PSGIResponse $response) is Event {
        $self->http_preamble($c, $response);
        $self->process_headers($c, $response);
        return unless ($self->http_body_allowed($c, $response));

       
        $self->_write($c, "Transfer-Encoding: chunked\r\n") if $c->{chunked};
        $self->_write($c, "\r\n");
        
        my $body = $response->[2];
        if ($body) {
            # If we have a real filehandle, build a Streamer
            if (Plack::Util::is_real_fh($body)) {
                # flush and destroy the old wheel, since the Streamer will build a new one
                $c->{wheel}->flush();
                $self->delete_wheel($c->{wheel}->ID);
                my $handle = (delete $c->{wheel})->get_input_handle();
                my $streamer = POEx::Role::PSGIServer::Streamer->new(
                    input_handle => $body,
                    output_handle => $handle,
                    server_context => $c,
                );
            }
            # If we don't just iterate the lines
            else {
                Plack::Util::foreach($body, sub{$self->write($c, @_)});
                $self->close($c);
            }

            return;
        }

        # If there was no body, we need to build a push writer
        return $self->generate_push_writer($c);
    }


    method generate_push_writer(PSGIServerContext $c) returns (Object) {
        return POEx::Role::PSGIServer::ProxyWriter->new(server_context => $c, proxied => $self);
    }


    method generate_psgi_env(PSGIServerContext $c) returns (HashRef) {
        return req_to_psgi(
            $c->{request},
            SERVER_NAME         => $self->listen_ip,
            SERVER_PORT         => $self->listen_port,
            SERVER_PROTOCOL     => $c->{protocol},
            'psgi.streaming'    => Plack::Util::TRUE,
            'psgi.nonblocking'  => Plack::Util::TRUE,
            'psgi.runonce'      => Plack::Util::FALSE,
        );
    }


    method build_server_context(HTTPRequest $req, WheelID $wheel_id) returns (PSGIServerContext) {
        my $version  = $req->header('X-HTTP-Version') || '0.9';
        my $protocol = "HTTP/$version";
        my $connection = $req->header('Connection') || '';
        my $keep_alive = ($version eq '1.1' && $connection ne 'close');
        
        my $context = {
            request => $req,
            wheel => $self->get_wheel($wheel_id),
            version => $version,
            protocol => $protocol,
            connection => $connection,
            keep_alive => $keep_alive,
            explicit_length => 0,
        };

        return $context;
    }


    method handle_inbound_data(HTTPRequest $req, WheelID $wheel_id) is Event {
        my $context = $self->build_server_context($req, $wheel_id);
        my $env = $self->generate_psgi_env($context);
        my $response = Plack::Util::run_app($self->psgi_app, $env);

        if (ref($response) eq 'CODE') {
            $response->(sub { $self->respond($context, @_) });
        }
        else {
            $self->yield('respond', $context, $response);
        }
    }


    method run(CodeRef $app) {
        $self->register_service($app);
        POE::Kernel->run();
    }

    method handle_on_flushed(WheelID $id) is Event {
        if ($self->has_wheel_flusher($id)) {
            $self->get_wheel_flusher($id)->();
        }
        1;
    }

    after delete_wheel(WheelID $id) {
        $self->clear_wheel_flusher($id);
    }

    with 'POEx::Role::TCPServer' => {
        -excludes => [
            qw/handle_socket_error handle_listen_error handle_on_flushed/
        ]
    };
}

__END__

=pod

=head1 NAME

POEx::Role::PSGIServer - (DEPRECATED) Encapsulates core PSGI server behavior

=head1 VERSION

version 1.150280

=head1 SYNOPSIS

    use MooseX::Declare;
    class MyServer with POEx::Role::PSGIServer { }

    MyServer->new()->run($some_psgi_app);

=head1 DESCRIPTION

This module has been deprecated.

POEx::Role::PSGIServer encapsulates the core L<PSGI> server behaviors into an easy to consume and extend role. It is based on previous POEx work such as POEx::Role::TCPServer which provides basic TCP socket multiplexing via POE::Wheel::SocketFactory ...

=head2 RATIONALE

This Role has its roots firmly planted in POE::Component::Server::PSGI which provided the initial seed with the layout and logic of the basic server. Unfortunately, POE::Component::Server::PSGI didn't provide any mechnism for extension. The main goal...

=head1 CLASS_METHODS

=head2 around BUILDARGS

    (ClassName $class: @args)

BUILDARGS is wrapped to translate from the expected Plack::Handler interface to POEx::Role::TCPServer's expected interface.

=head1 PUBLIC_ATTRIBUTES

=head2 psgi_app

    is: ro, isa: CodeRef, writer: register_service

This attribute stores the PSGI application to be run from this server. A writer method is provided to match the expected Plack::Handler interface

=head1 PROTECTED_ATTRIBUTES

=head2 wheel_flushers

    is: ro, isa: HashRef,
    exists : has_wheel_flusher,
    get    : get_wheel_flusher,
    set    : set_wheel_flusher,
    delete : clear_wheel_flusher

This attribute stores coderefs to be called on a wheel's flush event
(necessary to properly handle poll_cb)

=head1 PUBLIC_METHODS

=head2 run

    (CodeRef $app)

run is provided to complete the Plack::Handler interface and allow the server to be executed with the provided psgi app

=head1 PROTECTED_METHODS

=head2 after _start

    is Event

_start is advised to supply the proper input (HTTP::Parser) and output (Stream) filters.

=head2 write

    (PSGIServerContext $c, Str $data)

write will alter the data if necessary for a chunked transfer encoded response and send it to the output buffer for the current context

=head2 close

    (PSGIServerContext $c)

close will close the connection for the current context, but flushing the output buffer first

=head2 handle_socket_error



( run in 0.599 second using v1.01-cache-2.11-cpan-140bd7fdf52 )