From db842388b4957891c9cec8279636da965a75411e Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 26 Dec 2019 15:11:32 +0300 Subject: [PATCH 1/4] Introduce rebar_uri Attempts to bridge http_uri (deprecated in OTP 23) and uri_string (available as of OTP 21+). (cherry picked from commit 7057cbe281296707771ee3a017406f993f24c77d) --- src/rebar_git_resource.erl | 4 ++-- src/rebar_uri.erl | 44 ++++++++++++++++++++++++++++++++++++++ src/rebar_utils.erl | 33 +++++++++++++++++++++------- test/rebar_utils_SUITE.erl | 16 +++++++++++--- 4 files changed, 84 insertions(+), 13 deletions(-) create mode 100644 src/rebar_uri.erl diff --git a/src/rebar_git_resource.erl b/src/rebar_git_resource.erl index 45bc0432..ab06836b 100644 --- a/src/rebar_git_resource.erl +++ b/src/rebar_git_resource.erl @@ -117,8 +117,8 @@ parse_git_url(Url) -> end. parse_git_url(not_scp, Url) -> UriOpts = [{scheme_defaults, [{git, 9418} | http_uri:scheme_defaults()]}], - case http_uri:parse(Url, UriOpts) of - {ok, {_Scheme, _User, Host, _Port, Path, _Query}} -> + case rebar_uri:parse(Url, UriOpts) of + #{path := Path, host := Host} -> {ok, {Host, filename:rootname(Path, ".git")}}; {error, Reason} -> {error, Reason} diff --git a/src/rebar_uri.erl b/src/rebar_uri.erl new file mode 100644 index 00000000..6e28a90d --- /dev/null +++ b/src/rebar_uri.erl @@ -0,0 +1,44 @@ +%%% @doc multi-OTP version compatibility shim for working with URIs +-module(rebar_uri). + +-ifdef (OTP_RELEASE). +-export([parse/1]). + +-spec parse(URIString) -> URIMap when + URIString :: uri_string:uri_string(), + URIMap :: uri_string:uri_map() | uri_string:error(). + +parse(URIString) -> + uri_string:parse(URIString). +-else. +-export([parse/1]). + +-spec parse(URIString) -> URIMap when + URIString :: iodata(), + URIMap :: map() | {error, atom(), term()}. + +parse(URIString) -> + case http_uri:parse(URIString) of + {error, Reason} -> + %% no additional parser/term info available to us, + %% e.g. see what uri_string returns in + %% uri_string:parse(<<"h$ttp:::://////lolz">>). + {error, Reason, ""}; + {ok, {Scheme, UserInfo, Host, Port, Path, Query}} -> + #{ + scheme => Scheme, + host => Host, + port => Port, + path => Path, + %% http_uri:parse/1 includes the leading question mark + %% in query string but uri_string:parse/1 leaves it out. + %% string:slice/2 isn't available in OTP <= 19. + query => case Query of + [] -> ""; + _ -> string:substr(Query, 2) + end, + userinfo => UserInfo + } + end. +-endif. + diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl index c587363d..7bfa5ca8 100644 --- a/src/rebar_utils.erl +++ b/src/rebar_utils.erl @@ -910,8 +910,7 @@ get_http_vars(Scheme) -> -ifdef (OTP_RELEASE). -if(?OTP_RELEASE >= 23). - -compile({nowarn_deprecated_function, [{http_uri, parse, 1}, - {http_uri, decode, 1}]}). + -compile({nowarn_deprecated_function, [{http_uri, decode, 1}]}). -endif. -endif. @@ -924,7 +923,10 @@ set_httpc_options(_, []) -> set_httpc_options(Scheme, Proxy) -> URI = normalise_proxy(Scheme, Proxy), - {ok, {_, UserInfo, Host, Port, _, _}} = http_uri:parse(URI), + Parts = rebar_uri:parse(URI), + Host = maps:get(host, Parts, []), + Port = maps:get(port, Parts, []), + UserInfo = maps:get(userinfo, Parts, []), httpc:set_options([{Scheme, {{Host, Port}, []}}], rebar), set_proxy_auth(UserInfo). @@ -935,14 +937,30 @@ normalise_proxy(Scheme, URI) -> _ -> URI end. +%% OTP 21+ +-ifdef (OTP_RELEASE). url_append_path(Url, ExtraPath) -> - case http_uri:parse(Url) of - {ok, {Scheme, UserInfo, Host, Port, Path, Query}} -> + case rebar_uri:parse(Url) of + #{path := Path} = Map -> + FullPath = filename:join(Path, ExtraPath), + {ok, uri_string:recompose(maps:update(path, FullPath, Map))}; + _ -> + error + end. +-else. +url_append_path(Url, ExtraPath) -> + case rebar_uri:parse(Url) of + #{scheme := Scheme, userinfo := UserInfo, host := Host, port := Port, path := Path, query := Query} -> + PrefixedQuery = case Query of + [] -> []; + Other -> lists:append(["?", Other]) + end, {ok, lists:append([atom_to_list(Scheme), "://", UserInfo, Host, ":", integer_to_list(Port), - filename:join(Path, ExtraPath), Query])}; + filename:join(Path, ExtraPath), PrefixedQuery])}; _ -> error end. +-endif. %% escape\ as\ a\ shell\? escape_chars(Str) when is_atom(Str) -> @@ -1028,8 +1046,7 @@ ssl_opts(Url) -> ssl_opts(ssl_verify_enabled, Url) -> case check_ssl_version() of true -> - {ok, {_, _, Hostname, _, _, _}} = - http_uri:parse(rebar_utils:to_list(Url)), + #{host := Hostname} = rebar_uri:parse(rebar_utils:to_list(Url)), VerifyFun = {fun ssl_verify_hostname:verify_fun/3, [{check_hostname, Hostname}]}, CACerts = certifi:cacerts(), diff --git a/test/rebar_utils_SUITE.erl b/test/rebar_utils_SUITE.erl index 4901f40c..3b111f15 100644 --- a/test/rebar_utils_SUITE.erl +++ b/test/rebar_utils_SUITE.erl @@ -322,6 +322,16 @@ is_list_of_strings(_Config) -> ?assert(rebar_utils:is_list_of_strings("foo") == false). url_append_path(_Config) -> - ?assertEqual({ok, "https://repo.hex.pm:443/repos/org"}, rebar_utils:url_append_path("https://repo.hex.pm", "/repos/org")), - ?assertEqual({ok, "https://repo.hex.pm:443/repos/org?foo=bar"}, rebar_utils:url_append_path("https://repo.hex.pm", - "/repos/org?foo=bar")). + %% OTP version differences + {ok, Val1} = rebar_utils:url_append_path("https://repo.hex.pm", "/repos/org"), + ?assert(lists:member(Val1, [ + "https://repo.hex.pm/repos/org", + "https://repo.hex.pm:443/repos/org" + ])), + {ok, Val2} = rebar_utils:url_append_path("https://repo.hex.pm?foo=bar", "/repos/org"), + ?assert(lists:member(Val2, [ + "https://repo.hex.pm/repos/org?foo=bar", + "https://repo.hex.pm:443/repos/org?foo=bar" + ])), + ?assertEqual({ok, "https://repo.hex.pm:443/repos/org?foo=bar"}, + rebar_utils:url_append_path("https://repo.hex.pm:443?foo=bar", "/repos/org")). From 5b5ea533577571c5f290c1bc8b70076d86f6f985 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 27 Dec 2019 09:33:47 +0300 Subject: [PATCH 2/4] r3_hex_api: make query string encoding warning free on OTP 19 and 23 (cherry picked from commit 1c9e91b80a46014bbc44c4ac1e9739e6fe8b4cf2) --- src/r3_hex_api.erl | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/r3_hex_api.erl b/src/r3_hex_api.erl index a19472f1..d0943f71 100644 --- a/src/r3_hex_api.erl +++ b/src/r3_hex_api.erl @@ -28,12 +28,17 @@ put(Config, Path, Body) -> delete(Config, Path) -> request(Config, delete, Path, undefined). +%% OTP 21+ -ifdef (OTP_RELEASE). - -if(?OTP_RELEASE >= 23). - -compile({nowarn_deprecated_function, [{http_uri, encode, 1}]}). - -endif. --endif. - +encode_query_string(List0) -> + %% uri_string:compose_query/1 only accepts proplists where values are lists + Pairs = lists:map(fun ({K, V}) when is_atom(V) -> {K, atom_to_list(V)}; + ({K, V}) when is_binary(V) -> {K, binary_to_list(V)}; + ({K, V}) when is_integer(V) -> {K, integer_to_list(V)}; + ({K, V}) -> {K, V} + end, List0), + list_to_binary(uri_string:compose_query(Pairs)). +-else. %% @private encode_query_string(List) -> QueryString = @@ -48,6 +53,8 @@ encode_query_string(List) -> end, List)), Encoded = http_uri:encode(QueryString), list_to_binary(Encoded). +-endif. + %% @private build_repository_path(#{api_repository := Repo}, Path) when is_binary(Repo) -> @@ -61,9 +68,20 @@ build_organization_path(#{api_organization := Org}, Path) when is_binary(Org) -> build_organization_path(#{api_organization := undefined}, Path) -> Path. +%% OTP 21+ +-ifdef (OTP_RELEASE). +%% @private +join_path_segments(Segments) -> + Concatenated = join(<<"/">>, Segments), + %% uri_string:recompose/1 accepts path segments as a list, + %% both strings and binaries + list_to_binary(uri_string:recompose(#{path => Concatenated})). +-else. %% @private join_path_segments(Segments) -> erlang:iolist_to_binary(join(<<"/">>, lists:map(fun encode/1, Segments))). +-endif. + %%==================================================================== %% Internal functions @@ -92,10 +110,13 @@ request(Config, Method, Path, Body) when is_binary(Path) and is_map(Config) -> Other end. +%% OTP < 21 +-ifndef (OTP_RELEASE). encode(Binary) when is_binary(Binary) -> encode(binary_to_list(Binary)); encode(String) when is_list(String) -> http_uri:encode(String). +-endif. build_url(Path, #{api_url := URI}) -> <>. From 00ce31836b8209c86e98eb7ac6d9e2ae1713d174 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 27 Dec 2019 11:49:27 +0300 Subject: [PATCH 3/4] Continue transitioning away from http_uri (cherry picked from commit fa577bc46e289b5e1a739df7bd3bf08451579552) --- src/r3_hex_api.erl | 15 ++++-------- src/rebar_hex_repos.erl | 4 ++-- src/rebar_uri.erl | 37 +++++++++++++++++++++++++---- src/rebar_utils.erl | 28 ++-------------------- test/rebar_uri_SUITE.erl | 48 ++++++++++++++++++++++++++++++++++++++ test/rebar_utils_SUITE.erl | 20 ++-------------- 6 files changed, 90 insertions(+), 62 deletions(-) create mode 100644 test/rebar_uri_SUITE.erl diff --git a/src/r3_hex_api.erl b/src/r3_hex_api.erl index d0943f71..31c1ca89 100644 --- a/src/r3_hex_api.erl +++ b/src/r3_hex_api.erl @@ -16,6 +16,8 @@ ]). -define(ERL_CONTENT_TYPE, <<"application/vnd.hex+erlang">>). +-import(rebar_utils, [to_list/1]). + get(Config, Path) -> request(Config, get, Path, undefined). @@ -32,10 +34,7 @@ delete(Config, Path) -> -ifdef (OTP_RELEASE). encode_query_string(List0) -> %% uri_string:compose_query/1 only accepts proplists where values are lists - Pairs = lists:map(fun ({K, V}) when is_atom(V) -> {K, atom_to_list(V)}; - ({K, V}) when is_binary(V) -> {K, binary_to_list(V)}; - ({K, V}) when is_integer(V) -> {K, integer_to_list(V)}; - ({K, V}) -> {K, V} + Pairs = lists:map(fun ({K, V}) -> {to_list(K), to_list(V)} end, List0), list_to_binary(uri_string:compose_query(Pairs)). -else. @@ -43,13 +42,7 @@ encode_query_string(List0) -> encode_query_string(List) -> QueryString = join("&", - lists:map(fun - ({K, V}) when is_atom(V) -> - atom_to_list(K) ++ "=" ++ atom_to_list(V); - ({K, V}) when is_binary(V) -> - atom_to_list(K) ++ "=" ++ binary_to_list(V); - ({K, V}) when is_integer(V) -> - atom_to_list(K) ++ "=" ++ integer_to_list(V) + lists:map(fun ({K, V}) -> to_list(K) ++ "=" ++ to_list(V) end, List)), Encoded = http_uri:encode(QueryString), list_to_binary(Encoded). diff --git a/src/rebar_hex_repos.erl b/src/rebar_hex_repos.erl index 3377d907..7b1aa908 100644 --- a/src/rebar_hex_repos.erl +++ b/src/rebar_hex_repos.erl @@ -96,8 +96,8 @@ update_organizations(Repos) -> {ok, Parent} = get_repo_config(ParentName, Repos), ParentRepoUrl = rebar_utils:to_list(maps:get(repo_url, Parent)), {ok, _RepoUrl} = - rebar_utils:url_append_path(ParentRepoUrl, - filename:join("repos", rebar_utils:to_list(RepoName))), + rebar_uri:append_path(ParentRepoUrl, + filename:join("repos", rebar_utils:to_list(RepoName))), %% still let the organization config override this constructed repo url maps:merge(Parent#{repo_url => rebar_utils:to_binary(ParentRepoUrl)}, Repo); (Repo) -> diff --git a/src/rebar_uri.erl b/src/rebar_uri.erl index 6e28a90d..3a6382b1 100644 --- a/src/rebar_uri.erl +++ b/src/rebar_uri.erl @@ -1,9 +1,14 @@ %%% @doc multi-OTP version compatibility shim for working with URIs -module(rebar_uri). --ifdef (OTP_RELEASE). --export([parse/1]). +-export([ + parse/1, + append_path/2 +]). + +-import(rebar_utils, [to_list/1]). +-ifdef (OTP_RELEASE). -spec parse(URIString) -> URIMap when URIString :: uri_string:uri_string(), URIMap :: uri_string:uri_map() | uri_string:error(). @@ -11,8 +16,6 @@ parse(URIString) -> uri_string:parse(URIString). -else. --export([parse/1]). - -spec parse(URIString) -> URIMap when URIString :: iodata(), URIMap :: map() | {error, atom(), term()}. @@ -26,7 +29,7 @@ parse(URIString) -> {error, Reason, ""}; {ok, {Scheme, UserInfo, Host, Port, Path, Query}} -> #{ - scheme => Scheme, + scheme => rebar_utils:to_list(Scheme), host => Host, port => Port, path => Path, @@ -42,3 +45,27 @@ parse(URIString) -> end. -endif. +%% OTP 21+ +-ifdef (OTP_RELEASE). +append_path(Url, ExtraPath) -> + case parse(Url) of + #{path := Path} = Map -> + FullPath = filename:join(Path, ExtraPath), + {ok, uri_string:recompose(maps:update(path, FullPath, Map))}; + _ -> + error + end. +-else. +append_path(Url, ExtraPath) -> + case parse(Url) of + #{scheme := Scheme, userinfo := UserInfo, host := Host, port := Port, path := Path, query := Query} -> + PrefixedQuery = case Query of + [] -> []; + Other -> lists:append(["?", Other]) + end, + {ok, lists:append([to_list(Scheme), "://", UserInfo, Host, ":", to_list(Port), + filename:join(Path, ExtraPath), PrefixedQuery])}; + _ -> + error + end. +-endif. diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl index 7bfa5ca8..e0ffc0ec 100644 --- a/src/rebar_utils.erl +++ b/src/rebar_utils.erl @@ -64,7 +64,6 @@ tup_find/2, line_count/1, set_httpc_options/0, - url_append_path/2, escape_chars/1, escape_double_quotes/1, escape_double_quotes_weak/1, @@ -266,6 +265,8 @@ to_binary(A) when is_atom(A) -> atom_to_binary(A, unicode); to_binary(Str) -> unicode:characters_to_binary(Str). to_list(A) when is_atom(A) -> atom_to_list(A); +to_list(B) when is_binary(B) -> unicode:characters_to_list(B); +to_list(I) when is_integer(I) -> integer_to_list(I); to_list(Str) -> unicode:characters_to_list(Str). tup_dedup(List) -> @@ -937,31 +938,6 @@ normalise_proxy(Scheme, URI) -> _ -> URI end. -%% OTP 21+ --ifdef (OTP_RELEASE). -url_append_path(Url, ExtraPath) -> - case rebar_uri:parse(Url) of - #{path := Path} = Map -> - FullPath = filename:join(Path, ExtraPath), - {ok, uri_string:recompose(maps:update(path, FullPath, Map))}; - _ -> - error - end. --else. -url_append_path(Url, ExtraPath) -> - case rebar_uri:parse(Url) of - #{scheme := Scheme, userinfo := UserInfo, host := Host, port := Port, path := Path, query := Query} -> - PrefixedQuery = case Query of - [] -> []; - Other -> lists:append(["?", Other]) - end, - {ok, lists:append([atom_to_list(Scheme), "://", UserInfo, Host, ":", integer_to_list(Port), - filename:join(Path, ExtraPath), PrefixedQuery])}; - _ -> - error - end. --endif. - %% escape\ as\ a\ shell\? escape_chars(Str) when is_atom(Str) -> escape_chars(atom_to_list(Str)); diff --git a/test/rebar_uri_SUITE.erl b/test/rebar_uri_SUITE.erl new file mode 100644 index 00000000..4db93690 --- /dev/null +++ b/test/rebar_uri_SUITE.erl @@ -0,0 +1,48 @@ +-module(rebar_uri_SUITE). + +-export([all/0, + parse/1, + append_path/1]). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). +-include_lib("kernel/include/file.hrl"). + +all() -> + [parse]. + +parse(_Config) -> + #{scheme := Scheme, host := Host, path := Path} = rebar_uri:parse("https://repo.hex.pm"), + ?assertEqual("https", Scheme), + ?assertEqual("repo.hex.pm", Host), + ?assert(lists:member(Path, ["", "/"])), + + #{scheme := Scheme2, host := Host2, port := Port2, path := Path2, query := Query2} = + rebar_uri:parse("https://repo.hex.pm:443?foo=bar"), + ?assertEqual("https", Scheme2), + ?assertEqual("repo.hex.pm", Host2), + ?assertEqual(443, Port2), + ?assert(lists:member(Path2, ["", "/"])), + ?assertEqual("foo=bar", Query2), + + #{scheme := Scheme3, host := Host3, path := Path3, query := Query3} = + rebar_uri:parse("https://repo.hex.pm/over/here?foo=bar"), + ?assertEqual("https", Scheme3), + ?assertEqual("repo.hex.pm", Host3), + ?assertEqual("/over/here", Path3), + ?assertEqual("foo=bar", Query3). + +append_path(_Config) -> + %% OTP version differences + {ok, Val1} = rebar_utils:append_path("https://repo.hex.pm", "/repos/org"), + ?assert(lists:member(Val1, [ + "https://repo.hex.pm/repos/org", + "https://repo.hex.pm:443/repos/org" + ])), + {ok, Val2} = rebar_utils:append_path("https://repo.hex.pm?foo=bar", "/repos/org"), + ?assert(lists:member(Val2, [ + "https://repo.hex.pm/repos/org?foo=bar", + "https://repo.hex.pm:443/repos/org?foo=bar" + ])), + ?assertEqual({ok, "https://repo.hex.pm:443/repos/org?foo=bar"}, + rebar_utils:append_path("https://repo.hex.pm:443?foo=bar", "/repos/org")). diff --git a/test/rebar_utils_SUITE.erl b/test/rebar_utils_SUITE.erl index 3b111f15..233fcff3 100644 --- a/test/rebar_utils_SUITE.erl +++ b/test/rebar_utils_SUITE.erl @@ -33,8 +33,7 @@ sh_does_not_miss_messages/1, tup_merge/1, proxy_auth/1, - is_list_of_strings/1, - url_append_path/1]). + is_list_of_strings/1]). -include_lib("common_test/include/ct.hrl"). -include_lib("eunit/include/eunit.hrl"). @@ -50,7 +49,7 @@ all() -> [{group, args_to_tasks}, sh_does_not_miss_messages, tup_merge, - proxy_auth, is_list_of_strings, url_append_path]. + proxy_auth, is_list_of_strings]. groups() -> [{args_to_tasks, [], [empty_arglist, @@ -320,18 +319,3 @@ is_list_of_strings(_Config) -> ?assert(rebar_utils:is_list_of_strings([])), ?assert(rebar_utils:is_list_of_strings("")), ?assert(rebar_utils:is_list_of_strings("foo") == false). - -url_append_path(_Config) -> - %% OTP version differences - {ok, Val1} = rebar_utils:url_append_path("https://repo.hex.pm", "/repos/org"), - ?assert(lists:member(Val1, [ - "https://repo.hex.pm/repos/org", - "https://repo.hex.pm:443/repos/org" - ])), - {ok, Val2} = rebar_utils:url_append_path("https://repo.hex.pm?foo=bar", "/repos/org"), - ?assert(lists:member(Val2, [ - "https://repo.hex.pm/repos/org?foo=bar", - "https://repo.hex.pm:443/repos/org?foo=bar" - ])), - ?assertEqual({ok, "https://repo.hex.pm:443/repos/org?foo=bar"}, - rebar_utils:url_append_path("https://repo.hex.pm:443?foo=bar", "/repos/org")). From 2f4521e8a3cbd71dee899d464340a15628c5c880 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 28 Jan 2020 17:32:31 +0300 Subject: [PATCH 4/4] Undo r3_hex_api changes in favor of erlang/rebar3#2213 (cherry picked from commit 08eb611a3d3e3e5c25c263dcfe74272fd05ba4bc) --- src/r3_hex_api.erl | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/src/r3_hex_api.erl b/src/r3_hex_api.erl index 31c1ca89..a19472f1 100644 --- a/src/r3_hex_api.erl +++ b/src/r3_hex_api.erl @@ -16,8 +16,6 @@ ]). -define(ERL_CONTENT_TYPE, <<"application/vnd.hex+erlang">>). --import(rebar_utils, [to_list/1]). - get(Config, Path) -> request(Config, get, Path, undefined). @@ -30,24 +28,26 @@ put(Config, Path, Body) -> delete(Config, Path) -> request(Config, delete, Path, undefined). -%% OTP 21+ -ifdef (OTP_RELEASE). -encode_query_string(List0) -> - %% uri_string:compose_query/1 only accepts proplists where values are lists - Pairs = lists:map(fun ({K, V}) -> {to_list(K), to_list(V)} - end, List0), - list_to_binary(uri_string:compose_query(Pairs)). --else. + -if(?OTP_RELEASE >= 23). + -compile({nowarn_deprecated_function, [{http_uri, encode, 1}]}). + -endif. +-endif. + %% @private encode_query_string(List) -> QueryString = join("&", - lists:map(fun ({K, V}) -> to_list(K) ++ "=" ++ to_list(V) + lists:map(fun + ({K, V}) when is_atom(V) -> + atom_to_list(K) ++ "=" ++ atom_to_list(V); + ({K, V}) when is_binary(V) -> + atom_to_list(K) ++ "=" ++ binary_to_list(V); + ({K, V}) when is_integer(V) -> + atom_to_list(K) ++ "=" ++ integer_to_list(V) end, List)), Encoded = http_uri:encode(QueryString), list_to_binary(Encoded). --endif. - %% @private build_repository_path(#{api_repository := Repo}, Path) when is_binary(Repo) -> @@ -61,20 +61,9 @@ build_organization_path(#{api_organization := Org}, Path) when is_binary(Org) -> build_organization_path(#{api_organization := undefined}, Path) -> Path. -%% OTP 21+ --ifdef (OTP_RELEASE). -%% @private -join_path_segments(Segments) -> - Concatenated = join(<<"/">>, Segments), - %% uri_string:recompose/1 accepts path segments as a list, - %% both strings and binaries - list_to_binary(uri_string:recompose(#{path => Concatenated})). --else. %% @private join_path_segments(Segments) -> erlang:iolist_to_binary(join(<<"/">>, lists:map(fun encode/1, Segments))). --endif. - %%==================================================================== %% Internal functions @@ -103,13 +92,10 @@ request(Config, Method, Path, Body) when is_binary(Path) and is_map(Config) -> Other end. -%% OTP < 21 --ifndef (OTP_RELEASE). encode(Binary) when is_binary(Binary) -> encode(binary_to_list(Binary)); encode(String) when is_list(String) -> http_uri:encode(String). --endif. build_url(Path, #{api_url := URI}) -> <>.