Packages
oidcc
2.0.0-alpha.1
3.7.2
3.7.1
3.7.0
3.6.0
3.5.2
3.5.1
3.5.0
retired
3.4.0
3.3.0
3.2.6
3.2.5
3.2.4
3.2.3
3.2.2
3.2.1
3.2.0
3.2.0-beta.3
3.2.0-beta.2
retired
3.2.0-beta.1
retired
3.1.2
3.1.2-beta.1
retired
3.1.1
retired
3.1.0
retired
3.1.0-beta.2
retired
3.1.0-beta.1
retired
3.0.2
3.0.1
retired
3.0.0
retired
3.0.0-rc.6
retired
3.0.0-rc.5
retired
3.0.0-rc.4
retired
3.0.0-rc.3
retired
3.0.0-rc.2
retired
3.0.0-rc.1
retired
3.0.0-alpha.5
retired
3.0.0-alpha.4
retired
3.0.0-alpha.3
retired
3.0.0-alpha.2
retired
3.0.0-alpha.1
retired
2.0.0-alpha.2
retired
2.0.0-alpha.1
retired
1.8.1
retired
1.8.0
retired
1.7.0
retired
1.6.0
retired
1.5.1
retired
1.5.0
retired
1.4.0
retired
1.3.0
retired
1.2.1
retired
1.2.0
retired
1.1.0
retired
1.0.1
retired
1.0.0
retired
OpenID Connect client library for the BEAM.
Retired package: Security issue - Affected by hackney / CVE-2025-1211
Current section
Files
Jump to
Current section
Files
src/oidcc_http_util.erl
-module(oidcc_http_util).
-export([async_http/3, async_http/5]).
-export([sync_http/3, sync_http/5]).
-export([sync_http/4, sync_http/6]).
-export([uncompress_body_if_needed/2]).
-export([request_timeout/1]).
-include_lib("public_key/include/public_key.hrl").
sync_http(Method, Url, Header) ->
sync_http(Method, Url, Header, false).
sync_http(Method, Url, Header, ContentType, Body) ->
sync_http(Method, Url, Header, ContentType, Body, false).
sync_http(Method, Url, Header, UseCache) ->
perform_request(Method, Url, Header, undefined, <<>>, [], UseCache).
sync_http(Method, Url, Header, ContentType, Body, UseCache) ->
perform_request(Method, Url, Header, ContentType, Body, [], UseCache).
async_http(Method, Url, Header) ->
async_http(Method, Url, Header, undefined, <<>>).
async_http(Method, Url, Header, ContentType, Body) ->
RequestId = erlang:make_ref(),
Caller = self(),
spawn_link(fun() ->
async_http_perform(Caller, RequestId, Method, Url, Header, ContentType, Body)
end),
{ok, RequestId}.
async_http_perform(Caller, RequestId, Method, Url, Header, ContentType, Body) ->
Response =
case perform_request(Method, Url, Header, ContentType, Body, [], false) of
{error, _} = Error ->
Error;
{ok,
#{status := StatusCode,
header := RespHeaders,
body := InBody}} ->
{{<<>>, StatusCode, <<>>}, RespHeaders, InBody}
end,
Caller ! {http, {RequestId, Response}}.
request_timeout(Unit) ->
Timeout =
case application:get_env(oidcc, http_request_timeout, undefined) of
T when is_integer(T), T > 0 ->
T;
_ ->
300
end,
case Unit of
ms ->
Timeout * 1000;
s ->
Timeout
end.
perform_request(Method, Url, Header, ContentType, Body, Options, true) ->
case oidcc_http_cache:lookup_http_call(Method, {Method, Url, Header, ContentType, Body})
of
{ok, pending} ->
wait_for_cache(Method, {Method, Url, Header, ContentType, Body});
{ok, Res} ->
Res;
{error, _} ->
request_or_wait(Method, Url, Header, ContentType, Body, Options)
end;
perform_request(Method, Url, Header, ContentType, Body, Options, false) ->
perform_http_request(Method, Url, Header, ContentType, Body, Options).
perform_http_request(Method, Url, Header, ContentType, Body, Options) ->
Headers1 =
case ContentType of
undefined ->
Header;
_ ->
[{<<"content-type">>, ContentType} | Header]
end,
Res = hackney:request(Method, Url, Headers1, Body, Options ++ [{follow_redirect, true}]),
normalize_result(Res).
request_or_wait(Method, Url, Header, ContentType, Body, Options) ->
case oidcc_http_cache:enqueue_http_call(Method, {Method, Url, Header, ContentType, Body})
of
true ->
Result = perform_http_request(Method, Url, Header, ContentType, Body, Options),
ok =
oidcc_http_cache:cache_http_result(Method,
{Method, Url, Header, ContentType, Body},
Result),
Result;
_ ->
wait_for_cache(Method, {Method, Url, Header, ContentType, Body})
end.
wait_for_cache(Method, Request) ->
case oidcc_http_cache:lookup_http_call(Method, Request) of
{ok, pending} ->
timer:sleep(500),
wait_for_cache(Method, Request);
{ok, Result} ->
Result
end.
normalize_result({ok, StatusCode, RespHeaders, ClientRef}) ->
{ok, Body} = hackney:body(ClientRef),
{ok,
#{status => StatusCode,
header => RespHeaders,
body => Body}};
normalize_result({ok, StreamId}) ->
{ok, StreamId};
normalize_result({error, _} = Error) ->
Error.
uncompress_body_if_needed(Body, Header) when is_list(Header) ->
Encoding = lists:keyfind(<<"content-encoding">>, 1, Header),
uncompress_body_if_needed(Body, Encoding);
uncompress_body_if_needed(Body, false) ->
{ok, Body};
uncompress_body_if_needed(Body, {_, <<"gzip">>}) ->
{ok, zlib:gunzip(Body)};
uncompress_body_if_needed(Body, {_, <<"deflate">>}) ->
Z = zlib:open(),
ok = zlib:inflateInit(Z),
{ok, zlib:inflate(Z, Body)};
uncompress_body_if_needed(_Body, {_, Compression}) ->
erlang:error({unsupported_encoding, Compression}).