Current section
Files
Jump to
Current section
Files
src/dove@response.erl
-module(dove@response).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]).
-export([decode/1]).
-export_type([decode_result/0]).
-type decode_result() :: more |
{eoh, binary()} |
{header, {binary(), binary()}, binary()} |
{status_line, {{integer(), integer()}, integer(), binary()}, binary()}.
-spec consume_till_crlf(bitstring(), bitstring()) -> {ok,
{bitstring(), bitstring()}} |
{error, dove@error:error()}.
consume_till_crlf(Data, Storage) ->
case erlang:byte_size(Data) of
0 ->
{error, more_needed};
_ ->
case Data of
<<"\r\n"/utf8, Rest/bitstring>> ->
{ok,
{gleam@bit_array:append(Storage, <<"\r\n"/utf8>>), Rest}};
<<Ch:8, Rest@1/bitstring>> ->
consume_till_crlf(
Rest@1,
gleam@bit_array:append(Storage, <<Ch>>)
)
end
end.
-spec consume_till_double_crlf(bitstring(), bitstring()) -> {ok,
{bitstring(), bitstring()}} |
{error, dove@error:error()}.
consume_till_double_crlf(Data, Storage) ->
case erlang:byte_size(Data) of
0 ->
{error, more_needed};
_ ->
case Data of
<<"\r\n\r\n"/utf8, Rest/bitstring>> ->
{ok,
{gleam@bit_array:append(Storage, <<"\r\n\r\n"/utf8>>),
Rest}};
<<Ch:8, Rest@1/bitstring>> ->
consume_till_double_crlf(
Rest@1,
gleam@bit_array:append(Storage, <<Ch>>)
)
end
end.
-spec consume_by_length(bitstring(), integer(), bitstring()) -> {ok,
{bitstring(), bitstring()}} |
{error, nil}.
consume_by_length(Data, Length, Storage) ->
case erlang:byte_size(Data) of
0 ->
{error, nil};
_ ->
<<Ch:8, Rest/bitstring>> = Data,
case erlang:byte_size(Storage) =:= Length of
true ->
{ok, {gleam@bit_array:append(Storage, <<Ch>>), Rest}};
false ->
consume_by_length(
Rest,
Length,
gleam@bit_array:append(Storage, <<Ch>>)
)
end
end.
-spec decode_headers(binary(), list({binary(), binary()})) -> {ok,
{list({binary(), binary()}), binary()}} |
{error, dove@error:error()}.
decode_headers(Binary, Storage) ->
gleam@result:then(
begin
_pipe = dove_ffi:decode_header(Binary),
gleam@result:replace_error(_pipe, invalid_header)
end,
fun(Result) -> case Result of
{eoh, Rest} ->
{ok, {Storage, Rest}};
{header, Header, Rest@1} ->
decode_headers(Rest@1, gleam@list:append(Storage, [Header]));
more ->
{error, more_needed};
{status_line, _, _} ->
{error, wrong_packet_type}
end end
).
-spec decode(bitstring()) -> {ok,
{{integer(),
list({binary(), binary()}),
gleam@option:option(bitstring())},
bitstring()}} |
{error, dove@error:error()}.
decode(Response) ->
gleam@result:then(
consume_till_crlf(Response, <<>>),
fun(_use0) ->
{Status_line, Rest} = _use0,
gleam@result:then(
begin
_pipe = gleam@bit_array:to_string(Status_line),
gleam@result:replace_error(_pipe, invalid_status_line)
end,
fun(Status_line@1) ->
gleam@result:then(
consume_till_double_crlf(Rest, <<>>),
fun(_use0@1) ->
{Headers, Rest@1} = _use0@1,
gleam@result:then(
begin
_pipe@1 = gleam@bit_array:to_string(Headers),
gleam@result:replace_error(
_pipe@1,
invalid_header
)
end,
fun(Headers@1) ->
case dove_ffi:decode_status_line(
Status_line@1
) of
{ok, {status_line, {_, Status, _}, _}} ->
gleam@result:then(
decode_headers(Headers@1, []),
fun(_use0@2) ->
{Headers@2, _} = _use0@2,
case begin
_pipe@2 = gleam@list:key_find(
Headers@2,
<<"content-length"/utf8>>
),
_pipe@3 = gleam@result:map(
_pipe@2,
fun gleam@int:parse/1
),
gleam@result:flatten(
_pipe@3
)
end of
{ok, 0} ->
{ok,
{{Status,
Headers@2,
none},
Rest@1}};
{error, nil} ->
{ok,
{{Status,
Headers@2,
none},
Rest@1}};
{ok, Length} ->
gleam@result:then(
begin
_pipe@4 = consume_by_length(
Rest@1,
Length - 1,
<<>>
),
gleam@result:replace_error(
_pipe@4,
more_needed
)
end,
fun(_use0@3) ->
{Body,
Rest@2} = _use0@3,
{ok,
{{Status,
Headers@2,
{some,
Body}},
Rest@2}}
end
)
end
end
);
{ok, more} ->
{error, more_needed};
{error, nil} ->
{error, invalid_status_line};
_ ->
{error, wrong_packet_type}
end
end
)
end
)
end
)
end
).