-module(mist@internal@http2@handler). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([send_hpack_context/2, receive_hpack_context/2, append_data/2, upgrade/3, call/3]). -export_type([message/0, pending_send/0, state/0]). -type message() :: {send, mist@internal@http2@frame:stream_identifier(mist@internal@http2@frame:frame()), gleam@http@response:response(mist@internal@http:response_data())}. -type pending_send() :: pending_send. -type state() :: {state, gleam@option:option(mist@internal@http2@frame:frame()), mist@internal@buffer:buffer(), list(pending_send()), mist@internal@http2:hpack_context(), gleam@erlang@process:subject(message()), mist@internal@http2:hpack_context(), integer(), integer(), mist@internal@http2:http2_settings(), gleam@dict:dict(mist@internal@http2@frame:stream_identifier(mist@internal@http2@frame:frame()), mist@internal@http2@stream:state())}. -file("/home/alex/gleams/mist/src/mist/internal/http2/handler.gleam", 44). -spec send_hpack_context(state(), mist@internal@http2:hpack_context()) -> state(). send_hpack_context(State, Context) -> erlang:setelement(7, State, Context). -file("/home/alex/gleams/mist/src/mist/internal/http2/handler.gleam", 48). -spec receive_hpack_context(state(), mist@internal@http2:hpack_context()) -> state(). receive_hpack_context(State, Context) -> erlang:setelement(5, State, Context). -file("/home/alex/gleams/mist/src/mist/internal/http2/handler.gleam", 52). -spec append_data(state(), bitstring()) -> state(). append_data(State, Data) -> erlang:setelement( 3, State, mist@internal@buffer:append(erlang:element(3, State), Data) ). -file("/home/alex/gleams/mist/src/mist/internal/http2/handler.gleam", 56). -spec upgrade( bitstring(), mist@internal@http:connection(), gleam@erlang@process:subject(message()) ) -> {ok, state()} | {error, gleam@erlang@process:exit_reason()}. upgrade(_, Conn, _) -> _ = mist@internal@http2:default_settings(), Settings_frame = {settings, false, []}, _assert_subject = mist@internal@http2:send_frame( Settings_frame, erlang:element(3, Conn), erlang:element(4, Conn) ), {ok, _} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail, module => <<"mist/internal/http2/handler"/utf8>>, function => <<"upgrade"/utf8>>, line => 64}) end, logging:log(error, <<"HTTP/2 currently not supported"/utf8>>), {error, {abnormal, <<"HTTP/2 currently not supported"/utf8>>}}. -file("/home/alex/gleams/mist/src/mist/internal/http2/handler.gleam", 118). -spec handle_frame( mist@internal@http2@frame:frame(), state(), mist@internal@http:connection(), fun((gleam@http@request:request(mist@internal@http:connection())) -> gleam@http@response:response(mist@internal@http:response_data())) ) -> {ok, state()} | {error, gleam@erlang@process:exit_reason()}. handle_frame(Frame, State, Conn, Handler) -> case {erlang:element(2, State), Frame} of {{some, {header, {continued, Existing}, End_stream, Id1, Priority}}, {continuation, {complete, Data}, Id2}} when Id1 =:= Id2 -> Complete_frame = {header, {complete, <>}, End_stream, Id1, Priority}, handle_frame( Complete_frame, erlang:setelement(2, State, none), Conn, Handler ); {{some, {header, {continued, Existing@1}, End_stream@1, Id1@1, Priority@1}}, {continuation, {continued, Data@1}, Id2@1}} when Id1@1 =:= Id2@1 -> Next = {header, {continued, <>}, End_stream@1, Id1@1, Priority@1}, {ok, erlang:setelement(2, State, {some, Next})}; {none, {window_update, Amount, Identifier}} -> case mist@internal@http2@frame:get_stream_identifier(Identifier) of 0 -> {ok, erlang:setelement( 10, State, erlang:setelement( 5, erlang:element(10, State), Amount ) )}; _ -> _pipe = erlang:element(11, State), _pipe@1 = gleam_stdlib:map_get(_pipe, Identifier), _pipe@2 = gleam@result:replace_error( _pipe@1, {abnormal, <<"Window update for non-existent stream"/utf8>>} ), gleam@result:then( _pipe@2, fun(Stream) -> case mist@internal@http2@flow_control:update_send_window( erlang:element(6, Stream), Amount ) of {ok, Update} -> New_stream = erlang:setelement( 6, Stream, Update ), {ok, erlang:setelement( 11, State, gleam@dict:insert( erlang:element(11, State), Identifier, New_stream ) )}; _ -> {error, {abnormal, <<"Failed to update send window"/utf8>>}} end end ) end; {none, {header, {complete, Data@2}, End_stream@2, Identifier@1, _}} -> Conn@1 = {connection, {initial, <<>>}, erlang:element(3, Conn), erlang:element(4, Conn)}, _assert_subject = mist_ffi:hpack_decode( erlang:element(5, State), Data@2 ), {ok, {Headers, Context}} = case _assert_subject of {ok, {_, _}} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail, module => <<"mist/internal/http2/handler"/utf8>>, function => <<"handle_frame"/utf8>>, line => 213}) end, Pending_content_length = begin _pipe@3 = Headers, _pipe@4 = gleam@list:key_find( _pipe@3, <<"content-length"/utf8>> ), _pipe@5 = gleam@result:then( _pipe@4, fun gleam_stdlib:parse_int/1 ), gleam@option:from_result(_pipe@5) end, _assert_subject@1 = mist@internal@http2@stream:new( Handler, Headers, Conn@1, fun(Resp) -> gleam@erlang@process:send( erlang:element(6, State), {send, Identifier@1, Resp} ) end, End_stream@2 ), {ok, New_stream@1} = case _assert_subject@1 of {ok, _} -> _assert_subject@1; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail@1, module => <<"mist/internal/http2/handler"/utf8>>, function => <<"handle_frame"/utf8>>, line => 222}) end, gleam@erlang@process:send(New_stream@1, ready), Stream_state = {state, Identifier@1, open, New_stream@1, erlang:element(5, erlang:element(10, State)), erlang:element(5, erlang:element(10, State)), Pending_content_length}, Streams = gleam@dict:insert( erlang:element(11, State), Identifier@1, Stream_state ), {ok, erlang:setelement( 11, erlang:setelement(5, State, Context), Streams )}; {none, {data, Data@3, End_stream@3, Identifier@2}} -> Data_size = erlang:byte_size(Data@3), {Conn_receive_window_size, Conn_window_increment} = mist@internal@http2@flow_control:compute_receive_window( erlang:element(9, State), Data_size ), _pipe@6 = erlang:element(11, State), _pipe@7 = gleam_stdlib:map_get(_pipe@6, Identifier@2), _pipe@8 = gleam@result:map( _pipe@7, fun(_capture) -> mist@internal@http2@stream:receive_data(_capture, Data_size) end ), _pipe@9 = gleam@result:replace_error( _pipe@8, {abnormal, <<"Stream failed to receive data"/utf8>>} ), gleam@result:map( _pipe@9, fun(Update@1) -> {New_stream@2, Increment} = Update@1, _ = case Conn_window_increment > 0 of true -> mist@internal@http2:send_frame( {window_update, Conn_window_increment, mist@internal@http2@frame:stream_identifier( 0 )}, erlang:element(3, Conn), erlang:element(4, Conn) ); false -> {ok, nil} end, _ = case Increment > 0 of true -> mist@internal@http2:send_frame( {window_update, Increment, Identifier@2}, erlang:element(3, Conn), erlang:element(4, Conn) ); false -> {ok, nil} end, gleam@erlang@process:send( erlang:element(4, New_stream@2), {data, Data@3, End_stream@3} ), erlang:setelement( 9, erlang:setelement( 11, State, gleam@dict:insert( erlang:element(11, State), Identifier@2, New_stream@2 ) ), Conn_receive_window_size ) end ); {none, {priority, _, _, _, _}} -> {ok, State}; {none, {settings, true, _}} -> {ok, State}; {_, {settings, _, _}} -> _pipe@10 = mist@internal@http2:send_frame( mist@internal@http2@frame:settings_ack(), erlang:element(3, Conn), erlang:element(4, Conn) ), _pipe@11 = gleam@result:replace(_pipe@10, State), gleam@result:replace_error( _pipe@11, {abnormal, <<"Failed to respond to settings ACK"/utf8>>} ); {none, {go_away, _, _, _}} -> logging:log(debug, <<"byteeee~~"/utf8>>), {error, normal}; {_, Frame@1} -> logging:log( debug, <<"Ignoring frame: "/utf8, (gleam@erlang:format(Frame@1))/binary>> ), {ok, State} end. -file("/home/alex/gleams/mist/src/mist/internal/http2/handler.gleam", 91). -spec call( state(), mist@internal@http:connection(), fun((gleam@http@request:request(mist@internal@http:connection())) -> gleam@http@response:response(mist@internal@http:response_data())) ) -> {ok, state()} | {error, gleam@erlang@process:exit_reason()}. call(State, Conn, Handler) -> case mist@internal@http2@frame:decode( erlang:element(3, erlang:element(3, State)) ) of {ok, {Frame, Rest}} -> New_state = erlang:setelement( 3, State, mist@internal@buffer:new(Rest) ), case handle_frame(Frame, New_state, Conn, Handler) of {ok, Updated} -> call(Updated, Conn, Handler); {error, Reason} -> {error, Reason} end; {error, no_error} -> {ok, State}; {error, _} -> {ok, State} end.