Packages
erlcloud
3.1.1
3.8.3
3.8.2
3.8.1
3.7.6
3.7.4
3.7.3
3.7.2
3.7.1
3.7.0
3.6.8
3.6.7
3.6.5
3.6.4
3.6.3
3.6.2
3.6.1
3.6.0
3.5.16
3.5.15
3.5.14
3.5.13
3.5.12
3.5.11
3.5.10
3.5.9
3.5.8
3.5.7
3.5.6
3.5.5
3.5.4
3.5.3
3.5.2
3.5.1
3.5.0
3.4.5
3.4.3
3.4.1
3.4.0
3.3.9
3.3.8
3.3.7
3.3.6
3.3.5
3.3.4
3.3.3
3.3.2
3.3.1
3.3.0
3.2.18
3.2.17
3.2.16
3.2.15
3.2.14
3.2.13
3.2.12
3.2.11
3.2.10
3.2.7
3.2.6
3.2.5
3.2.4
3.2.3
3.2.2
3.2.1
3.2.0
3.1.17
3.1.16
3.1.14
3.1.13
3.1.12
3.1.11
3.1.9
3.1.8
3.1.7
3.1.6
3.1.5
3.1.4
3.1.3
3.1.2
3.1.1
3.1.0
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
2.2.16
2.2.15
2.2.14
2.2.13
2.2.12
2.2.11
2.2.10
2.2.9
2.2.8
2.2.7
2.2.6
2.2.5
2.2.4
2.2.2
2.2.1
2.2.0
2.1.0
2.0.5
2.0.4
2.0.3
2.0.0
0.13.10
0.13.9
0.13.8
0.13.6
0.13.5
0.13.4
0.13.3
0.13.2
0.13.0
0.12.0
0.11.0
0.9.2
0.9.2-rc.1
0.9.1
0.9.0
AWS APIs library for Erlang
Current section
Files
Jump to
Current section
Files
src/erlcloud_httpc.erl
%% @author Ransom Richardson <ransom@ransomr.net>
%% @doc
%%
%% HTTP client abstraction for erlcloud. Simplifies changing http clients.
%% API matches lhttpc, except Config is passed instead of options for
%% future cusomizability.
%%
%% @end
-module(erlcloud_httpc).
-include("erlcloud_aws.hrl").
-export([request/6]).
-type request_fun() ::
lhttpc | httpc | hackney |
{module(), atom()} |
fun((string(),
head | get | put | post | trace | options | delete,
list({binary(), binary()}),
binary(), pos_integer(), #aws_config{}) ->
{ok, {{pos_integer(), string()},
list({string(), string()}), binary()}} |
{error, any()}).
-export_type([request_fun/0]).
request(URL, Method, Hdrs, Body, Timeout,
#aws_config{http_client = lhttpc} = Config) ->
request_lhttpc(URL, Method, Hdrs, Body, Timeout, Config);
request(URL, Method, Hdrs, Body, Timeout,
#aws_config{http_client = httpc} = Config) ->
request_httpc(URL, Method, Hdrs, Body, Timeout, Config);
request(URL, Method, Hdrs, Body, Timeout,
#aws_config{http_client = hackney} = Config) ->
request_hackney(URL, Method, Hdrs, Body, Timeout, Config);
request(URL, Method, Hdrs, Body, Timeout,
#aws_config{http_client = {M, F}} = Config)
when is_atom(M), is_atom(F) ->
M:F(URL, Method, Hdrs, Body, Timeout, Config);
request(URL, Method, Hdrs, Body, Timeout,
#aws_config{http_client = F} = Config)
when is_function(F, 6) ->
F(URL, Method, Hdrs, Body, Timeout, Config).
request_lhttpc(URL, Method, Hdrs, Body, Timeout, #aws_config{lhttpc_pool = undefined}) ->
lhttpc:request(URL, Method, Hdrs, Body, Timeout, []);
request_lhttpc(URL, Method, Hdrs, Body, Timeout, #aws_config{lhttpc_pool = Pool}) ->
LHttpcOpts = [{pool, Pool}, {pool_ensure, true}],
lhttpc:request(URL, Method, Hdrs, Body, Timeout, LHttpcOpts).
%% Guard clause protects against empty bodied requests from being
%% unable to find a matching httpc:request call.
request_httpc(URL, Method, Hdrs, <<>>, Timeout, _Config)
when (Method =:= options) orelse
(Method =:= get) orelse
(Method =:= head) orelse
(Method =:= delete) orelse
(Method =:= trace) ->
HdrsStr = [{to_list_string(K), to_list_string(V)} || {K, V} <- Hdrs],
response_httpc(httpc:request(Method, {URL, HdrsStr},
[{timeout, Timeout}],
[{body_format, binary}]));
request_httpc(URL, Method, Hdrs, Body, Timeout, _Config) ->
HdrsStr = [{to_list_string(K), to_list_string(V)} || {K, V} <- Hdrs],
{"content-type", ContentType} = lists:keyfind("content-type", 1, HdrsStr),
response_httpc(httpc:request(Method,
{URL, HdrsStr,
ContentType, Body},
[{timeout, Timeout}],
[{body_format, binary}])).
request_hackney(URL, Method, Hdrs, Body, Timeout, #aws_config{hackney_pool = Pool}) ->
BinURL = to_binary(URL),
BinHdrs = [{to_binary(K), to_binary(V)} || {K, V} <- Hdrs],
PoolOpt = if Pool =:= undefined ->
[];
true ->
[{pool, Pool}]
end,
response_hackney(hackney:request(Method,
BinURL, BinHdrs,
Body,
[{recv_timeout, Timeout}] ++ PoolOpt)).
response_httpc({ok, {{_HTTPVer, Status, StatusLine}, Headers, Body}}) ->
{ok, {{Status, StatusLine}, Headers, Body}};
response_httpc({error, _} = Error) ->
Error.
response_hackney({ok, Status, Hdrs}) ->
HdrsStr = header_str(Hdrs),
{ok, {{Status, undefined}, HdrsStr, undefined}};
response_hackney({ok, Status, Hdrs, Ref}) ->
case hackney:body(Ref) of
{ok, Body} ->
HdrsStr = header_str(Hdrs),
{ok, {{Status, undefined}, HdrsStr, Body}};
{error, Reason} when Status >= 200, Status =< 299 ->
{error, {hackney_error, Reason}};
{error, _} ->
HdrsStr = header_str(Hdrs),
{ok, {{Status, undefined}, HdrsStr, undefined}}
end;
response_hackney({error, _} = Error) ->
Error.
header_str(Hdrs) ->
[{string:to_lower(to_list_string(K)), to_list_string(V)} || {K, V} <- Hdrs].
to_list_string(Val) when erlang:is_binary(Val) ->
erlang:binary_to_list(Val);
to_list_string(Val) when erlang:is_list(Val) ->
Val.
to_binary(Val) when erlang:is_list(Val) ->
erlang:list_to_binary(Val);
to_binary(Val) when erlang:is_binary(Val) ->
Val.