Current section

Files

Jump to
ewe src ewe@internal@handler.erl
Raw

src/ewe@internal@handler.erl

-module(ewe@internal@handler).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/ewe/internal/handler.gleam").
-export([init/1, loop/3]).
-export_type([next/0, glisten_message/0, glisten_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 next() :: {continue, glisten_state()} | stop.
-type glisten_message() :: idle_timeout.
-type glisten_state() :: {glisten_state,
gleam@option:option(gleam@erlang@process:timer()),
gleam@erlang@process:subject(glisten_message())}.
-file("src/ewe/internal/handler.gleam", 52).
?DOC(false).
-spec init(any()) -> {glisten_state(),
gleam@option:option(gleam@erlang@process:selector(glisten_message()))}.
init(_) ->
Subject = gleam@erlang@process:new_subject(),
Selector = begin
_pipe = gleam_erlang_ffi:new_selector(),
gleam@erlang@process:select(_pipe, Subject)
end,
{{glisten_state, none, Subject}, {some, Selector}}.
-file("src/ewe/internal/handler.gleam", 162).
?DOC(false).
-spec handle_resp_file(
gleam@http@request:request(ewe@internal@http:connection()),
gleam@http@response:response(ewe@internal@http:response_body()),
ewe@internal@file:io_device(),
integer(),
integer()
) -> {ok, nil} | {error, glisten@socket:socket_reason()}.
handle_resp_file(Req, Resp, Descriptor, Offset, Size) ->
Http_version@1 = case erlang:element(5, erlang:element(4, Req)) of
{some, Http_version} -> Http_version;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"ewe/internal/handler"/utf8>>,
function => <<"handle_resp_file"/utf8>>,
line => 169,
value => _assert_fail,
start => 5024,
'end' => 5084,
pattern_start => 5035,
pattern_end => 5060})
end,
Resp@1 = case gleam@http@response:get_header(
Resp,
<<"content-length"/utf8>>
) of
{ok, _} ->
Resp;
{error, nil} ->
gleam@http@response:set_header(
Resp,
<<"content-length"/utf8>>,
erlang:integer_to_binary(Size)
)
end,
Sent = begin
_pipe = gleam@http@response:set_body(Resp@1, gleam@bytes_tree:new()),
_pipe@1 = ewe@internal@http:append_default_headers(
_pipe,
Req,
Http_version@1
),
_pipe@2 = ewe@internal@encoder:setup_encoded_response(_pipe@1),
_pipe@3 = glisten@transport:send(
erlang:element(2, erlang:element(4, Req)),
erlang:element(3, erlang:element(4, Req)),
_pipe@2
),
gleam@result:'try'(
_pipe@3,
fun(_) ->
_pipe@4 = ewe@internal@file:send(
erlang:element(2, erlang:element(4, Req)),
erlang:element(3, erlang:element(4, Req)),
Descriptor,
Offset,
Size
),
gleam@result:replace_error(_pipe@4, badarg)
end
)
end,
_ = ewe_ffi:close_file(Descriptor),
Sent.
-file("src/ewe/internal/handler.gleam", 231).
?DOC(false).
-spec handle_resp_body(
gleam@http@request:request(ewe@internal@http:connection()),
gleam@http@response:response(ewe@internal@http:response_body()),
ewe@internal@http:response_body()
) -> {ok, nil} | {error, glisten@socket:socket_reason()}.
handle_resp_body(Req, Resp, Body) ->
Http_version@1 = case erlang:element(5, erlang:element(4, Req)) of
{some, Http_version} -> Http_version;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"ewe/internal/handler"/utf8>>,
function => <<"handle_resp_body"/utf8>>,
line => 236,
value => _assert_fail,
start => 7111,
'end' => 7171,
pattern_start => 7122,
pattern_end => 7147})
end,
Bytes@1 = case Body of
{text_data, Text} ->
gleam_stdlib:wrap_list(Text);
{string_tree_data, String_tree} ->
gleam_stdlib:wrap_list(String_tree);
{bits_data, Bits} ->
gleam@bytes_tree:from_bit_array(Bits);
{bytes_data, Bytes} ->
Bytes;
empty ->
gleam@bytes_tree:new();
_ ->
erlang:error(#{gleam_error => panic,
message => <<"`panic` expression evaluated."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"ewe/internal/handler"/utf8>>,
function => <<"handle_resp_body"/utf8>>,
line => 244})
end,
_pipe = gleam@http@response:set_body(Resp, Bytes@1),
_pipe@1 = ewe@internal@http:append_default_headers(
_pipe,
Req,
Http_version@1
),
_pipe@2 = ewe@internal@encoder:encode_response(_pipe@1),
glisten@transport:send(
erlang:element(2, erlang:element(4, Req)),
erlang:element(3, erlang:element(4, Req)),
_pipe@2
).
-file("src/ewe/internal/handler.gleam", 253).
?DOC(false).
-spec is_connection_close(gleam@http@response:response(any())) -> boolean().
is_connection_close(Resp) ->
case gleam@http@response:get_header(Resp, <<"connection"/utf8>>) of
{ok, <<"close"/utf8>>} ->
true;
_ ->
false
end.
-file("src/ewe/internal/handler.gleam", 260).
?DOC(false).
-spec to_hex_string(integer()) -> binary().
to_hex_string(Integer) ->
erlang:integer_to_list(Integer, 16).
-file("src/ewe/internal/handler.gleam", 193).
?DOC(false).
-spec handle_resp_chunked(
gleam@http@request:request(ewe@internal@http:connection()),
gleam@http@response:response(ewe@internal@http:response_body()),
gleam@yielder:yielder(bitstring())
) -> {ok, nil} | {error, glisten@socket:socket_reason()}.
handle_resp_chunked(Req, Resp, Yielder) ->
Http_version@1 = case erlang:element(5, erlang:element(4, Req)) of
{some, Http_version} -> Http_version;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"ewe/internal/handler"/utf8>>,
function => <<"handle_resp_chunked"/utf8>>,
line => 198,
value => _assert_fail,
start => 5902,
'end' => 5962,
pattern_start => 5913,
pattern_end => 5938})
end,
Resp@1 = case gleam@http@response:get_header(
Resp,
<<"transfer-encoding"/utf8>>
) of
{ok, <<"chunked"/utf8>>} ->
Resp;
{ok, _} ->
Resp;
{error, _} ->
gleam@http@response:set_header(
Resp,
<<"transfer-encoding"/utf8>>,
<<"chunked"/utf8>>
)
end,
_pipe = gleam@http@response:set_body(Resp@1, gleam@bytes_tree:new()),
_pipe@1 = ewe@internal@http:append_default_headers(
_pipe,
Req,
Http_version@1
),
_pipe@2 = ewe@internal@encoder:setup_encoded_response(_pipe@1),
_pipe@3 = glisten@transport:send(
erlang:element(2, erlang:element(4, Req)),
erlang:element(3, erlang:element(4, Req)),
_pipe@2
),
gleam@result:'try'(
_pipe@3,
fun(_) ->
_pipe@9 = gleam@yielder:try_fold(
Yielder,
nil,
fun(_, Chunk) -> _pipe@4 = gleam@bytes_tree:new(),
_pipe@5 = gleam@bytes_tree:append_string(
_pipe@4,
to_hex_string(erlang:byte_size(Chunk))
),
_pipe@6 = gleam@bytes_tree:append(_pipe@5, <<"\r\n"/utf8>>),
_pipe@7 = gleam@bytes_tree:append(_pipe@6, Chunk),
_pipe@8 = gleam@bytes_tree:append(_pipe@7, <<"\r\n"/utf8>>),
glisten@transport:send(
erlang:element(2, erlang:element(4, Req)),
erlang:element(3, erlang:element(4, Req)),
_pipe@8
) end
),
gleam@result:'try'(
_pipe@9,
fun(_) ->
glisten@transport:send(
erlang:element(2, erlang:element(4, Req)),
erlang:element(3, erlang:element(4, Req)),
gleam@bytes_tree:from_bit_array(<<"0\r\n\r\n"/utf8>>)
)
end
)
end
).
-file("src/ewe/internal/handler.gleam", 119).
?DOC(false).
-spec call_handler(
gleam@http@request:request(ewe@internal@http:connection()),
gleam@erlang@process:subject(glisten_message()),
fun((gleam@http@request:request(ewe@internal@http:connection())) -> gleam@http@response:response(ewe@internal@http:response_body())),
gleam@http@response:response(ewe@internal@http:response_body()),
integer()
) -> next().
call_handler(Req, Subject, Handler, On_crash, Idle_timeout) ->
Resp = begin
_pipe = ewe_ffi:rescue(fun() -> Handler(Req) end),
_pipe@2 = gleam@result:map_error(_pipe, fun(_) -> _pipe@1 = On_crash,
gleam@http@response:set_header(
_pipe@1,
<<"connection"/utf8>>,
<<"close"/utf8>>
) end),
gleam@result:unwrap_both(_pipe@2)
end,
case Resp of
{response, _, _, {websocket, Selector}} ->
_ = gleam_erlang_ffi:select(Selector),
stop;
{response, _, _, {s_s_e, Selector}} ->
_ = gleam_erlang_ffi:select(Selector),
stop;
{response, _, _, Body} ->
Sent = case Body of
{file, Descriptor, Offset, Size} ->
handle_resp_file(Req, Resp, Descriptor, Offset, Size);
{chunked_data, Yielder} ->
handle_resp_chunked(Req, Resp, Yielder);
_ ->
handle_resp_body(Req, Resp, Body)
end,
case {Sent, is_connection_close(Resp)} of
{{ok, nil}, false} ->
Timer = gleam@erlang@process:send_after(
Subject,
Idle_timeout,
idle_timeout
),
{continue, {glisten_state, {some, Timer}, Subject}};
{_, _} ->
stop
end
end.
-file("src/ewe/internal/handler.gleam", 62).
?DOC(false).
-spec loop(
fun((gleam@http@request:request(ewe@internal@http:connection())) -> gleam@http@response:response(ewe@internal@http:response_body())),
gleam@http@response:response(ewe@internal@http:response_body()),
integer()
) -> fun((glisten_state(), glisten:message(glisten_message()), glisten:connection(glisten_message())) -> glisten:next(glisten_state(), glisten:message(glisten_message()))).
loop(Handler, On_crash, Idle_timeout) ->
fun(State, Msg, Conn) -> case Msg of
{user, idle_timeout} ->
glisten:stop();
{packet, Msg@1} ->
case erlang:element(2, State) of
{some, Timer} ->
gleam@erlang@process:cancel_timer(Timer);
none ->
timer_not_found
end,
Http_conn = ewe@internal@http:transform_connection(Conn),
Parsed = ewe@internal@http:parse_request(
Http_conn,
ewe@internal@buffer:new(Msg@1)
),
case Parsed of
{ok, Req} ->
case call_handler(
Req,
erlang:element(3, State),
Handler,
On_crash,
Idle_timeout
) of
{continue, New_state} ->
glisten:continue(New_state);
stop ->
glisten:stop()
end;
{error, Reason} ->
Status = case Reason of
invalid_version ->
505;
_ ->
400
end,
_ = begin
_pipe = gleam@http@response:new(Status),
_pipe@1 = gleam@http@response:set_body(
_pipe,
gleam@bytes_tree:new()
),
_pipe@2 = gleam@http@response:set_header(
_pipe@1,
<<"connection"/utf8>>,
<<"close"/utf8>>
),
_pipe@3 = ewe@internal@encoder:encode_response(
_pipe@2
),
glisten@transport:send(
erlang:element(2, Http_conn),
erlang:element(3, Http_conn),
_pipe@3
)
end,
glisten:stop()
end
end end.