Conduit

 view release on metacpan or  search on metacpan

lib/Conduit/Client.pm  view on Meta::CPAN

   while( defined( my $req = await $self->read_request ) ) {
      my $resp;
      try {
         $resp = await $responder->( $req );
      }
      catch( $e ) {
         chomp $e;
         $resp = HTTP::Response->new( 500, undef,
            [ "Content-Type" => "text/plain" ],
            $e,
         );
      }
      $resp->request( $req );

      $resp->protocol or $resp->protocol( $req->protocol );
      $resp->content_length or $resp->content_length( length $resp->content );

      $bytes_written = 0;

      $server->on_response_header( $req, $resp )
         if $server->can( "on_response_header" );

      await $self->write( $resp->as_string( "\x0D\x0A" ) );
      Conduit::Metrics->sent_response( $resp, $bytes_written );
   }
}

class Conduit::Client::_ForPSGI
   :strict(params);
inherit Conduit::Client qw( $server $bytes_written );

no if $^V lt v5.40, warnings => "experimental::try", "experimental::builtin";

field $psgi_app :param;

async method run ()
{
   while( defined( my $req = await $self->read_request ) ) {
      my $uri = $req->uri;

      my $path_info = $uri->path;
      $path_info = "" if $path_info eq "/";

      open my $stdin, "<", \$req->content;

      my %env = (
         SERVER_PROTOCOL     => $req->protocol,
         SCRIPT_NAME         => '',
         PATH_INFO           => $path_info,
         QUERY_STRING        => $uri->query // "",
         REQUEST_METHOD      => $req->method,
         REQUEST_URI         => $uri->path,
         'psgi.version'      => [1,0],
         'psgi.url_scheme'   => "http",
         'psgi.input'        => $stdin,
         'psgi.errors'       => \*STDERR,
         'psgi.multithread'  => 0,
         'psgi.multiprocess' => 0,
         'psgi.run_once'     => 0,
         'psgi.nonblocking'  => 1,
         'psgi.streaming'    => 1,
      );

      # TODO: socket info

      $req->scan( sub ( $name, $value ) {
         $name =~ s/-/_/g;
         $name = uc $name;

         # Content-Length and Content-Type don't get an HTTP_ prefix
         $name = "HTTP_$name" unless $name =~ m/^CONTENT_(?:LENGTH|TYPE)$/;

         $env{$name} = $value;
      } );

      my $psgiresp;
      try {
         $psgiresp = $psgi_app->( \%env );
      }
      catch( $e ) {
         chomp $e;
         $psgiresp = [ 500, [ "Content-Type" => "text/plain" ], [ $e ] ];
      }

      $bytes_written = 0;

      my $aresponder = async sub ( $v ) {
         my ( $status, $headers, $body ) = @$v;

         my $resp = HTTP::Response->new( $status );

         $resp->request( $req );
         $resp->protocol( $req->protocol );

         my $has_content_length = 0;
         my $use_chunked_transfer = 0;
         while( my ( $key, $value ) = splice @$headers, 0, 2 ) {
            $resp->push_header( $key, $value );

            $has_content_length = 1 if $key eq "Content-Length";
            $use_chunked_transfer = 1 if $key eq "Transfer-Encoding" and $value eq "chunked";
         }

         if( !defined $body ) {
            die "TODO: no body yet; use deferred writer";
         }
         elsif( ref $body eq "ARRAY" ) {
            unless( $has_content_length ) {
               my $len = 0;
               $len += length( $_ ) for @$body;

               $resp->content_length( $len );
            }

            $server->on_response_header( $req, $resp )
               if $server->can( "on_response_header" );

            await $self->write( $resp->as_string( "\x0D\x0A" ) );

            foreach my $chunk ( @$body ) {
               await $self->write( $chunk );



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