Current section
Files
Jump to
Current section
Files
src/cgi.erl
-module(cgi).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([load_request/0, read_body/1, with_request_body/2, handle_request/1, main/0, send_response/1]).
-spec load_request() -> gleam@http@request:request(bitstring()).
load_request() ->
Env = envoy_ffi:all(),
Method = begin
_pipe = Env,
_pipe@1 = gleam@dict:get(_pipe, <<"REQUEST_METHOD"/utf8>>),
_pipe@2 = gleam@result:'try'(_pipe@1, fun gleam@http:parse_method/1),
gleam@result:unwrap(_pipe@2, get)
end,
Port = begin
_pipe@3 = Env,
_pipe@4 = gleam@dict:get(_pipe@3, <<"SERVER_PORT"/utf8>>),
_pipe@5 = gleam@result:'try'(_pipe@4, fun gleam@int:parse/1),
gleam@option:from_result(_pipe@5)
end,
Scheme = case gleam@dict:get(Env, <<"HTTPS"/utf8>>) of
{ok, _} ->
https;
_ ->
http
end,
Query = gleam@option:from_result(
gleam@dict:get(Env, <<"QUERY_STRING"/utf8>>)
),
Host = begin
_pipe@6 = gleam@dict:get(Env, <<"SERVER_NAME"/utf8>>),
gleam@result:unwrap(_pipe@6, <<"localhost"/utf8>>)
end,
Path = begin
_pipe@7 = gleam@dict:get(Env, <<"PATH_INFO"/utf8>>),
gleam@result:unwrap(_pipe@7, <<"/"/utf8>>)
end,
Headers = begin
_pipe@8 = Env,
_pipe@9 = maps:to_list(_pipe@8),
gleam@list:filter_map(
_pipe@9,
fun(Pair) -> case erlang:element(1, Pair) of
<<"CONTENT_TYPE"/utf8>> ->
{ok, {<<"content-type"/utf8>>, erlang:element(2, Pair)}};
<<"CONTENT_LENGTH"/utf8>> ->
{ok,
{<<"content-length"/utf8>>, erlang:element(2, Pair)}};
<<"HTTP_"/utf8, Name/binary>> ->
{ok,
{gleam@string:replace(
gleam@string:lowercase(Name),
<<"_"/utf8>>,
<<"-"/utf8>>
),
erlang:element(2, Pair)}};
_ ->
{error, nil}
end end
)
end,
Body = <<>>,
{request, Method, Headers, Body, Scheme, Host, Port, Path, Query}.
-spec request_content_length(gleam@http@request:request(bitstring())) -> integer().
request_content_length(Request) ->
_pipe = Request,
_pipe@1 = gleam@http@request:get_header(_pipe, <<"content-length"/utf8>>),
_pipe@2 = gleam@result:'try'(_pipe@1, fun gleam@int:parse/1),
gleam@result:unwrap(_pipe@2, 0).
-spec read_body(gleam@http@request:request(bitstring())) -> gleam@http@request:request(bitstring()).
read_body(Request) ->
Body = cgi_ffi:read_body_sync(request_content_length(Request)),
erlang:setelement(4, Request, Body).
-spec read_body_async(integer(), fun((bitstring()) -> any())) -> nil.
read_body_async(Length, Handle) ->
Body = cgi_ffi:read_body_sync(Length),
Handle(Body),
nil.
-spec with_request_body(
gleam@http@request:request(bitstring()),
fun((gleam@http@request:request(bitstring())) -> any())
) -> nil.
with_request_body(Request, Handle) ->
read_body_async(
request_content_length(Request),
fun(Body) -> Handle(erlang:setelement(4, Request, Body)) end
).
-spec handle_request(
fun((gleam@http@request:request(bitstring())) -> gleam@http@response:response(binary()))
) -> nil.
handle_request(F) ->
with_request_body(load_request(), F).
-spec main() -> nil.
main() ->
handle_request(
fun(Request) ->
Body = <<"Hello! You send me this request:\n\n"/utf8,
(gleam@string:inspect(Request))/binary>>,
{response,
201,
[{<<"content-type"/utf8>>, <<"text/plain"/utf8>>}],
Body}
end
).
-spec status_phrase(integer()) -> binary().
status_phrase(Status) ->
case Status of
100 ->
<<"Continue"/utf8>>;
101 ->
<<"Switching Protocols"/utf8>>;
102 ->
<<"Processing"/utf8>>;
103 ->
<<"Early Hints"/utf8>>;
200 ->
<<"OK"/utf8>>;
201 ->
<<"Created"/utf8>>;
202 ->
<<"Accepted"/utf8>>;
203 ->
<<"Non-Authoritative Information"/utf8>>;
204 ->
<<"No Content"/utf8>>;
205 ->
<<"Reset Content"/utf8>>;
206 ->
<<"Partial Content"/utf8>>;
207 ->
<<"Multi-Status"/utf8>>;
208 ->
<<"Already Reported"/utf8>>;
226 ->
<<"IM Used"/utf8>>;
300 ->
<<"Multiple Choices"/utf8>>;
301 ->
<<"Moved Permanently"/utf8>>;
302 ->
<<"Found"/utf8>>;
303 ->
<<"See Other"/utf8>>;
304 ->
<<"Not Modified"/utf8>>;
305 ->
<<"Use Proxy"/utf8>>;
306 ->
<<"Switch Proxy"/utf8>>;
307 ->
<<"Temporary Redirect"/utf8>>;
308 ->
<<"Permanent Redirect"/utf8>>;
400 ->
<<"Bad Request"/utf8>>;
401 ->
<<"Unauthorized"/utf8>>;
402 ->
<<"Payment Required"/utf8>>;
403 ->
<<"Forbidden"/utf8>>;
404 ->
<<"Not Found"/utf8>>;
405 ->
<<"Method Not Allowed"/utf8>>;
406 ->
<<"Not Acceptable"/utf8>>;
407 ->
<<"Proxy Authentication Required"/utf8>>;
408 ->
<<"Request Timeout"/utf8>>;
409 ->
<<"Conflict"/utf8>>;
410 ->
<<"Gone"/utf8>>;
411 ->
<<"Length Required"/utf8>>;
412 ->
<<"Precondition Failed"/utf8>>;
413 ->
<<"Request Entity Too Large"/utf8>>;
414 ->
<<"Request-URI Too Long"/utf8>>;
415 ->
<<"Unsupported Media Type"/utf8>>;
416 ->
<<"Requested Range Not Satisfiable"/utf8>>;
417 ->
<<"Expectation Failed"/utf8>>;
418 ->
<<"I'm a teapot"/utf8>>;
421 ->
<<"Misdirected Request"/utf8>>;
422 ->
<<"Unprocessable Entity"/utf8>>;
423 ->
<<"Locked"/utf8>>;
424 ->
<<"Failed Dependency"/utf8>>;
425 ->
<<"Too Early"/utf8>>;
426 ->
<<"Upgrade Required"/utf8>>;
428 ->
<<"Precondition Required"/utf8>>;
429 ->
<<"Too Many Requests"/utf8>>;
431 ->
<<"Request Header Fields Too Large"/utf8>>;
451 ->
<<"Unavailable For Legal Reasons"/utf8>>;
500 ->
<<"Internal Server Error"/utf8>>;
501 ->
<<"Not Implemented"/utf8>>;
502 ->
<<"Bad Gateway"/utf8>>;
503 ->
<<"Service Unavailable"/utf8>>;
504 ->
<<"Gateway Timeout"/utf8>>;
505 ->
<<"HTTP Version Not Supported"/utf8>>;
506 ->
<<"Variant Also Negotiates"/utf8>>;
507 ->
<<"Insufficient Storage"/utf8>>;
508 ->
<<"Loop Detected"/utf8>>;
510 ->
<<"Not Extended"/utf8>>;
511 ->
<<"Network Authentication Required"/utf8>>;
_ ->
<<""/utf8>>
end.
-spec send_response(gleam@http@response:response(binary())) -> nil.
send_response(Response) ->
S = erlang:element(2, Response),
gleam@io:println(
<<<<<<"status: "/utf8, (gleam@int:to_string(S))/binary>>/binary,
" "/utf8>>/binary,
(status_phrase(S))/binary>>
),
L = erlang:byte_size(erlang:element(4, Response)),
gleam@io:println(
<<"content-length: "/utf8, (gleam@int:to_string(L))/binary>>
),
gleam@list:each(
erlang:element(3, Response),
fun(Header) ->
gleam@io:println(
<<<<(erlang:element(1, Header))/binary, ": "/utf8>>/binary,
(erlang:element(2, Header))/binary>>
)
end
),
gleam@io:println(<<""/utf8>>),
gleam@io:println(erlang:element(4, Response)).