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(), boolean()) -> {ok,
{bitstring(), bitstring()}} |
{error, dove@error:error()}.
consume_till_crlf(Data, Storage, Include_crlf) ->
case erlang:byte_size(Data) of
0 ->
{error, more_needed};
_ ->
case Data of
<<"\r\n"/utf8, Rest/bitstring>> when Include_crlf ->
{ok,
{gleam@bit_array:append(Storage, <<"\r\n"/utf8>>), Rest}};
<<"\r\n"/utf8, Rest@1/bitstring>> ->
{ok, {Storage, Rest@1}};
<<Ch:8, Rest@2/bitstring>> ->
consume_till_crlf(
Rest@2,
gleam@bit_array:append(Storage, <<Ch>>),
Include_crlf
)
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, dove@error:error()}.
consume_by_length(Data, Length, Storage) ->
case erlang:byte_size(Data) of
0 ->
{error, more_needed};
_ ->
<<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 gather_chunks(bitstring(), bitstring()) -> {ok,
{bitstring(), bitstring()}} |
{error, dove@error:error()}.
gather_chunks(Data, Storage) ->
case erlang:byte_size(Data) of
0 ->
{error, more_needed};
_ ->
case consume_till_crlf(Data, <<>>, false) of
{ok, {Length, Rest}} ->
case Length of
<<"0"/utf8>> ->
<<"\r\n"/utf8, Rest@1/bitstring>> = Rest,
{ok, {Storage, Rest@1}};
_ ->
case consume_till_crlf(Rest, <<>>, false) of
{ok, {Chunk, Rest@2}} ->
gather_chunks(
Rest@2,
gleam@bit_array:append(Storage, Chunk)
);
{error, Error} ->
{error, Error}
end
end;
{error, Error@1} ->
{error, Error@1}
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, <<>>, true),
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 {gleam@list:key_find(
Headers@2,
<<"transfer-encoding"/utf8>>
),
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,
<<"chunked"/utf8>>},
_} ->
gleam@result:then(
gather_chunks(
Rest@1,
<<>>
),
fun(_use0@3) ->
{Body,
Rest@2} = _use0@3,
{ok,
{{Status,
Headers@2,
{some,
Body}},
Rest@2}}
end
);
{_, {ok, Length}} when Length > 0 ->
gleam@result:then(
consume_by_length(
Rest@1,
Length - 1,
<<>>
),
fun(_use0@4) ->
{Body@1,
Rest@3} = _use0@4,
{ok,
{{Status,
Headers@2,
{some,
Body@1}},
Rest@3}}
end
);
_ ->
{ok,
{{Status,
Headers@2,
none},
Rest@1}}
end
end
);
{ok, more} ->
{error, more_needed};
{error, nil} ->
{error, invalid_status_line};
_ ->
{error, wrong_packet_type}
end
end
)
end
)
end
)
end
).