use Cro::TCP; use Cro::FCGI::NameValuePairs; use Cro::FCGI::ConnectionState; use Cro::FCGI::Record; use Cro::Transform; use Cro; sub a-sub-with-dashes() { say "Dashy sub"; } my @array = 1, 2, 3; @array[1]; my %hash = <a 1 b 2>; %hash{"a"}; %hash<a>; class X::Cro::FCGI::UnsupportedVersion is Exception { has $.version is required; method message() { "Webserver sent unsupported version: $!version" } } class X::Cro::FCGI::InvalidLength is Exception { method message() { 'Webserver \qq"Oh hello there!" sent a length \\value \'mismatching the expected length.' } } class X::Cro::FCGI::InvalidRole is Exception { has $.role is required; method message() { "Invalid role given: $!role" } } class X::Cro::FCGI::ManagementApplicationMismatch is Exception { method message() { "A management record had a request-id or an application record had no request-id." } } class Cro::FCGI::RecordParser does Cro::Transform does Cro::ConnectionState[Cro::FCGI::ConnectionState] { method consumes() { Cro::TCP::Message } method produces() { Cro::FCGI::Record } method transformer(Supply:D $in, Cro::FCGI::ConnectionState :$connection-state!) { supply { my enum Expecting <Header Payload>; my Buf $buffer .= new; my $request-id; my $length; my $type; my $padding; my Expecting $expecting = Header; whenever $in -> Cro::TCP::Message $packet { my $data = $buffer ~ $packet.data; $buffer .= new; loop { $_ = $expecting; when Header { if $data.elems < 8 { $buffer.append: $data; last; } if $data[0] != 1 { die X::Cro::FCGI::UnsupportedVersion.new: version => $data[0]; } $type = $data[1]; $request-id = ($data[2] +< 8) +| $data[3]; $length = ($data[4] +< 8) +| $data[5]; $padding = $data[6]; # $reserved = $data[7]; $data .= subbuf(8); $expecting = Payload; } when Payload { if $data.elems < $length + $padding { $buffer.append: $data; last; } my Cro::FCGI::Record $record = payload($type, $data, $request-id, $length, :connection($packet.connection)); $data .= subbuf($padding); $expecting = Header; emit $record; } } } } } # FCGI_BEGIN_REQUEST my multi sub payload(1, Buf $data is rw, $request-id, $length, :$connection) { die X::Cro::FCGI::ManagementApplicationMismatch.new if $request-id == 0; die X::Cro::FCGI::InvalidLength.new if $length != 8; my $role = ($data[0] +< 8) +| $data[1]; die X::Cro::FCGI::InvalidRole.new(:$role) unless 1 <= $role <= 3; my $flags = $data[2]; $data .= subbuf($length); Cro::FCGI::Record::BeginRequest.new: :$request-id, role => Role($role), :$flags, :$connection; } # FCGI_ABORT_REQUEST my multi sub payload(2, Buf $data is rw, $request-id, $length, :$connection) { die X::Cro::FCGI::ManagementApplicationMismatch.new if $request-id == 0; die X::Cro::FCGI::InvalidLength.new if $length != 0; $data .= subbuf($length); Cro::FCGI::Record::AbortRequest.new: :$request-id; } # FCGI_PARAMS my multi sub payload(4, Buf $data is rw, $request-id, $length, :$connection) { die X::Cro::FCGI::ManagementApplicationMismatch.new if $request-id == 0; if $length { my $r = Cro::FCGI::Record::Params.new: :$request-id, pair-bytes => Buf.new($data.subbuf(0, $length)); $data .= subbuf($length); $r; } else { Cro::FCGI::Record::Params.new: :$request-id, :ended; } } # FCGI_STREAM my multi sub payload($type where 5|6|7|8, Buf $data is rw, $request-id, $length, :$connection) { die X::Cro::FCGI::ManagementApplicationMismatch.new if $request-id == 0; if $length { my $r = Cro::FCGI::Record::ByteStream.new: :$request-id, stream => Stream($type), data => Buf.new($data.subbuf(0, $length)); $data .= subbuf($length); $r } else { Cro::FCGI::Record::ByteStream.new: :$request-id, stream => Stream($type), :ended; } } # FCGI_GET_VALUES my multi sub payload(9, Buf $data is rw, $request-id, $length is copy, :$connection) { die X::Cro::FCGI::ManagementApplicationMismatch.new if $request-id != 0; my @pairs; while $length > 0 { my $consumed = Cro::FCGI::NameValuePairs::decode-single($data, @pairs, $length, True); $length -= $consumed; $data .= subbuf($consumed); } Cro::FCGI::Record::GetValues.new: :$request-id, :@pairs; } my multi sub payload($unknown, Buf $data is rw, $request-id, $length, :$connection) { my $payload = Buf.new: $data.subbuf(0, $length); $data .= subbuf($length); Cro::FCGI::Record::Unknown.new: :$request-id, :$payload, type => $unknown; } }