Current section

Files

Jump to
mist src mist.erl
Raw

src/mist.erl

-module(mist).
-compile(no_auto_import).
-export([from_header/1, parse_headers/2, parse_request/1, code_to_string/1, headers/1, to_string/1, http_response/2, hello_world/2, make_handler/1, listen/2, start_acceptor_pool/3]).
-export_type([packet_type/0, http_uri/0, http_packet/0, decoded_packet/0, decode_error/0]).
-type packet_type() :: http | httph_bin.
-type http_uri() :: {abs_path, gleam@erlang@charlist:charlist()}.
-type http_packet() :: {http_request,
gleam@erlang@atom:atom_(),
http_uri(),
{integer(), integer()}} |
{http_header,
integer(),
gleam@erlang@atom:atom_(),
bitstring(),
bitstring()}.
-type decoded_packet() :: {binary_data, http_packet(), bitstring()} |
{end_of_headers, bitstring()} |
{more_data, gleam@option:option(integer())}.
-type decode_error() :: invalid_method | unknown_header.
-spec from_header(bitstring()) -> binary().
from_header(Value) ->
{ok, Value@2} = case gleam@bit_string:to_string(Value) of
{ok, Value@1} -> {ok, Value@1};
_try ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _try,
module => <<"mist"/utf8>>,
function => <<"from_header"/utf8>>,
line => 54})
end,
gleam@string:lowercase(Value@2).
-spec parse_headers(bitstring(), list({binary(), binary()})) -> {ok,
{list({binary(),
binary()}),
bitstring()}} |
{error, decode_error()}.
parse_headers(Bs, Headers) ->
case glisten_ffi:decode_packet(httph_bin, Bs, []) of
{ok, {binary_data, {http_header, _@1, _@2, Field, Value}, Rest}} ->
Field@1 = from_header(Field),
Value@1 = from_header(Value),
parse_headers(Rest, [{Field@1, Value@1} | Headers]);
{ok, {end_of_headers, Rest@1}} ->
{ok, {Headers, Rest@1}};
_@3 ->
{error, unknown_header}
end.
-spec parse_request(bitstring()) -> {ok,
gleam@http@request:request(bitstring())} |
{error, decode_error()}.
parse_request(Bs) ->
case glisten_ffi:decode_packet(http, Bs, []) of
{error, _try} -> {error, _try};
{ok, {binary_data, Req, Rest}} ->
{http_request, Method@1, {abs_path, Path@1}, _@2} = case Req of
{http_request, Method, {abs_path, Path}, _@1} -> {http_request,
Method,
{abs_path,
Path},
_@1};
_try@1 ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _try@1,
module => <<"mist"/utf8>>,
function => <<"parse_request"/utf8>>,
line => 77})
end,
case begin
_pipe = Method@1,
_pipe@1 = gleam@erlang@atom:to_string(_pipe),
_pipe@2 = gleam@http:parse_method(_pipe@1),
gleam@result:replace_error(_pipe@2, invalid_method)
end of
{error, _try@2} -> {error, _try@2};
{ok, Method@2} ->
case parse_headers(Rest, []) of
{error, _try@3} -> {error, _try@3};
{ok, {Headers, Rest@1}} ->
Req@1 = begin
_pipe@3 = gleam@http@request:new(),
_pipe@4 = gleam@http@request:set_body(
_pipe@3,
Rest@1
),
_pipe@5 = gleam@http@request:set_method(
_pipe@4,
Method@2
),
gleam@http@request:set_path(
_pipe@5,
gleam@erlang@charlist:to_string(Path@1)
)
end,
{ok, erlang:setelement(3, Req@1, Headers)}
end
end
end.
-spec code_to_string(integer()) -> binary().
code_to_string(Code) ->
case Code of
200 ->
<<"Ok"/utf8>>;
_@1 ->
<<"Unknown"/utf8>>
end.
-spec headers(gleam@http@response:response(bitstring())) -> gleam@string_builder:string_builder().
headers(Resp) ->
gleam@list:fold(
erlang:element(3, Resp),
gleam@string_builder:from_string(<<""/utf8>>),
fun(Builder, Tup) ->
{Header, Value} = Tup,
_pipe = gleam@string_builder:from_strings(
[Header, <<": "/utf8>>, Value, <<"\r\n"/utf8>>]
),
gleam@string_builder:append_builder(Builder, _pipe)
end
).
-spec to_string(gleam@http@response:response(bitstring())) -> bitstring().
to_string(Resp) ->
Body_builder = case gleam@bit_string:byte_size(erlang:element(4, Resp)) of
0 ->
gleam@string_builder:from_string(<<""/utf8>>);
_@1 ->
_pipe = erlang:element(4, Resp),
_pipe@1 = gleam@bit_string:to_string(_pipe),
_pipe@2 = gleam@result:unwrap(_pipe@1, <<""/utf8>>),
_pipe@3 = gleam@string_builder:from_string(_pipe@2),
gleam@string_builder:append(_pipe@3, <<"\r\n"/utf8>>)
end,
_pipe@4 = <<"HTTP/1.1 "/utf8>>,
_pipe@5 = gleam@string_builder:from_string(_pipe@4),
_pipe@6 = gleam@string_builder:append(
_pipe@5,
gleam@int:to_string(erlang:element(2, Resp))
),
_pipe@7 = gleam@string_builder:append(_pipe@6, <<"\r\n"/utf8>>),
_pipe@8 = gleam@string_builder:append_builder(_pipe@7, headers(Resp)),
_pipe@9 = gleam@string_builder:append(_pipe@8, <<"\r\n\r\n"/utf8>>),
_pipe@10 = gleam@string_builder:append_builder(_pipe@9, Body_builder),
_pipe@11 = gleam@string_builder:to_string(_pipe@10),
gleam@bit_string:from_string(_pipe@11).
-spec http_response(integer(), bitstring()) -> bitstring().
http_response(Status, Body) ->
_pipe = gleam@http@response:new(Status),
_pipe@1 = gleam@http@response:set_body(_pipe, Body),
_pipe@2 = gleam@http@response:prepend_header(
_pipe@1,
<<"Content-Type"/utf8>>,
<<"text/plain"/utf8>>
),
_pipe@6 = gleam@http@response:prepend_header(
_pipe@2,
<<"Content-Length"/utf8>>,
begin
_pipe@3 = Body,
_pipe@4 = gleam@bit_string:byte_size(_pipe@3),
_pipe@5 = (fun(Size) -> Size + 1 end)(_pipe@4),
gleam@int:to_string(_pipe@5)
end
),
to_string(_pipe@6).
-spec hello_world(glisten@tcp:handler_message(), glisten@tcp:socket()) -> gleam@otp@actor:next(glisten@tcp:socket()).
hello_world(_, Sock) ->
{ok, Resp@1} = case begin
_pipe = <<"hello, world!"/utf8>>,
_pipe@1 = gleam@bit_string:from_string(_pipe),
_pipe@2 = http_response(200, _pipe@1),
gleam@bit_string:to_string(_pipe@2)
end of
{ok, Resp} -> {ok, Resp};
_try ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _try,
module => <<"mist"/utf8>>,
function => <<"hello_world"/utf8>>,
line => 155})
end,
_pipe@3 = Resp@1,
_pipe@4 = gleam@erlang@charlist:from_string(_pipe@3),
glisten_ffi:send(Sock, _pipe@4),
{stop, normal}.
-spec make_handler(
fun((gleam@http@request:request(bitstring())) -> gleam@http@response:response(bitstring()))
) -> fun((glisten@tcp:handler_message(), glisten@tcp:socket()) -> gleam@otp@actor:next(glisten@tcp:socket())).
make_handler(Handler) ->
fun(Msg, Sock) -> case Msg of
{tcp, _@1, _@2} ->
gleam@io:print(<<"this should not happen"/utf8>>),
{continue, Sock};
{tcp_closed, _@3} ->
{stop, normal};
{receive_message, Data} ->
case parse_request(
begin
_pipe = Data,
_pipe@1 = gleam@erlang@charlist:to_string(_pipe),
gleam@bit_string:from_string(_pipe@1)
end
) of
{ok, Req} ->
{ok, Resp@1} = case begin
_pipe@2 = Req,
_pipe@3 = Handler(_pipe@2),
_pipe@4 = to_string(_pipe@3),
gleam@bit_string:to_string(_pipe@4)
end of
{ok, Resp} -> {ok, Resp};
_try ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _try,
module => <<"mist"/utf8>>,
function => <<"make_handler"/utf8>>,
line => 188})
end,
{ok, nil} = case glisten_ffi:send(
Sock,
gleam@erlang@charlist:from_string(Resp@1)
) of
{ok, nil} -> {ok, nil};
_try@1 ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _try@1,
module => <<"mist"/utf8>>,
function => <<"make_handler"/utf8>>,
line => 193})
end;
{error, _@4} ->
{ok, Error@1} = case begin
_pipe@5 = 400,
_pipe@6 = gleam@http@response:new(_pipe@5),
_pipe@7 = gleam@http@response:set_body(
_pipe@6,
gleam@bit_string:from_string(<<""/utf8>>)
),
_pipe@8 = to_string(_pipe@7),
gleam@bit_string:to_string(_pipe@8)
end of
{ok, Error} -> {ok, Error};
_try@2 ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _try@2,
module => <<"mist"/utf8>>,
function => <<"make_handler"/utf8>>,
line => 196})
end,
{ok, nil} = case glisten_ffi:send(
Sock,
gleam@erlang@charlist:from_string(Error@1)
) of
{ok, nil} -> {ok, nil};
_try@3 ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _try@3,
module => <<"mist"/utf8>>,
function => <<"make_handler"/utf8>>,
line => 202})
end
end,
{stop, normal}
end end.
-spec listen(integer(), list(glisten@tcp:tcp_option())) -> {ok,
glisten@tcp:listen_socket()} |
{error, glisten@tcp:socket_reason()}.
listen(Port, Options) ->
glisten@tcp:listen(Port, Options).
-spec start_acceptor_pool(
glisten@tcp:listen_socket(),
fun((glisten@tcp:handler_message(), glisten@tcp:socket()) -> gleam@otp@actor:next(glisten@tcp:socket())),
integer()
) -> {ok, nil} | {error, nil}.
start_acceptor_pool(Listener_socket, Handler, Pool_count) ->
glisten@tcp:start_acceptor_pool(Listener_socket, Handler, Pool_count).