-module(fcgi@internal@protocol). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/fcgi/internal/protocol.gleam"). -export([encode_record_tree_unchecked/3, encode_record_bits_unchecked/3, encode_name_value_pairs/1, encode_record/1, encode_stdout_record_header/2, chunk_stdout/2, parse_name_value_pairs/1, parse_record/1]). -export_type([outgoing/0, status/0, incoming/0, parse_failure/0, parse_result/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC(false). -type outgoing() :: {end_request, integer(), integer(), status()} | {stdout, integer(), bitstring()} | {get_values_result, list({binary(), binary()})} | {unknown_type, integer()}. -type status() :: request_complete | cant_multiplex_connection | overloaded | unknown_role. -type incoming() :: {begin_request, integer(), integer(), boolean()} | {abort_request, integer()} | {params, integer(), bitstring()} | {stdin, integer(), bitstring()} | {get_values, list(binary())} | {incoming_unknown, integer(), integer()}. -type parse_failure() :: {unsupported_version, integer()} | malformed_record | malformed_name_value. -type parse_result() :: {parsed, incoming(), bitstring()} | need_more | {parse_error, parse_failure()}. -file("src/fcgi/internal/protocol.gleam", 104). ?DOC(false). -spec padding_for(integer()) -> integer(). padding_for(Content_length) -> Remainder = case 8 of 0 -> 0; Gleam@denominator -> Content_length rem Gleam@denominator end, case Remainder of 0 -> 0; _ -> 8 - Remainder end. -file("src/fcgi/internal/protocol.gleam", 83). ?DOC(false). -spec encode_record_tree_unchecked( integer(), integer(), gleam@bytes_tree:bytes_tree() ) -> gleam@bytes_tree:bytes_tree(). encode_record_tree_unchecked(Record_type, Request_id, Body) -> Content_length = erlang:iolist_size(Body), Padding_length = padding_for(Content_length), Header = <<1:8, Record_type:8, Request_id:16, Content_length:16, Padding_length:8, 0:8>>, Padding = <<0:(erlang:max(0, (Padding_length * 8)))>>, _pipe = gleam@bytes_tree:from_bit_array(Header), _pipe@1 = gleam_stdlib:iodata_append(_pipe, Body), gleam@bytes_tree:append(_pipe@1, Padding). -file("src/fcgi/internal/protocol.gleam", 74). ?DOC(false). -spec encode_record_bits_unchecked(integer(), integer(), bitstring()) -> gleam@bytes_tree:bytes_tree(). encode_record_bits_unchecked(Record_type, Request_id, Body) -> _pipe = gleam@bytes_tree:from_bit_array(Body), encode_record_tree_unchecked(Record_type, Request_id, _pipe). -file("src/fcgi/internal/protocol.gleam", 136). ?DOC(false). -spec encode_length(integer()) -> bitstring(). encode_length(N) -> case N < 128 of true -> <>; false -> <<1:1, N:31>> end. -file("src/fcgi/internal/protocol.gleam", 121). ?DOC(false). -spec encode_name_value_pairs(list({binary(), binary()})) -> gleam@bytes_tree:bytes_tree(). encode_name_value_pairs(Pairs) -> gleam@list:fold( Pairs, gleam@bytes_tree:new(), fun(Acc, Pair) -> {Name, Value} = Pair, Name_bytes = gleam_stdlib:identity(Name), Value_bytes = gleam_stdlib:identity(Value), Name_length = erlang:byte_size(Name_bytes), Value_length = erlang:byte_size(Value_bytes), _pipe = Acc, _pipe@1 = gleam@bytes_tree:append(_pipe, encode_length(Name_length)), _pipe@2 = gleam@bytes_tree:append( _pipe@1, encode_length(Value_length) ), _pipe@3 = gleam@bytes_tree:append(_pipe@2, Name_bytes), gleam@bytes_tree:append(_pipe@3, Value_bytes) end ). -file("src/fcgi/internal/protocol.gleam", 112). ?DOC(false). -spec status_to_int(status()) -> integer(). status_to_int(Status) -> case Status of request_complete -> 0; cant_multiplex_connection -> 1; overloaded -> 2; unknown_role -> 3 end. -file("src/fcgi/internal/protocol.gleam", 50). ?DOC(false). -spec encode_record(outgoing()) -> gleam@bytes_tree:bytes_tree(). encode_record(Record) -> case Record of {end_request, Id, App_status, Protocol_status} -> Body = <>, encode_record_bits_unchecked(3, Id, Body); {stdout, Id@1, Data} -> encode_record_bits_unchecked(6, Id@1, Data); {get_values_result, Pairs} -> encode_record_tree_unchecked(10, 0, encode_name_value_pairs(Pairs)); {unknown_type, Type_byte} -> Body@1 = <>, encode_record_bits_unchecked(11, 0, Body@1) end. -file("src/fcgi/internal/protocol.gleam", 147). ?DOC(false). -spec encode_stdout_record_header(integer(), integer()) -> {bitstring(), integer()}. encode_stdout_record_header(Request_id, Content_length) -> Padding_length = padding_for(Content_length), Header = <<1:8, 6:8, Request_id:16, Content_length:16, Padding_length:8, 0:8>>, {Header, Padding_length}. -file("src/fcgi/internal/protocol.gleam", 167). ?DOC(false). -spec chunk_stdout_loop(integer(), bitstring(), list(outgoing())) -> list(outgoing()). chunk_stdout_loop(Request_id, Body, Acc) -> Total = erlang:byte_size(Body), gleam@bool:guard( Total =:= 0, lists:reverse(Acc), fun() -> gleam@bool:guard( Total =< 65535, lists:reverse([{stdout, Request_id, Body} | Acc]), fun() -> Head@1 = case gleam_stdlib:bit_array_slice(Body, 0, 65535) of {ok, Head} -> Head; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"fcgi/internal/protocol"/utf8>>, function => <<"chunk_stdout_loop"/utf8>>, line => 180, value => _assert_fail, start => 4560, 'end' => 4631, pattern_start => 4571, pattern_end => 4579}) end, Tail@1 = case gleam_stdlib:bit_array_slice( Body, 65535, Total - 65535 ) of {ok, Tail} -> Tail; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"fcgi/internal/protocol"/utf8>>, function => <<"chunk_stdout_loop"/utf8>>, line => 181, value => _assert_fail@1, start => 4634, 'end' => 4764, pattern_start => 4645, pattern_end => 4653}) end, chunk_stdout_loop( Request_id, Tail@1, [{stdout, Request_id, Head@1} | Acc] ) end ) end ). -file("src/fcgi/internal/protocol.gleam", 163). ?DOC(false). -spec chunk_stdout(integer(), bitstring()) -> list(outgoing()). chunk_stdout(Request_id, Body) -> chunk_stdout_loop(Request_id, Body, []). -file("src/fcgi/internal/protocol.gleam", 340). ?DOC(false). -spec parse_length(bitstring()) -> {ok, {integer(), bitstring()}} | {error, parse_failure()}. parse_length(Bytes) -> case Bytes of <<0:1, N:7, Rest/bitstring>> -> {ok, {N, Rest}}; <<1:1, N@1:31, Rest@1/bitstring>> -> {ok, {N@1, Rest@1}}; _ -> {error, malformed_name_value} end. -file("src/fcgi/internal/protocol.gleam", 313). ?DOC(false). -spec parse_one_pair(bitstring()) -> {ok, {{binary(), binary()}, bitstring()}} | {error, parse_failure()}. parse_one_pair(Bytes) -> gleam@result:'try'( parse_length(Bytes), fun(_use0) -> {Name_length, After_name_length} = _use0, gleam@result:'try'( parse_length(After_name_length), fun(_use0@1) -> {Value_length, After_value_length} = _use0@1, case After_value_length of <> -> gleam@result:'try'( begin _pipe = gleam@bit_array:to_string( Name_bytes ), gleam@result:replace_error( _pipe, malformed_name_value ) end, fun(Name) -> gleam@result:map( begin _pipe@1 = gleam@bit_array:to_string( Value_bytes ), gleam@result:replace_error( _pipe@1, malformed_name_value ) end, fun(Value) -> {{Name, Value}, Rest} end ) end ); _ -> {error, malformed_name_value} end end ) end ). -file("src/fcgi/internal/protocol.gleam", 300). ?DOC(false). -spec parse_name_value_pairs_loop(bitstring(), list({binary(), binary()})) -> {ok, list({binary(), binary()})} | {error, parse_failure()}. parse_name_value_pairs_loop(Bytes, Acc) -> gleam@bool:guard( erlang:byte_size(Bytes) =:= 0, {ok, lists:reverse(Acc)}, fun() -> gleam@result:'try'( parse_one_pair(Bytes), fun(_use0) -> {Pair, Rest} = _use0, parse_name_value_pairs_loop(Rest, [Pair | Acc]) end ) end ). -file("src/fcgi/internal/protocol.gleam", 294). ?DOC(false). -spec parse_name_value_pairs(bitstring()) -> {ok, list({binary(), binary()})} | {error, parse_failure()}. parse_name_value_pairs(Bytes) -> parse_name_value_pairs_loop(Bytes, []). -file("src/fcgi/internal/protocol.gleam", 284). ?DOC(false). -spec parse_get_values(bitstring(), bitstring()) -> parse_result(). parse_get_values(Body, Rest) -> case parse_name_value_pairs(Body) of {error, Reason} -> {parse_error, Reason}; {ok, Pairs} -> Names = gleam@list:map(Pairs, fun gleam@pair:first/1), {parsed, {get_values, Names}, Rest} end. -file("src/fcgi/internal/protocol.gleam", 273). ?DOC(false). -spec parse_begin_request(integer(), bitstring(), bitstring()) -> parse_result(). parse_begin_request(Id, Body, Rest) -> case Body of <> -> {parsed, {begin_request, Id, Role, Keep_bit =:= 1}, Rest}; _ -> {parse_error, malformed_record} end. -file("src/fcgi/internal/protocol.gleam", 257). ?DOC(false). -spec parse_body(integer(), integer(), bitstring(), bitstring()) -> parse_result(). parse_body(Record_type, Id, Body, Rest) -> case Record_type of 1 -> parse_begin_request(Id, Body, Rest); 2 -> {parsed, {abort_request, Id}, Rest}; 4 -> {parsed, {params, Id, Body}, Rest}; 5 -> {parsed, {stdin, Id, Body}, Rest}; 9 -> parse_get_values(Body, Rest); _ -> {parsed, {incoming_unknown, Id, Record_type}, Rest} end. -file("src/fcgi/internal/protocol.gleam", 235). ?DOC(false). -spec parse_after_header( integer(), integer(), integer(), integer(), integer(), bitstring() ) -> parse_result(). parse_after_header( Version, Record_type, Id, Content_length, Padding_length, Rest ) -> gleam@bool:guard( Version /= 1, {parse_error, {unsupported_version, Version}}, fun() -> case Rest of <> -> parse_body(Record_type, Id, Body, Remaining); _ -> need_more end end ). -file("src/fcgi/internal/protocol.gleam", 212). ?DOC(false). -spec parse_record(bitstring()) -> parse_result(). parse_record(Buffer) -> case Buffer of <> -> parse_after_header( Version, Record_type, Id, Content_length, Padding_length, Rest ); _ -> need_more end.