Packages
mist
5.0.0-rc1
6.0.3
6.0.2
6.0.1
6.0.0
5.0.4
5.0.3
5.0.2
5.0.1
5.0.0
5.0.0-rc1
4.0.7
4.0.6
4.0.5
4.0.4
4.0.3
4.0.2
4.0.1
4.0.0
3.0.0
2.0.0
1.2.0
1.1.0
1.0.0
1.0.0-rc3
1.0.0-rc2
1.0.0-rc1
0.17.0
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.2
0.13.1
0.13.0
0.12.0
0.11.0
0.10.0
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.3
0.8.2
0.8.1
0.8.0
0.7.1
0.7.0
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.3
0.3.2
0.3.1
0.3.0
0.2.1
0.2.0
0.1.3
a misty Gleam web server
Current section
Files
Jump to
Current section
Files
src/mist@internal@http2@handler.erl
-module(mist@internal@http2@handler).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-define(FILEPATH, "src/mist/internal/http2/handler.gleam").
-export([send_hpack_context/2, receive_hpack_context/2, append_data/2, upgrade/3, call/3]).
-export_type([pending_send/0, state/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 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(mist@internal@http2@stream:send_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("src/mist/internal/http2/handler.gleam", 38).
?DOC(false).
-spec send_hpack_context(state(), mist@internal@http2:hpack_context()) -> state().
send_hpack_context(State, Context) ->
_record = State,
{state,
erlang:element(2, _record),
erlang:element(3, _record),
erlang:element(4, _record),
erlang:element(5, _record),
erlang:element(6, _record),
Context,
erlang:element(8, _record),
erlang:element(9, _record),
erlang:element(10, _record),
erlang:element(11, _record)}.
-file("src/mist/internal/http2/handler.gleam", 42).
?DOC(false).
-spec receive_hpack_context(state(), mist@internal@http2:hpack_context()) -> state().
receive_hpack_context(State, Context) ->
_record = State,
{state,
erlang:element(2, _record),
erlang:element(3, _record),
erlang:element(4, _record),
Context,
erlang:element(6, _record),
erlang:element(7, _record),
erlang:element(8, _record),
erlang:element(9, _record),
erlang:element(10, _record),
erlang:element(11, _record)}.
-file("src/mist/internal/http2/handler.gleam", 46).
?DOC(false).
-spec append_data(state(), bitstring()) -> state().
append_data(State, Data) ->
_record = State,
{state,
erlang:element(2, _record),
mist@internal@buffer:append(erlang:element(3, State), Data),
erlang:element(4, _record),
erlang:element(5, _record),
erlang:element(6, _record),
erlang:element(7, _record),
erlang:element(8, _record),
erlang:element(9, _record),
erlang:element(10, _record),
erlang:element(11, _record)}.
-file("src/mist/internal/http2/handler.gleam", 50).
?DOC(false).
-spec upgrade(
bitstring(),
mist@internal@http:connection(),
gleam@erlang@process:subject(mist@internal@http2@stream:send_message())
) -> {ok, state()} | {error, binary()}.
upgrade(Data, Conn, Self) ->
Initial_settings = mist@internal@http2:default_settings(),
Settings_frame = {settings, false, []},
Sent = begin
_pipe = mist@internal@http2:send_frame(
Settings_frame,
erlang:element(3, Conn),
erlang:element(4, Conn)
),
gleam@result:replace_error(
_pipe,
<<"Failed to send settings frame"/utf8>>
)
end,
gleam@result:map(
Sent,
fun(_) ->
{state,
none,
mist@internal@buffer:new(Data),
[],
hpack:new_context(erlang:element(2, Initial_settings)),
Self,
hpack:new_context(erlang:element(2, Initial_settings)),
65535,
65535,
Initial_settings,
maps:new()}
end
).
-file("src/mist/internal/http2/handler.gleam", 106).
?DOC(false).
-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, binary()}.
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, <<Existing/bitstring, Data/bitstring>>},
End_stream,
Id1,
Priority},
handle_frame(
Complete_frame,
begin
_record = State,
{state,
none,
erlang:element(3, _record),
erlang:element(4, _record),
erlang:element(5, _record),
erlang:element(6, _record),
erlang:element(7, _record),
erlang:element(8, _record),
erlang:element(9, _record),
erlang:element(10, _record),
erlang:element(11, _record)}
end,
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, <<Existing@1/bitstring, Data@1/bitstring>>},
End_stream@1,
Id1@1,
Priority@1},
{ok,
begin
_record@1 = State,
{state,
{some, Next},
erlang:element(3, _record@1),
erlang:element(4, _record@1),
erlang:element(5, _record@1),
erlang:element(6, _record@1),
erlang:element(7, _record@1),
erlang:element(8, _record@1),
erlang:element(9, _record@1),
erlang:element(10, _record@1),
erlang:element(11, _record@1)}
end};
{none, {window_update, Amount, Identifier}} ->
case mist@internal@http2@frame:get_stream_identifier(Identifier) of
0 ->
{ok,
begin
_record@2 = State,
{state,
erlang:element(2, _record@2),
erlang:element(3, _record@2),
erlang:element(4, _record@2),
erlang:element(5, _record@2),
erlang:element(6, _record@2),
erlang:element(7, _record@2),
erlang:element(8, _record@2),
erlang:element(9, _record@2),
begin
_record@3 = erlang:element(10, State),
{http2_settings,
erlang:element(2, _record@3),
erlang:element(3, _record@3),
erlang:element(4, _record@3),
Amount,
erlang:element(6, _record@3),
erlang:element(7, _record@3)}
end,
erlang:element(11, _record@2)}
end};
_ ->
_pipe = erlang:element(11, State),
_pipe@1 = gleam_stdlib:map_get(_pipe, Identifier),
_pipe@2 = gleam@result:replace_error(
_pipe@1,
<<"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 = begin
_record@4 = Stream,
{state,
erlang:element(2, _record@4),
erlang:element(3, _record@4),
erlang:element(4, _record@4),
erlang:element(5, _record@4),
Update,
erlang:element(7, _record@4)}
end,
{ok,
begin
_record@5 = State,
{state,
erlang:element(2, _record@5),
erlang:element(3, _record@5),
erlang:element(4, _record@5),
erlang:element(5, _record@5),
erlang:element(6, _record@5),
erlang:element(7, _record@5),
erlang:element(8, _record@5),
erlang:element(9, _record@5),
erlang:element(10, _record@5),
gleam@dict:insert(
erlang:element(11, State),
Identifier,
New_stream
)}
end};
_ ->
{error,
<<"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)},
{Headers@1, Context@1} = case mist_ffi:hpack_decode(
erlang:element(5, State),
Data@2
) of
{ok, {Headers, Context}} -> {Headers, Context};
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"mist/internal/http2/handler"/utf8>>,
function => <<"handle_frame"/utf8>>,
line => 199,
value => _assert_fail,
start => 5569,
'end' => 5667,
pattern_start => 5580,
pattern_end => 5603})
end,
Pending_content_length = begin
_pipe@3 = Headers@1,
_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,
New_stream@2 = case mist@internal@http2@stream:new(
Identifier@1,
Handler,
Headers@1,
Conn@1,
erlang:element(6, State),
End_stream@2
) of
{ok, New_stream@1} -> New_stream@1;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"mist/internal/http2/handler"/utf8>>,
function => <<"handle_frame"/utf8>>,
line => 208,
value => _assert_fail@1,
start => 5834,
'end' => 6087,
pattern_start => 5845,
pattern_end => 5859})
end,
gleam@erlang@process:send(erlang:element(3, New_stream@2), ready),
Stream_state = {state,
Identifier@1,
open,
erlang:element(3, New_stream@2),
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,
begin
_record@6 = State,
{state,
erlang:element(2, _record@6),
erlang:element(3, _record@6),
erlang:element(4, _record@6),
Context@1,
erlang:element(6, _record@6),
erlang:element(7, _record@6),
erlang:element(8, _record@6),
erlang:element(9, _record@6),
erlang:element(10, _record@6),
Streams}
end};
{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,
<<"Stream failed to receive data"/utf8>>
),
gleam@result:map(
_pipe@9,
fun(Update@1) ->
{New_stream@3, 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@3),
{data, Data@3, End_stream@3}
),
_record@7 = State,
{state,
erlang:element(2, _record@7),
erlang:element(3, _record@7),
erlang:element(4, _record@7),
erlang:element(5, _record@7),
erlang:element(6, _record@7),
erlang:element(7, _record@7),
erlang:element(8, _record@7),
Conn_receive_window_size,
erlang:element(10, _record@7),
gleam@dict:insert(
erlang:element(11, State),
Identifier@2,
New_stream@3
)}
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,
<<"Failed to respond to settings ACK"/utf8>>
);
{none, {go_away, _, _, _}} ->
logging:log(debug, <<"byteeee~~"/utf8>>),
{error, <<"Going away..."/utf8>>};
{_, Frame@1} ->
logging:log(
debug,
<<"Ignoring frame: "/utf8,
(gleam@string:inspect(Frame@1))/binary>>
),
{ok, State}
end.
-file("src/mist/internal/http2/handler.gleam", 81).
?DOC(false).
-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, {ok, nil} | {error, binary()}}.
call(State, Conn, Handler) ->
case mist@internal@http2@frame:decode(
erlang:element(3, erlang:element(3, State))
) of
{ok, {Frame, Rest}} ->
New_state = begin
_record = State,
{state,
erlang:element(2, _record),
mist@internal@buffer:new(Rest),
erlang:element(4, _record),
erlang:element(5, _record),
erlang:element(6, _record),
erlang:element(7, _record),
erlang:element(8, _record),
erlang:element(9, _record),
erlang:element(10, _record),
erlang:element(11, _record)}
end,
case handle_frame(Frame, New_state, Conn, Handler) of
{ok, Updated} ->
call(Updated, Conn, Handler);
{error, Reason} ->
{error, {error, Reason}}
end;
{error, no_error} ->
{ok, State};
{error, _} ->
{ok, State}
end.