Packages
mist
0.9.2
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@handler.erl
-module(mist@handler).
-compile(no_auto_import).
-export([new_state/0, with_func/1, with/3]).
-export_type([handler_response/0, handler_error/0, state/0]).
-type handler_response() :: {response,
gleam@http@response:response(mist@http:http_response_body())} |
{upgrade, mist@websocket:websocket_handler()}.
-type handler_error() :: {invalid_request, mist@http:decode_error()} | not_found.
-type state() :: {state,
gleam@option:option(gleam@erlang@process:timer()),
gleam@option:option(mist@websocket:websocket_handler())}.
-spec new_state() -> state().
new_state() ->
{state, none, none}.
-spec with_func(
fun((gleam@http@request:request(mist@http:body())) -> handler_response())
) -> fun((glisten@handler:handler_message(), glisten@handler:loop_state(state())) -> gleam@otp@actor:next(glisten@handler:loop_state(state()))).
with_func(Handler) ->
glisten@handler:func(
fun(Msg, Socket_state) ->
{loop_state, Socket, _@1, Transport, State} = Socket_state,
case erlang:element(3, State) of
{some, Ws_handler} ->
handle_websocket_message(Socket_state, Ws_handler, Msg);
none ->
_pipe@7 = begin
_@3 = case erlang:element(2, State) of
{some, T} ->
gleam@erlang@process:cancel_timer(T);
_@2 ->
timer_not_found
end,
_pipe = Msg,
_pipe@1 = mist@http:parse_request(
_pipe,
Socket,
Transport
),
_pipe@2 = gleam@result:map_error(
_pipe@1,
fun(Err) -> case Err of
discard_packet ->
nil;
_@4 ->
mist@logger:error(Err),
(erlang:element(4, Transport))(Socket),
nil
end end
),
_pipe@3 = gleam@result:replace_error(
_pipe@2,
{stop, normal}
),
_pipe@6 = gleam@result:then(
_pipe@3,
fun(Req) ->
_pipe@4 = gleam_erlang_ffi:rescue(
fun() -> Handler(Req) end
),
_pipe@5 = gleam@result:map(
_pipe@4,
fun(Resp) -> {Req, Resp} end
),
gleam@result:map_error(
_pipe@5,
fun(_capture) ->
log_and_error(
_capture,
erlang:element(2, Socket_state),
erlang:element(4, Socket_state)
)
end
)
end
),
gleam@result:map(
_pipe@6,
fun(Req_resp) ->
{Req@1, Response} = Req_resp,
case Response of
{response,
{response,
_@5,
_@6,
{bit_builder_body, Body}} = Resp@1} ->
handle_bit_builder_body(
Resp@1,
Body,
Socket_state
);
{response,
{response,
_@7,
_@8,
{file_body, _@9, _@10, _@11, _@12}} = Resp@2} ->
handle_file_body(Resp@2, Socket_state);
{upgrade, With_handler} ->
handle_upgrade(
Req@1,
With_handler,
Socket_state
)
end
end
)
end,
gleam@result:unwrap_both(_pipe@7)
end
end
).
-spec handle_websocket_message(
glisten@handler:loop_state(state()),
mist@websocket:websocket_handler(),
bitstring()
) -> gleam@otp@actor:next(glisten@handler:loop_state(state())).
handle_websocket_message(State, Handler, Msg) ->
case mist@websocket:frame_from_message(
erlang:element(2, State),
erlang:element(4, State),
Msg
) of
{ok, {ping_frame, _@1, _@2}} ->
{ok, _@4} = case (erlang:element(10, erlang:element(4, State)))(
erlang:element(2, State),
mist@websocket:frame_to_bit_builder({pong_frame, 0, <<>>})
) of
{ok, _@3} -> {ok, _@3};
_try ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _try,
module => <<"mist/handler"/utf8>>,
function => <<"handle_websocket_message"/utf8>>,
line => 114})
end,
{continue, State};
{ok, {close_frame, _@5, _@6} = Frame} ->
{ok, _@8} = case (erlang:element(10, erlang:element(4, State)))(
erlang:element(2, State),
mist@websocket:frame_to_bit_builder(Frame)
) of
{ok, _@7} -> {ok, _@7};
_try@1 ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _try@1,
module => <<"mist/handler"/utf8>>,
function => <<"handle_websocket_message"/utf8>>,
line => 122})
end,
_@10 = case erlang:element(2, Handler) of
{some, Func} ->
Func(erlang:element(3, State));
_@9 ->
nil
end,
{stop, normal};
{ok, {pong_frame, _@11, _@12}} ->
{stop, normal};
{ok, Frame@1} ->
_pipe = case Frame@1 of
{text_frame, _@13, Payload} ->
{ok, Msg@2} = case gleam@bit_string:to_string(Payload) of
{ok, Msg@1} -> {ok, Msg@1};
_try@2 ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _try@2,
module => <<"mist/handler"/utf8>>,
function => <<"handle_websocket_message"/utf8>>,
line => 137})
end,
{text_message, Msg@2};
_@14 ->
{binary_message, erlang:element(3, Frame@1)}
end,
_pipe@1 = (fun(Ws_msg) ->
gleam_erlang_ffi:rescue(
fun() ->
(erlang:element(4, Handler))(
Ws_msg,
erlang:element(3, State)
)
end
)
end)(_pipe),
_pipe@2 = gleam@result:replace(_pipe@1, {continue, State}),
_pipe@3 = gleam@result:map_error(
_pipe@2,
fun(Err) ->
mist@logger:error(Err),
_@16 = case erlang:element(2, Handler) of
{some, Func@1} ->
Func@1(erlang:element(3, State));
_@15 ->
nil
end,
Err
end
),
_pipe@4 = gleam@result:replace_error(_pipe@3, {stop, normal}),
gleam@result:unwrap_both(_pipe@4);
{error, _@17} ->
_@19 = case erlang:element(2, Handler) of
{some, Func@2} ->
Func@2(erlang:element(3, State));
_@18 ->
nil
end,
{stop, normal}
end.
-spec log_and_error(
gleam@erlang:crash(),
glisten@socket:socket(),
glisten@socket@transport:transport()
) -> gleam@otp@actor:next(glisten@handler:loop_state(state())).
log_and_error(Error, Socket, Transport) ->
case Error of
{exited, Msg} ->
mist@logger:error(Error),
_pipe = gleam@http@response:new(500),
_pipe@1 = gleam@http@response:set_body(
_pipe,
gleam@bit_builder:from_bit_string(
<<"Internal Server Error"/utf8>>
)
),
_pipe@2 = gleam@http@response:prepend_header(
_pipe@1,
<<"content-length"/utf8>>,
<<"21"/utf8>>
),
_pipe@3 = mist@encoder:to_bit_builder(_pipe@2),
(erlang:element(10, Transport))(Socket, _pipe@3),
(erlang:element(4, Transport))(Socket),
{stop, {abnormal, gleam@dynamic:unsafe_coerce(Msg)}};
{thrown, Msg} ->
mist@logger:error(Error),
_pipe = gleam@http@response:new(500),
_pipe@1 = gleam@http@response:set_body(
_pipe,
gleam@bit_builder:from_bit_string(
<<"Internal Server Error"/utf8>>
)
),
_pipe@2 = gleam@http@response:prepend_header(
_pipe@1,
<<"content-length"/utf8>>,
<<"21"/utf8>>
),
_pipe@3 = mist@encoder:to_bit_builder(_pipe@2),
(erlang:element(10, Transport))(Socket, _pipe@3),
(erlang:element(4, Transport))(Socket),
{stop, {abnormal, gleam@dynamic:unsafe_coerce(Msg)}};
{errored, Msg} ->
mist@logger:error(Error),
_pipe = gleam@http@response:new(500),
_pipe@1 = gleam@http@response:set_body(
_pipe,
gleam@bit_builder:from_bit_string(
<<"Internal Server Error"/utf8>>
)
),
_pipe@2 = gleam@http@response:prepend_header(
_pipe@1,
<<"content-length"/utf8>>,
<<"21"/utf8>>
),
_pipe@3 = mist@encoder:to_bit_builder(_pipe@2),
(erlang:element(10, Transport))(Socket, _pipe@3),
(erlang:element(4, Transport))(Socket),
{stop, {abnormal, gleam@dynamic:unsafe_coerce(Msg)}}
end.
-spec handle_bit_builder_body(
gleam@http@response:response(mist@http:http_response_body()),
gleam@bit_builder:bit_builder(),
glisten@handler:loop_state(state())
) -> gleam@otp@actor:next(glisten@handler:loop_state(state())).
handle_bit_builder_body(Resp, Body, State) ->
_pipe = Resp,
_pipe@1 = gleam@http@response:set_body(_pipe, Body),
_pipe@2 = mist@encoder:to_bit_builder(_pipe@1),
_pipe@3 = (erlang:element(10, erlang:element(4, State)))(
erlang:element(2, State),
_pipe@2
),
_pipe@4 = gleam@result:map(
_pipe@3,
fun(_) ->
case gleam@http@response:get_header(Resp, <<"connection"/utf8>>) of
{ok, <<"close"/utf8>>} ->
(erlang:element(4, erlang:element(4, State)))(
erlang:element(2, State)
),
{stop, normal};
_@1 ->
Timer = gleam@erlang@process:send_after(
erlang:element(3, State),
10000,
close
),
{continue,
erlang:setelement(
5,
State,
erlang:setelement(
2,
erlang:element(5, State),
{some, Timer}
)
)}
end
end
),
_pipe@5 = gleam@result:replace_error(_pipe@4, {stop, normal}),
gleam@result:unwrap_both(_pipe@5).
-spec handle_file_body(
gleam@http@response:response(mist@http:http_response_body()),
glisten@handler:loop_state(state())
) -> gleam@otp@actor:next(glisten@handler:loop_state(state())).
handle_file_body(Resp, State) ->
{file_body, File_descriptor@1, Content_type@1, Offset@1, Length@1} = case erlang:element(
4,
Resp
) of
{file_body, File_descriptor, Content_type, Offset, Length} -> {file_body,
File_descriptor,
Content_type,
Offset,
Length};
_try ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _try,
module => <<"mist/handler"/utf8>>,
function => <<"handle_file_body"/utf8>>,
line => 222})
end,
_pipe = Resp,
_pipe@1 = gleam@http@response:prepend_header(
_pipe,
<<"content-length"/utf8>>,
gleam@int:to_string(Length@1 - Offset@1)
),
_pipe@2 = gleam@http@response:prepend_header(
_pipe@1,
<<"content-type"/utf8>>,
Content_type@1
),
_pipe@3 = gleam@http@response:set_body(_pipe@2, gleam@bit_builder:new()),
_pipe@4 = (fun(R) ->
mist@encoder:response_builder(
erlang:element(2, Resp),
erlang:element(3, R)
)
end)(_pipe@3),
_pipe@5 = (erlang:element(10, erlang:element(4, State)))(
erlang:element(2, State),
_pipe@4
),
_pipe@6 = gleam@result:map(
_pipe@5,
fun(_) ->
mist@file:sendfile(
File_descriptor@1,
erlang:element(2, State),
Offset@1,
Length@1,
[]
)
end
),
_pipe@7 = gleam@result:replace(_pipe@6, {continue, State}),
_pipe@8 = gleam@result:replace_error(_pipe@7, {stop, normal}),
gleam@result:unwrap_both(_pipe@8).
-spec handle_upgrade(
gleam@http@request:request(mist@http:body()),
mist@websocket:websocket_handler(),
glisten@handler:loop_state(state())
) -> gleam@otp@actor:next(glisten@handler:loop_state(state())).
handle_upgrade(Req, Handler, State) ->
_pipe = Req,
_pipe@1 = mist@http:upgrade(
erlang:element(2, State),
erlang:element(4, State),
_pipe
),
_pipe@2 = gleam@result:map(
_pipe@1,
fun(_) -> _@2 = case erlang:element(3, Handler) of
{some, Func} ->
Func(erlang:element(3, State));
_@1 ->
nil
end end
),
_pipe@3 = gleam@result:replace(
_pipe@2,
{continue,
erlang:setelement(
5,
State,
erlang:setelement(3, erlang:element(5, State), {some, Handler})
)}
),
_pipe@4 = gleam@result:replace_error(_pipe@3, {stop, normal}),
gleam@result:unwrap_both(_pipe@4).
-spec with(
fun((gleam@http@request:request(bitstring())) -> gleam@http@response:response(gleam@bit_builder:bit_builder())),
glisten@socket@transport:transport(),
integer()
) -> fun((glisten@handler:handler_message(), glisten@handler:loop_state(state())) -> gleam@otp@actor:next(glisten@handler:loop_state(state()))).
with(Handler, Transport, Max_body_limit) ->
Bad_request = begin
_pipe = gleam@http@response:new(400),
gleam@http@response:set_body(_pipe, gleam@bit_builder:new())
end,
with_func(
fun(Req) ->
_pipe@12 = case {gleam@http@request:get_header(
Req,
<<"content-length"/utf8>>
),
gleam@http@request:get_header(
Req,
<<"transfer-encoding"/utf8>>
)} of
{{ok, <<"0"/utf8>>}, _@1} ->
_pipe@1 = Req,
_pipe@2 = gleam@http@request:set_body(_pipe@1, <<>>),
Handler(_pipe@2);
{{error, nil}, {error, nil}} ->
_pipe@1 = Req,
_pipe@2 = gleam@http@request:set_body(_pipe@1, <<>>),
Handler(_pipe@2);
{_@1, {ok, <<"chunked"/utf8>>}} ->
_pipe@1 = Req,
_pipe@2 = mist@http:read_body(_pipe@1, Transport),
_pipe@3 = gleam@result:map(_pipe@2, Handler),
gleam@result:unwrap(_pipe@3, Bad_request);
{{ok, Size}, _@2} ->
_pipe@4 = Size,
_pipe@5 = gleam@int:parse(_pipe@4),
_pipe@11 = gleam@result:map(
_pipe@5,
fun(Size@1) -> case Size@1 > Max_body_limit of
true ->
_pipe@6 = gleam@http@response:new(413),
_pipe@7 = gleam@http@response:set_body(
_pipe@6,
gleam@bit_builder:new()
),
gleam@http@response:prepend_header(
_pipe@7,
<<"connection"/utf8>>,
<<"close"/utf8>>
);
false ->
_pipe@8 = Req,
_pipe@9 = mist@http:read_body(
_pipe@8,
Transport
),
_pipe@10 = gleam@result:map(
_pipe@9,
Handler
),
gleam@result:unwrap(_pipe@10, Bad_request)
end end
),
gleam@result:unwrap(_pipe@11, Bad_request)
end,
_pipe@13 = gleam@http@response:map(
_pipe@12,
fun(A) -> {bit_builder_body, A} end
),
{response, _pipe@13}
end
).