Current section
Files
Jump to
Current section
Files
src/gramps@http.erl
-module(gramps@http).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-define(FILEPATH, "src/gramps/http.gleam").
-export([read_response/1, read_request/1, status_to_bit_array/1, encode_headers/1, response_builder/2, to_bytes_tree/1]).
-export_type([packet_type/0, decode_packet_error/0, uri_packet/0, decoded_packet/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.
-type packet_type() :: httph_bin | http_bin.
-type decode_packet_error() :: {more, integer()} | {http_error, binary()}.
-type uri_packet() :: {abs_path, binary()} |
{absolute_uri, gleam@http:scheme(), binary(), integer(), binary()}.
-type decoded_packet() :: {http_request,
binary(),
uri_packet(),
{integer(), integer()}} |
{http_response, {integer(), integer()}, integer(), binary()} |
{http_header, integer(), gleam@dynamic:dynamic_(), binary(), binary()} |
http_eoh.
-file("src/gramps/http.gleam", 41).
-spec get_headers(bitstring(), list({binary(), binary()})) -> {ok,
{list({binary(), binary()}), bitstring()}} |
{error, decode_packet_error()}.
get_headers(Data, Headers) ->
case gramps_ffi:decode_packet(httph_bin, Data, []) of
{ok, {http_eoh, Rest}} ->
{ok, {Headers, Rest}};
{ok, {{http_header, _, _, Field, Value}, Rest@1}} ->
get_headers(Rest@1, [{string:lowercase(Field), Value} | Headers]);
{ok, Val} ->
{error,
{http_error,
<<"Expected only headers but got request/response: "/utf8,
(gleam@string:inspect(Val))/binary>>}};
{error, Reason} ->
{error, Reason}
end.
-file("src/gramps/http.gleam", 59).
-spec read_response(bitstring()) -> {ok,
{gleam@http@response:response(nil), bitstring()}} |
{error, decode_packet_error()}.
read_response(Data) ->
case gramps_ffi:decode_packet(http_bin, Data, []) of
{ok, {{http_response, _, Status, _}, Rest}} ->
case get_headers(Rest, []) of
{ok, {Headers, Rest@1}} ->
{ok, {{response, Status, Headers, nil}, Rest@1}};
{error, Reason} ->
{error, Reason}
end;
{error, Reason@1} ->
{error, Reason@1};
_ ->
{error, {http_error, <<"Unexpected data"/utf8>>}}
end.
-file("src/gramps/http.gleam", 76).
-spec read_request(bitstring()) -> {ok,
{gleam@http@request:request(nil), bitstring()}} |
{error, decode_packet_error()}.
read_request(Data) ->
case gramps_ffi:decode_packet(http_bin, Data, []) of
{ok, {{http_request, Method, Uri, _}, Rest}} ->
case get_headers(Rest, []) of
{ok, {Headers, Rest@1}} ->
Host = begin
_pipe = Headers,
_pipe@1 = gleam@list:key_find(_pipe, <<"host"/utf8>>),
gleam@result:unwrap(_pipe@1, <<""/utf8>>)
end,
{Scheme@1, Host@2, Port@1, Path@2} = case Uri of
{absolute_uri, Scheme, Host@1, Port, Path} ->
{Scheme, Host@1, {some, Port}, Path};
{abs_path, Path@1} ->
{http, Host, none, Path@1}
end,
{Path@3, Query} = begin
_pipe@2 = Path@2,
_pipe@3 = gleam@string:split_once(_pipe@2, <<"?"/utf8>>),
_pipe@4 = gleam@result:map(
_pipe@3,
fun(Pair) ->
{erlang:element(1, Pair),
{some, erlang:element(2, Pair)}}
end
),
gleam@result:unwrap(_pipe@4, {Path@2, none})
end,
Method@1 = gleam@http:parse_method(Method),
{ok,
{{request,
gleam@result:unwrap(Method@1, get),
Headers,
nil,
Scheme@1,
Host@2,
Port@1,
Path@3,
Query},
Rest@1}};
{error, Reason} ->
{error, Reason}
end;
{error, Reason@1} ->
{error, Reason@1};
Err ->
{error,
{http_error,
<<"Unexpected data: "/utf8,
(gleam@string:inspect(Err))/binary>>}}
end.
-file("src/gramps/http.gleam", 148).
-spec status_to_bit_array(integer()) -> bitstring().
status_to_bit_array(Status) ->
case Status of
100 ->
<<"Continue"/utf8>>;
101 ->
<<"Switching Protocols"/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>>;
300 ->
<<"Multiple Choices"/utf8>>;
301 ->
<<"Moved Permanently"/utf8>>;
302 ->
<<"Found"/utf8>>;
303 ->
<<"See Other"/utf8>>;
304 ->
<<"Not Modified"/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 ->
<<"Payload Too Large"/utf8>>;
414 ->
<<"URI Too Long"/utf8>>;
415 ->
<<"Unsupported Media Type"/utf8>>;
416 ->
<<"Range Not Satisfiable"/utf8>>;
417 ->
<<"Expectation Failed"/utf8>>;
418 ->
<<"I'm a teapot"/utf8>>;
422 ->
<<"Unprocessable Entity"/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>>;
_ ->
<<"Unknown HTTP Status"/utf8>>
end.
-file("src/gramps/http.gleam", 209).
-spec encode_headers(list({binary(), binary()})) -> gleam@bytes_tree:bytes_tree().
encode_headers(Headers) ->
gleam@list:fold(
Headers,
gleam@bytes_tree:new(),
fun(Builder, Tup) ->
{Header, Value} = Tup,
_pipe = Builder,
_pipe@1 = gleam@bytes_tree:append_string(_pipe, Header),
_pipe@2 = gleam@bytes_tree:append(_pipe@1, <<": "/utf8>>),
_pipe@3 = gleam@bytes_tree:append_string(_pipe@2, Value),
gleam@bytes_tree:append(_pipe@3, <<"\r\n"/utf8>>)
end
).
-file("src/gramps/http.gleam", 132).
-spec response_builder(integer(), list({binary(), binary()})) -> gleam@bytes_tree:bytes_tree().
response_builder(Status, Headers) ->
Status_string = begin
_pipe = Status,
_pipe@1 = erlang:integer_to_binary(_pipe),
_pipe@2 = gleam_stdlib:wrap_list(_pipe@1),
_pipe@3 = gleam@bytes_tree:append(_pipe@2, <<" "/utf8>>),
gleam@bytes_tree:append(_pipe@3, status_to_bit_array(Status))
end,
_pipe@4 = gleam@bytes_tree:new(),
_pipe@5 = gleam@bytes_tree:append(_pipe@4, <<"HTTP/1.1 "/utf8>>),
_pipe@6 = gleam_stdlib:iodata_append(_pipe@5, Status_string),
_pipe@7 = gleam@bytes_tree:append(_pipe@6, <<"\r\n"/utf8>>),
_pipe@8 = gleam_stdlib:iodata_append(_pipe@7, encode_headers(Headers)),
gleam@bytes_tree:append(_pipe@8, <<"\r\n"/utf8>>).
-file("src/gramps/http.gleam", 126).
?DOC(" Turns an HTTP response into a TCP message\n").
-spec to_bytes_tree(gleam@http@response:response(gleam@bytes_tree:bytes_tree())) -> gleam@bytes_tree:bytes_tree().
to_bytes_tree(Resp) ->
_pipe = erlang:element(2, Resp),
_pipe@1 = response_builder(_pipe, erlang:element(3, Resp)),
gleam_stdlib:iodata_append(_pipe@1, erlang:element(4, Resp)).