Packages
hackney
1.17.2
4.7.2
4.7.1
4.7.0
4.6.1
4.6.0
4.5.2
4.5.1
4.5.0
4.4.5
4.4.3
4.4.2
4.4.1
4.4.0
4.3.0
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.3
4.0.2
4.0.1
4.0.0
3.2.1
3.2.0
3.1.2
3.1.1
3.1.0
3.0.3
3.0.2
3.0.1
3.0.0
retired
2.0.1
2.0.0
2.0.0-beta.1
1.25.0
1.24.1
1.24.0
1.23.0
1.22.0
1.21.0
1.20.1
1.20.0
1.19.1
1.19.0
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.0
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.0
1.13.0
1.12.1
1.12.0
1.11.0
1.10.1
1.10.0
1.9.0
1.8.6
1.8.5
1.8.4
1.8.3
1.8.2
1.8.0
1.7.1
1.7.0
1.6.6
retired
1.6.5
1.6.4
retired
1.6.3
1.6.2
1.6.1
1.6.0
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.10
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.6
1.0.5
1.0.2
1.0.1
0.15.2
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
Simple HTTP client with HTTP/1.1, HTTP/2, and HTTP/3 support
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
src/hackney_connections.erl
%%% -*- erlang -*-
%%%
%%% This file is part of hackney released under the Apache 2 license.
%%% See the NOTICE for more information
-module(hackney_connections).
-behaviour(gen_server).
%% API
-export([
insert/2,
lookup/1,
delete/1,
get_num_entries/0
]).
-export([start_link/0]).
-export([init/1,
handle_call/3,
handle_cast/2,
handle_info/2,
code_change/3,
terminate/2]).
-include("hackney.hrl").
-define(SERVER, ?MODULE).
-record(state, {tab,lru}).
-define(MAX_ITEMS, 1000).
insert(Key, Id) ->
gen_server:call(?SERVER, {insert, Key, Id}).
lookup(Key) ->
gen_server:call(?SERVER, {lookup, Key}).
delete(Key) ->
gen_server:call(?SERVER, {delete, Key}).
get_num_entries() ->
gen_server:call(?SERVER, num_entries).
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
init([]) ->
Tab = ets:new(?SERVER, [set, {read_concurrency, true}]),
{ok, #state{tab=Tab, lru=new_lrulist()}}.
handle_call({insert, Key, Id}, From, #state{tab=Tab, lru=Lru} = State) ->
true = ets:insert(Tab, {Key, Id}),
gen_server:reply(From, true),
Lru2 = push(Key, Lru),
NewState = case has_exceeded(State) of
true ->
evict(State#state{lru=Lru2});
false ->
State#state{lru=Lru2 }
end,
{noreply, NewState};
handle_call({lookup, Key}, From, State = #state{tab=Tab, lru=Lru}) ->
case ets:lookup(Tab, Key) of
[{Key, Id}] ->
gen_server:reply(From, {ok, Id}),
Lru2 = touch(Key, Lru),
{noreply, State#state{lru=Lru2}};
[] ->
{reply, error, State}
end;
handle_call({delete, Key}, From, State = #state{tab=Tab, lru=Lru}) ->
_ = ets:delete(Tab, Key),
gen_server:reply(From, ok),
Lru2 = drop(Key, Lru),
{reply, true, State#state{lru=Lru2}};
handle_call(num_entries, _From, State = #state{tab=Tab}) ->
{reply, ets:info(Tab, size) , State};
handle_call(_Msg, _From, State) ->
{reply, {error, bad_call}, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
terminate(_Reason, _State) ->
ok.
has_exceeded(#state{ tab = Tab}) ->
(ets:info(Tab, size) > ?MAX_ITEMS).
evict(State = #state{tab=Tab, lru=Lru}) ->
case pop(Lru) of
{ok, Key, Lru2} ->
_ = ets:delete(Tab, Key),
State#state{lru=Lru2};
empty ->
State
end.
%% ========
%% LRU LIST
new_lrulist() -> [].
push(LruElement, LruList) ->
case lists:member(LruElement, LruList) of
true -> LruList;
false -> LruList ++ [LruElement]
end.
pop([]) -> empty;
pop([ El | Rest] ) -> {ok, El, Rest}.
touch(LruElement, [LruElement|Rest]) ->
Rest ++ [LruElement];
touch(LruElement, [H|Rest]) ->
[H|touch(LruElement, Rest)];
touch(LruElement, []) ->
[LruElement].
drop(LruElement, LruList) ->
lists:delete(LruElement, LruList).