-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}}; <> -> consume_till_crlf( Rest@1, gleam@bit_array:append(Storage, <>) ) 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}}; <> -> consume_till_double_crlf( Rest@1, gleam@bit_array:append(Storage, <>) ) 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}; _ -> <> = Data, case erlang:byte_size(Storage) =:= Length of true -> {ok, {gleam@bit_array:append(Storage, <>), Rest}}; false -> consume_by_length( Rest, Length, gleam@bit_array:append(Storage, <>) ) 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 ).