-module(dew). -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]). -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 => <<"dew"/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 => <<"dew"/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 => <<"dew"/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 => <<"dew"/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 => <<"dew"/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 => <<"dew"/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 => <<"dew"/utf8>>, function => <<"make_handler"/utf8>>, line => 202}) end end, {stop, normal} end end.