%%% -*- erlang -*- %%% %%% This file is part of hackney released under the Apache 2 license. %%% See the NOTICE for more information. %%% -module(hackney_util). -export([filter_options/3]). -export([set_option_default/3]). -export([require/1]). -export([maybe_apply_defaults/2]). -export([is_ipv6/1]). -export([privdir/0]). -export([mod_metrics/0]). -export([to_atom/1]). -include("hackney.hrl"). %% @doc filter a proplists and only keep allowed keys -spec filter_options([{atom(), any()} | {raw, any(), any(), any()}], [atom()], Acc) -> Acc when Acc :: [any()]. filter_options([], _, Acc) -> Acc; filter_options([Opt = {Key, _}|Tail], AllowedKeys, Acc) -> case lists:member(Key, AllowedKeys) of true -> filter_options(Tail, AllowedKeys, [Opt|Acc]); false -> filter_options(Tail, AllowedKeys, Acc) end; filter_options([Opt = {raw, _, _, _}|Tail], AllowedKeys, Acc) -> case lists:member(raw, AllowedKeys) of true -> filter_options(Tail, AllowedKeys, [Opt|Acc]); false -> filter_options(Tail, AllowedKeys, Acc) end; filter_options([Opt|Tail], AllowedKeys, Acc) when is_atom(Opt) -> case lists:member(Opt, AllowedKeys) of true -> filter_options(Tail, AllowedKeys, [Opt|Acc]); false -> filter_options(Tail, AllowedKeys, Acc) end. %% @doc set the default options in a proplists if not defined -spec set_option_default(Opts, atom(), any()) -> Opts when Opts :: [{atom(), any()}]. set_option_default(Opts, Key, Value) -> case lists:keymember(Key, 1, Opts) of true -> Opts; false -> [{Key, Value}|Opts] end. %% @doc Start the given applications if they were not already started. -spec require(list(module())) -> ok. require([]) -> ok; require([App|Rest]) -> case application:start(App) of ok -> ok; {error, {already_started, App}} -> ok end, require(Rest). maybe_apply_defaults([], Options) -> Options; maybe_apply_defaults([OptName | Rest], Options) -> case proplists:is_defined(OptName, Options) of true -> maybe_apply_defaults(Rest, Options); false -> {ok, Default} = application:get_env(hackney, OptName), maybe_apply_defaults(Rest, [{OptName, Default} | Options]) end. is_ipv6(Host) -> case inet_parse:address(Host) of {ok, {_, _, _, _, _, _, _, _}} -> true; {ok, {_, _, _, _}} -> false; _ -> case inet:getaddr(Host, inet) of {ok, _} -> false; _ -> case inet:getaddr(Host, inet6) of {ok, _} -> true; _ -> false end end end. privdir() -> case code:priv_dir(hackney) of {error, _} -> %% try to get relative priv dir. useful for tests. EbinDir = filename:dirname(code:which(?MODULE)), AppPath = filename:dirname(EbinDir), filename:join(AppPath, "priv"); Dir -> Dir end. mod_metrics() -> case application:get_env(hackney, mod_metrics) of {ok, folsom} -> hackney_folsom_metrics; {ok, exometer} -> hackney_exometer_metrics; {ok, dummy} -> hackney_dummy_metrics; {ok, Mod} -> _ = code:ensure_loaded(Mod), case erlang:function_exported(Mod, new, 2) of false -> {error, badarg}; true -> Mod end; _ -> hackney_dummy_metrics end. to_atom(V) when is_list(V) -> try list_to_existing_atom(V) catch _:_ -> list_to_atom(V) end; to_atom(V) when is_binary(V) -> to_atom(binary_to_list(V)); to_atom(V) when is_atom(V) -> V.