Current section

Files

Jump to
aws_http src aws_http.erl
Raw

src/aws_http.erl

-module(aws_http).
-include("../src/aws_http.hrl").
-export([post/5, put/5, get/5, delete/4, req/7]).
%% Application api
-ignore_xref([post/5, put/5, get/5, delete/4, req/7]).
%% apply
-export([default_decode/3]).
-ignore_xref([default_decode/3]).
post(Path, Headers, Payload0, Callback, Opts) ->
Payload = encode_payload(Payload0, Opts),
req("POST", Path, [], Headers, Payload, Callback, Opts).
put(Path, Headers, Payload0, Callback, Opts) ->
Payload = encode_payload(Payload0, Opts),
req("PUT", Path, [], Headers, Payload, Callback, Opts).
get(Path, QueryString, Headers, Callback, Opts) ->
req("GET", Path, QueryString, Headers, <<"">>, Callback, Opts).
delete(Path, Headers, Callback, Opts) ->
req("DELETE", Path, [], Headers, <<"">>, Callback, Opts).
req(Method, Path0, QueryString, Headers, Payload, Callback, Opts) ->
Retry = aws_http_retry:init(Opts),
req(Method, Path0, QueryString, Headers, Payload, Callback,
Retry, Opts).
req(Method, Path0, QueryString, Headers, Payload, Callback, Retry, Opts) ->
Path = mk_req_path(Path0, QueryString),
Service = Callback:service_name(),
Conf = get_conf(Service, Opts),
URL = proplists:get_value(host, Opts, Conf#aws_conf.base_url) ++ Path,
NewHeaders = mk_headers(Conf, Method, Path0, QueryString, Headers, Payload),
HttpResp = do_call(URL, Method, NewHeaders, Payload, Opts),
case aws_http_retry:should(Retry, HttpResp, Callback) of
true ->
{Sleep, NewRetry} = aws_http_retry:backoff(Retry),
timer:sleep(Sleep),
req(Method, Path0, QueryString, Headers, Payload, Callback,
NewRetry, Opts);
false ->
HttpResp
end.
%% ---------------------------------------------------------------------------
%% Internal
mk_req_path(Path0, QueryString) ->
Path1 = string:join(["" | Path0], "/"),
LQueryString = string:join(
[K ++ "=" ++ V ||
{K, V} <- QueryString], "&"),
maybe_add_querystring(Path1, LQueryString).
maybe_add_querystring(Path0, []) -> Path0;
maybe_add_querystring(Path0, Qs) -> Path0 ++ "?" ++ Qs.
do_call(URL, Method, Headers, Payload, Opts) ->
HttpTimeout = proplists:get_value(http_timeout, Opts, 5000),
%% FIXME: Handle lhttpcs error messages.
HttpResp = lhttpc:request(URL, Method, Headers, Payload, HttpTimeout),
decode_http_resp(HttpResp, Opts).
get_conf(Service, Opts) ->
ProfileName = proplists:get_value(profile, Opts, default),
aws_http_cfg:get(ProfileName, Service).
mk_headers(Conf, Method, Path, QueryString, Headers0, Payload) ->
Headers = Headers0 ++ [{"Host", Conf#aws_conf.endpoint}],
aws_http_auth_v4:sign_v4(Method, Path, QueryString, Conf, Headers, Payload).
encode_payload(Payload, Opts) ->
case proplists:get_value(request_body_encode, Opts, {jiffy, encode, []}) of
none -> Payload;
{M, F, Args} -> erlang:apply(M, F, [Payload|Args])
end.
decode_http_resp({ok, {{Code, Msg}, Hdrs, Body}}, Opts) ->
case proplists:get_value(response_body_decode, Opts,
{aws_http, default_decode, []}) of
none -> {ok, {{Code, Msg}, Hdrs, Body}};
{M, F, Args} ->
NewBody = erlang:apply(M, F, [Code, Body,Hdrs|Args]),
{ok, {{Code, Msg}, Hdrs, NewBody}}
end;
decode_http_resp({error, Rsn}, _Opts) -> {error, Rsn}.
default_decode(Code, Body, Headers) ->
case {lists:member(Code, [204, 304]),
proplists:get_value("Content-Type", Headers)} of
{false, "application/json"} -> jiffy:decode(Body, [return_maps]);
{_, _} -> Body
end.