aboutsummaryrefslogtreecommitdiff
path: root/aoc2023/build/packages/gleam_http/src/gleam@http.erl
diff options
context:
space:
mode:
authorHJ <thechairman@thechairman.info>2024-02-03 15:09:54 -0500
committerHJ <thechairman@thechairman.info>2024-02-03 15:09:54 -0500
commit96a3c5c179d8d3fff24eb2953e45f8dd15e2714c (patch)
tree0a67bc0cfeabe51740bb049c61f16f1ac3bdd4ff /aoc2023/build/packages/gleam_http/src/gleam@http.erl
parent547fe03cf43105f46160e2dd9afff21637eaaf47 (diff)
downloadgleam_aoc-96a3c5c179d8d3fff24eb2953e45f8dd15e2714c.tar.gz
gleam_aoc-96a3c5c179d8d3fff24eb2953e45f8dd15e2714c.zip
cleanup
Diffstat (limited to 'aoc2023/build/packages/gleam_http/src/gleam@http.erl')
-rw-r--r--aoc2023/build/packages/gleam_http/src/gleam@http.erl626
1 files changed, 626 insertions, 0 deletions
diff --git a/aoc2023/build/packages/gleam_http/src/gleam@http.erl b/aoc2023/build/packages/gleam_http/src/gleam@http.erl
new file mode 100644
index 0000000..91ee6e8
--- /dev/null
+++ b/aoc2023/build/packages/gleam_http/src/gleam@http.erl
@@ -0,0 +1,626 @@
+-module(gleam@http).
+-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]).
+
+-export([parse_method/1, method_to_string/1, scheme_to_string/1, scheme_from_string/1, parse_content_disposition/1, parse_multipart_body/2, method_from_dynamic/1, parse_multipart_headers/2]).
+-export_type([method/0, scheme/0, multipart_headers/0, multipart_body/0, content_disposition/0]).
+
+-type method() :: get |
+ post |
+ head |
+ put |
+ delete |
+ trace |
+ connect |
+ options |
+ patch |
+ {other, binary()}.
+
+-type scheme() :: http | https.
+
+-type multipart_headers() :: {multipart_headers,
+ list({binary(), binary()}),
+ bitstring()} |
+ {more_required_for_headers,
+ fun((bitstring()) -> {ok, multipart_headers()} | {error, nil})}.
+
+-type multipart_body() :: {multipart_body, bitstring(), boolean(), bitstring()} |
+ {more_required_for_body,
+ bitstring(),
+ fun((bitstring()) -> {ok, multipart_body()} | {error, nil})}.
+
+-type content_disposition() :: {content_disposition,
+ binary(),
+ list({binary(), binary()})}.
+
+-spec parse_method(binary()) -> {ok, method()} | {error, nil}.
+parse_method(S) ->
+ case gleam@string:lowercase(S) of
+ <<"connect"/utf8>> ->
+ {ok, connect};
+
+ <<"delete"/utf8>> ->
+ {ok, delete};
+
+ <<"get"/utf8>> ->
+ {ok, get};
+
+ <<"head"/utf8>> ->
+ {ok, head};
+
+ <<"options"/utf8>> ->
+ {ok, options};
+
+ <<"patch"/utf8>> ->
+ {ok, patch};
+
+ <<"post"/utf8>> ->
+ {ok, post};
+
+ <<"put"/utf8>> ->
+ {ok, put};
+
+ <<"trace"/utf8>> ->
+ {ok, trace};
+
+ _ ->
+ {error, nil}
+ end.
+
+-spec method_to_string(method()) -> binary().
+method_to_string(Method) ->
+ case Method of
+ connect ->
+ <<"connect"/utf8>>;
+
+ delete ->
+ <<"delete"/utf8>>;
+
+ get ->
+ <<"get"/utf8>>;
+
+ head ->
+ <<"head"/utf8>>;
+
+ options ->
+ <<"options"/utf8>>;
+
+ patch ->
+ <<"patch"/utf8>>;
+
+ post ->
+ <<"post"/utf8>>;
+
+ put ->
+ <<"put"/utf8>>;
+
+ trace ->
+ <<"trace"/utf8>>;
+
+ {other, S} ->
+ S
+ end.
+
+-spec scheme_to_string(scheme()) -> binary().
+scheme_to_string(Scheme) ->
+ case Scheme of
+ http ->
+ <<"http"/utf8>>;
+
+ https ->
+ <<"https"/utf8>>
+ end.
+
+-spec scheme_from_string(binary()) -> {ok, scheme()} | {error, nil}.
+scheme_from_string(Scheme) ->
+ case gleam@string:lowercase(Scheme) of
+ <<"http"/utf8>> ->
+ {ok, http};
+
+ <<"https"/utf8>> ->
+ {ok, https};
+
+ _ ->
+ {error, nil}
+ end.
+
+-spec skip_whitespace(bitstring()) -> bitstring().
+skip_whitespace(Data) ->
+ case Data of
+ <<32, Data@1/binary>> ->
+ skip_whitespace(Data@1);
+
+ <<9, Data@1/binary>> ->
+ skip_whitespace(Data@1);
+
+ _ ->
+ Data
+ end.
+
+-spec more_please_headers(
+ fun((bitstring()) -> {ok, multipart_headers()} | {error, nil}),
+ bitstring()
+) -> {ok, multipart_headers()} | {error, nil}.
+more_please_headers(Continuation, Existing) ->
+ {ok,
+ {more_required_for_headers,
+ fun(More) ->
+ gleam@bool:guard(
+ More =:= <<>>,
+ {error, nil},
+ fun() ->
+ Continuation(<<Existing/bitstring, More/bitstring>>)
+ end
+ )
+ end}}.
+
+-spec parse_rfc_2045_parameter_quoted_value(binary(), binary(), binary()) -> {ok,
+ {{binary(), binary()}, binary()}} |
+ {error, nil}.
+parse_rfc_2045_parameter_quoted_value(Header, Name, Value) ->
+ case gleam@string:pop_grapheme(Header) of
+ {error, nil} ->
+ {error, nil};
+
+ {ok, {<<"\""/utf8>>, Rest}} ->
+ {ok, {{Name, Value}, Rest}};
+
+ {ok, {<<"\\"/utf8>>, Rest@1}} ->
+ gleam@result:'try'(
+ gleam@string:pop_grapheme(Rest@1),
+ fun(_use0) ->
+ {Grapheme, Rest@2} = _use0,
+ parse_rfc_2045_parameter_quoted_value(
+ Rest@2,
+ Name,
+ <<Value/binary, Grapheme/binary>>
+ )
+ end
+ );
+
+ {ok, {Grapheme@1, Rest@3}} ->
+ parse_rfc_2045_parameter_quoted_value(
+ Rest@3,
+ Name,
+ <<Value/binary, Grapheme@1/binary>>
+ )
+ end.
+
+-spec parse_rfc_2045_parameter_unquoted_value(binary(), binary(), binary()) -> {{binary(),
+ binary()},
+ binary()}.
+parse_rfc_2045_parameter_unquoted_value(Header, Name, Value) ->
+ case gleam@string:pop_grapheme(Header) of
+ {error, nil} ->
+ {{Name, Value}, Header};
+
+ {ok, {<<";"/utf8>>, Rest}} ->
+ {{Name, Value}, Rest};
+
+ {ok, {<<" "/utf8>>, Rest}} ->
+ {{Name, Value}, Rest};
+
+ {ok, {<<"\t"/utf8>>, Rest}} ->
+ {{Name, Value}, Rest};
+
+ {ok, {Grapheme, Rest@1}} ->
+ parse_rfc_2045_parameter_unquoted_value(
+ Rest@1,
+ Name,
+ <<Value/binary, Grapheme/binary>>
+ )
+ end.
+
+-spec parse_rfc_2045_parameter_value(binary(), binary()) -> {ok,
+ {{binary(), binary()}, binary()}} |
+ {error, nil}.
+parse_rfc_2045_parameter_value(Header, Name) ->
+ case gleam@string:pop_grapheme(Header) of
+ {error, nil} ->
+ {error, nil};
+
+ {ok, {<<"\""/utf8>>, Rest}} ->
+ parse_rfc_2045_parameter_quoted_value(Rest, Name, <<""/utf8>>);
+
+ {ok, {Grapheme, Rest@1}} ->
+ {ok,
+ parse_rfc_2045_parameter_unquoted_value(Rest@1, Name, Grapheme)}
+ end.
+
+-spec parse_rfc_2045_parameter(binary(), binary()) -> {ok,
+ {{binary(), binary()}, binary()}} |
+ {error, nil}.
+parse_rfc_2045_parameter(Header, Name) ->
+ gleam@result:'try'(
+ gleam@string:pop_grapheme(Header),
+ fun(_use0) ->
+ {Grapheme, Rest} = _use0,
+ case Grapheme of
+ <<"="/utf8>> ->
+ parse_rfc_2045_parameter_value(Rest, Name);
+
+ _ ->
+ parse_rfc_2045_parameter(
+ Rest,
+ <<Name/binary,
+ (gleam@string:lowercase(Grapheme))/binary>>
+ )
+ end
+ end
+ ).
+
+-spec parse_rfc_2045_parameters(binary(), list({binary(), binary()})) -> {ok,
+ list({binary(), binary()})} |
+ {error, nil}.
+parse_rfc_2045_parameters(Header, Parameters) ->
+ case gleam@string:pop_grapheme(Header) of
+ {error, nil} ->
+ {ok, gleam@list:reverse(Parameters)};
+
+ {ok, {<<";"/utf8>>, Rest}} ->
+ parse_rfc_2045_parameters(Rest, Parameters);
+
+ {ok, {<<" "/utf8>>, Rest}} ->
+ parse_rfc_2045_parameters(Rest, Parameters);
+
+ {ok, {<<"\t"/utf8>>, Rest}} ->
+ parse_rfc_2045_parameters(Rest, Parameters);
+
+ {ok, {Grapheme, Rest@1}} ->
+ Acc = gleam@string:lowercase(Grapheme),
+ gleam@result:'try'(
+ parse_rfc_2045_parameter(Rest@1, Acc),
+ fun(_use0) ->
+ {Parameter, Rest@2} = _use0,
+ parse_rfc_2045_parameters(Rest@2, [Parameter | Parameters])
+ end
+ )
+ end.
+
+-spec parse_content_disposition_type(binary(), binary()) -> {ok,
+ content_disposition()} |
+ {error, nil}.
+parse_content_disposition_type(Header, Name) ->
+ case gleam@string:pop_grapheme(Header) of
+ {error, nil} ->
+ {ok, {content_disposition, Name, []}};
+
+ {ok, {<<" "/utf8>>, Rest}} ->
+ Result = parse_rfc_2045_parameters(Rest, []),
+ gleam@result:map(
+ Result,
+ fun(Parameters) -> {content_disposition, Name, Parameters} end
+ );
+
+ {ok, {<<"\t"/utf8>>, Rest}} ->
+ Result = parse_rfc_2045_parameters(Rest, []),
+ gleam@result:map(
+ Result,
+ fun(Parameters) -> {content_disposition, Name, Parameters} end
+ );
+
+ {ok, {<<";"/utf8>>, Rest}} ->
+ Result = parse_rfc_2045_parameters(Rest, []),
+ gleam@result:map(
+ Result,
+ fun(Parameters) -> {content_disposition, Name, Parameters} end
+ );
+
+ {ok, {Grapheme, Rest@1}} ->
+ parse_content_disposition_type(
+ Rest@1,
+ <<Name/binary, (gleam@string:lowercase(Grapheme))/binary>>
+ )
+ end.
+
+-spec parse_content_disposition(binary()) -> {ok, content_disposition()} |
+ {error, nil}.
+parse_content_disposition(Header) ->
+ parse_content_disposition_type(Header, <<""/utf8>>).
+
+-spec more_please_body(
+ fun((bitstring()) -> {ok, multipart_body()} | {error, nil}),
+ bitstring(),
+ bitstring()
+) -> {ok, multipart_body()} | {error, nil}.
+more_please_body(Continuation, Chunk, Existing) ->
+ _pipe = fun(More) ->
+ gleam@bool:guard(
+ More =:= <<>>,
+ {error, nil},
+ fun() -> Continuation(<<Existing/bitstring, More/bitstring>>) end
+ )
+ end,
+ _pipe@1 = {more_required_for_body, Chunk, _pipe},
+ {ok, _pipe@1}.
+
+-spec parse_body_loop(bitstring(), bitstring(), bitstring()) -> {ok,
+ multipart_body()} |
+ {error, nil}.
+parse_body_loop(Data, Boundary, Body) ->
+ Dsize = erlang:byte_size(Data),
+ Bsize = erlang:byte_size(Boundary),
+ Required = 6 + Bsize,
+ case Data of
+ _ when Dsize < Required ->
+ more_please_body(
+ fun(_capture) -> parse_body_loop(_capture, Boundary, <<>>) end,
+ Body,
+ Data
+ );
+
+ <<13, 10, Data@1/binary>> ->
+ Desired = <<45, 45, Boundary/bitstring>>,
+ Size = erlang:byte_size(Desired),
+ Dsize@1 = erlang:byte_size(Data@1),
+ Prefix = gleam_stdlib:bit_array_slice(Data@1, 0, Size),
+ Rest = gleam_stdlib:bit_array_slice(Data@1, Size, Dsize@1 - Size),
+ case {Prefix =:= {ok, Desired}, Rest} of
+ {true, {ok, <<13, 10, _/binary>>}} ->
+ {ok, {multipart_body, Body, false, Data@1}};
+
+ {true, {ok, <<45, 45, Data@2/binary>>}} ->
+ {ok, {multipart_body, Body, true, Data@2}};
+
+ {false, _} ->
+ parse_body_loop(
+ Data@1,
+ Boundary,
+ <<Body/bitstring, 13, 10>>
+ );
+
+ {_, _} ->
+ {error, nil}
+ end;
+
+ <<Char, Data@3/binary>> ->
+ parse_body_loop(Data@3, Boundary, <<Body/bitstring, Char>>)
+ end.
+
+-spec parse_body_with_bit_array(bitstring(), bitstring()) -> {ok,
+ multipart_body()} |
+ {error, nil}.
+parse_body_with_bit_array(Data, Boundary) ->
+ Bsize = erlang:byte_size(Boundary),
+ Prefix = gleam_stdlib:bit_array_slice(Data, 0, 2 + Bsize),
+ case Prefix =:= {ok, <<45, 45, Boundary/bitstring>>} of
+ true ->
+ {ok, {multipart_body, <<>>, false, Data}};
+
+ false ->
+ parse_body_loop(Data, Boundary, <<>>)
+ end.
+
+-spec parse_multipart_body(bitstring(), binary()) -> {ok, multipart_body()} |
+ {error, nil}.
+parse_multipart_body(Data, Boundary) ->
+ _pipe = Boundary,
+ _pipe@1 = gleam_stdlib:identity(_pipe),
+ parse_body_with_bit_array(Data, _pipe@1).
+
+-spec method_from_dynamic(gleam@dynamic:dynamic_()) -> {ok, method()} |
+ {error, list(gleam@dynamic:decode_error())}.
+method_from_dynamic(Value) ->
+ case gleam_http_native:decode_method(Value) of
+ {ok, Method} ->
+ {ok, Method};
+
+ {error, _} ->
+ {error,
+ [{decode_error,
+ <<"HTTP method"/utf8>>,
+ gleam@dynamic:classify(Value),
+ []}]}
+ end.
+
+-spec parse_header_value(
+ bitstring(),
+ list({binary(), binary()}),
+ bitstring(),
+ bitstring()
+) -> {ok, multipart_headers()} | {error, nil}.
+parse_header_value(Data, Headers, Name, Value) ->
+ Size = erlang:byte_size(Data),
+ case Data of
+ _ when Size < 4 ->
+ _pipe@2 = fun(Data@1) -> _pipe = Data@1,
+ _pipe@1 = skip_whitespace(_pipe),
+ parse_header_value(_pipe@1, Headers, Name, Value) end,
+ more_please_headers(_pipe@2, Data);
+
+ <<13, 10, 13, 10, Data@2/binary>> ->
+ gleam@result:'try'(
+ gleam@bit_array:to_string(Name),
+ fun(Name@1) ->
+ gleam@result:map(
+ gleam@bit_array:to_string(Value),
+ fun(Value@1) ->
+ Headers@1 = gleam@list:reverse(
+ [{gleam@string:lowercase(Name@1), Value@1} |
+ Headers]
+ ),
+ {multipart_headers, Headers@1, Data@2}
+ end
+ )
+ end
+ );
+
+ <<13, 10, 32, Data@3/binary>> ->
+ parse_header_value(Data@3, Headers, Name, Value);
+
+ <<13, 10, 9, Data@3/binary>> ->
+ parse_header_value(Data@3, Headers, Name, Value);
+
+ <<13, 10, Data@4/binary>> ->
+ gleam@result:'try'(
+ gleam@bit_array:to_string(Name),
+ fun(Name@2) ->
+ gleam@result:'try'(
+ gleam@bit_array:to_string(Value),
+ fun(Value@2) ->
+ Headers@2 = [{gleam@string:lowercase(Name@2),
+ Value@2} |
+ Headers],
+ parse_header_name(Data@4, Headers@2, <<>>)
+ end
+ )
+ end
+ );
+
+ <<Char, Rest/binary>> ->
+ Value@3 = <<Value/bitstring, Char>>,
+ parse_header_value(Rest, Headers, Name, Value@3);
+
+ _ ->
+ {error, nil}
+ end.
+
+-spec parse_header_name(bitstring(), list({binary(), binary()}), bitstring()) -> {ok,
+ multipart_headers()} |
+ {error, nil}.
+parse_header_name(Data, Headers, Name) ->
+ case skip_whitespace(Data) of
+ <<58, Data@1/binary>> ->
+ _pipe = Data@1,
+ _pipe@1 = skip_whitespace(_pipe),
+ parse_header_value(_pipe@1, Headers, Name, <<>>);
+
+ <<Char, Data@2/binary>> ->
+ parse_header_name(Data@2, Headers, <<Name/bitstring, Char>>);
+
+ <<>> ->
+ more_please_headers(
+ fun(_capture) -> parse_header_name(_capture, Headers, Name) end,
+ Data
+ )
+ end.
+
+-spec do_parse_headers(bitstring()) -> {ok, multipart_headers()} | {error, nil}.
+do_parse_headers(Data) ->
+ case Data of
+ <<13, 10, 13, 10, Data@1/binary>> ->
+ {ok, {multipart_headers, [], Data@1}};
+
+ <<13, 10, Data@2/binary>> ->
+ parse_header_name(Data@2, [], <<>>);
+
+ <<13>> ->
+ more_please_headers(fun do_parse_headers/1, Data);
+
+ <<>> ->
+ more_please_headers(fun do_parse_headers/1, Data);
+
+ _ ->
+ {error, nil}
+ end.
+
+-spec parse_headers_after_prelude(bitstring(), bitstring()) -> {ok,
+ multipart_headers()} |
+ {error, nil}.
+parse_headers_after_prelude(Data, Boundary) ->
+ Dsize = erlang:byte_size(Data),
+ Bsize = erlang:byte_size(Boundary),
+ Required_size = Bsize + 4,
+ gleam@bool:guard(
+ Dsize < Required_size,
+ more_please_headers(
+ fun(_capture) -> parse_headers_after_prelude(_capture, Boundary) end,
+ Data
+ ),
+ fun() ->
+ gleam@result:'try'(
+ gleam_stdlib:bit_array_slice(Data, 0, Required_size - 2),
+ fun(Prefix) ->
+ gleam@result:'try'(
+ gleam_stdlib:bit_array_slice(Data, 2 + Bsize, 2),
+ fun(Second) ->
+ Desired = <<45, 45, Boundary/bitstring>>,
+ gleam@bool:guard(
+ Prefix /= Desired,
+ {error, nil},
+ fun() -> case Second =:= <<45, 45>> of
+ true ->
+ Rest_size = Dsize - Required_size,
+ gleam@result:map(
+ gleam_stdlib:bit_array_slice(
+ Data,
+ Required_size,
+ Rest_size
+ ),
+ fun(Data@1) ->
+ {multipart_headers,
+ [],
+ Data@1}
+ end
+ );
+
+ false ->
+ Start = Required_size - 2,
+ Rest_size@1 = (Dsize - Required_size)
+ + 2,
+ gleam@result:'try'(
+ gleam_stdlib:bit_array_slice(
+ Data,
+ Start,
+ Rest_size@1
+ ),
+ fun(Data@2) ->
+ do_parse_headers(Data@2)
+ end
+ )
+ end end
+ )
+ end
+ )
+ end
+ )
+ end
+ ).
+
+-spec skip_preamble(bitstring(), bitstring()) -> {ok, multipart_headers()} |
+ {error, nil}.
+skip_preamble(Data, Boundary) ->
+ Data_size = erlang:byte_size(Data),
+ Boundary_size = erlang:byte_size(Boundary),
+ Required = Boundary_size + 4,
+ case Data of
+ _ when Data_size < Required ->
+ more_please_headers(
+ fun(_capture) -> skip_preamble(_capture, Boundary) end,
+ Data
+ );
+
+ <<13, 10, 45, 45, Data@1/binary>> ->
+ case gleam_stdlib:bit_array_slice(Data@1, 0, Boundary_size) of
+ {ok, Prefix} when Prefix =:= Boundary ->
+ Start = Boundary_size,
+ Length = erlang:byte_size(Data@1) - Boundary_size,
+ gleam@result:'try'(
+ gleam_stdlib:bit_array_slice(Data@1, Start, Length),
+ fun(Rest) -> do_parse_headers(Rest) end
+ );
+
+ {ok, _} ->
+ skip_preamble(Data@1, Boundary);
+
+ {error, _} ->
+ {error, nil}
+ end;
+
+ <<_, Data@2/binary>> ->
+ skip_preamble(Data@2, Boundary)
+ end.
+
+-spec parse_multipart_headers(bitstring(), binary()) -> {ok,
+ multipart_headers()} |
+ {error, nil}.
+parse_multipart_headers(Data, Boundary) ->
+ Boundary@1 = gleam_stdlib:identity(Boundary),
+ Prefix = <<45, 45, Boundary@1/bitstring>>,
+ case gleam_stdlib:bit_array_slice(Data, 0, erlang:byte_size(Prefix)) =:= {ok,
+ Prefix} of
+ true ->
+ parse_headers_after_prelude(Data, Boundary@1);
+
+ false ->
+ skip_preamble(Data, Boundary@1)
+ end.