Packages
🐑 a fluffy Gleam web server
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
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/4]).
-export_type([glisten_message/0, glisten_state/0, next/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 glisten_message() :: idle_timeout.
-type glisten_state() :: {glisten_state,
gleam@option:option(gleam@erlang@process:timer()),
gleam@erlang@process:subject(glisten_message())}.
-type next() :: {continue, glisten_state()} | stop.
-file("src/ewe/internal/handler.gleam", 64).
?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", 191).
?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 => 198,
value => _assert_fail,
start => 5885,
'end' => 5945,
pattern_start => 5896,
pattern_end => 5921})
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 = ewe@internal@http:append_default_headers(
Resp@1,
Req,
Http_version@1
),
_pipe@1 = ewe@internal@encoder:setup_encoded_response(_pipe),
_pipe@2 = glisten@transport:send(
erlang:element(2, erlang:element(4, Req)),
erlang:element(3, erlang:element(4, Req)),
_pipe@1
),
gleam@result:'try'(
_pipe@2,
fun(_) ->
_pipe@3 = 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@3, badarg)
end
)
end,
_ = ewe_ffi:close_file(Descriptor),
Sent.
-file("src/ewe/internal/handler.gleam", 273).
?DOC(false).
-spec encode_gzip(
gleam@http@request:request(ewe@internal@http:connection()),
gleam@http@response:response(any())
) -> boolean().
encode_gzip(Req, Resp) ->
Req@1 = begin
_pipe = gleam@http@request:get_header(Req, <<"accept-encoding"/utf8>>),
gleam@result:map(
_pipe,
fun(_capture) ->
gleam_stdlib:contains_string(_capture, <<"gzip"/utf8>>)
end
)
end,
Resp@1 = gleam@http@response:get_header(Resp, <<"content-encoding"/utf8>>),
case {Req@1, Resp@1} of
{{ok, true}, {error, nil}} ->
true;
{_, _} ->
false
end.
-file("src/ewe/internal/handler.gleam", 286).
?DOC(false).
-spec remove_charset(gleam@http@response:response(MBE)) -> gleam@http@response:response(MBE).
remove_charset(Resp) ->
_pipe = gleam@http@response:get_header(Resp, <<"content-type"/utf8>>),
_pipe@1 = gleam@result:'try'(
_pipe,
fun(_capture) -> gleam@string:split_once(_capture, <<";"/utf8>>) end
),
_pipe@2 = gleam@result:map(
_pipe@1,
fun(Parts) ->
gleam@http@response:set_header(
Resp,
<<"content-type"/utf8>>,
erlang:element(1, Parts)
)
end
),
gleam@result:unwrap(_pipe@2, Resp).
-file("src/ewe/internal/handler.gleam", 221).
?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 => 226,
value => _assert_fail,
start => 6704,
'end' => 6764,
pattern_start => 6715,
pattern_end => 6740})
end,
Bits@1 = case Body of
{text_data, Text} ->
gleam_stdlib:identity(Text);
{string_tree_data, String_tree} ->
_pipe = unicode:characters_to_binary(String_tree),
gleam_stdlib:identity(_pipe);
{bits_data, Bits} ->
Bits;
{bytes_data, Bytes} ->
erlang:list_to_bitstring(Bytes);
empty ->
<<>>;
_ ->
erlang:error(#{gleam_error => panic,
message => <<"`panic` expression evaluated."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"ewe/internal/handler"/utf8>>,
function => <<"handle_resp_body"/utf8>>,
line => 235})
end,
Content_length = erlang:byte_size(Bits@1),
Resp@1 = case Content_length > 1024 of
true ->
case encode_gzip(Req, Resp) of
true ->
Compressed = compresso:gzip(Bits@1),
Content_length@1 = erlang:byte_size(Compressed),
_pipe@1 = remove_charset(Resp),
_pipe@2 = gleam@http@response:set_header(
_pipe@1,
<<"content-encoding"/utf8>>,
<<"gzip"/utf8>>
),
_pipe@3 = gleam@http@response:set_header(
_pipe@2,
<<"vary"/utf8>>,
<<"Accept-Encoding"/utf8>>
),
_pipe@4 = gleam@http@response:set_header(
_pipe@3,
<<"content-length"/utf8>>,
erlang:integer_to_binary(Content_length@1)
),
gleam@http@response:set_body(_pipe@4, Compressed);
_ ->
_pipe@5 = gleam@http@response:set_body(Resp, Bits@1),
gleam@http@response:set_header(
_pipe@5,
<<"content-length"/utf8>>,
erlang:integer_to_binary(Content_length)
)
end;
false ->
_pipe@6 = gleam@http@response:set_body(Resp, Bits@1),
gleam@http@response:set_header(
_pipe@6,
<<"content-length"/utf8>>,
erlang:integer_to_binary(Content_length)
)
end,
_pipe@7 = ewe@internal@http:append_default_headers(
Resp@1,
Req,
Http_version@1
),
_pipe@8 = ewe@internal@encoder:encode_response(_pipe@7),
glisten@transport:send(
erlang:element(2, erlang:element(4, Req)),
erlang:element(3, erlang:element(4, Req)),
_pipe@8
).
-file("src/ewe/internal/handler.gleam", 293).
?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", 141).
?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@1 = case ewe_ffi:rescue(fun() -> Handler(Req) end) of
{ok, Resp} ->
Resp;
{error, E} ->
logging:log(error, gleam@string:inspect(E)),
gleam@http@response:set_header(
On_crash,
<<"connection"/utf8>>,
<<"close"/utf8>>
)
end,
case erlang:element(4, Resp@1) of
websocket ->
gleam_erlang_ffi:sleep(1000),
stop;
s_s_e ->
gleam_erlang_ffi:sleep(1000),
stop;
chunked ->
gleam_erlang_ffi:sleep(1000),
stop;
{file, Descriptor, Offset, Size} ->
Sent = handle_resp_file(Req, Resp@1, Descriptor, Offset, Size),
case {Sent, is_connection_close(Resp@1)} of
{{ok, nil}, false} ->
Timer = gleam@erlang@process:send_after(
Subject,
Idle_timeout,
idle_timeout
),
{continue, {glisten_state, {some, Timer}, Subject}};
{_, _} ->
stop
end;
_ ->
Sent@1 = handle_resp_body(Req, Resp@1, erlang:element(4, Resp@1)),
case {Sent@1, is_connection_close(Resp@1)} of
{{ok, nil}, false} ->
Timer@1 = gleam@erlang@process:send_after(
Subject,
Idle_timeout,
idle_timeout
),
{continue, {glisten_state, {some, Timer@1}, Subject}};
{_, _} ->
stop
end
end.
-file("src/ewe/internal/handler.gleam", 74).
?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()),
gleam@erlang@process:name(gleam@otp@factory_supervisor:message(fun(() -> {ok,
gleam@otp@actor:started(nil)} |
{error, gleam@otp@actor:start_error()}), nil)),
integer()
) -> fun((glisten_state(), glisten:message(glisten_message()), glisten:connection(glisten_message())) -> glisten:next(glisten_state(), glisten:message(glisten_message()))).
loop(Handler, On_crash, Factory_name, 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,
Factory_name
),
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,
logging:log(
error,
<<"Received invalid request: "/utf8,
(gleam@string:inspect(Reason))/binary>>
),
_ = begin
_pipe = gleam@http@response:new(Status),
_pipe@1 = gleam@http@response:set_body(_pipe, <<>>),
_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.