aboutsummaryrefslogtreecommitdiffstats
path: root/lib/inets/src/http_client
diff options
context:
space:
mode:
Diffstat (limited to 'lib/inets/src/http_client')
-rw-r--r--lib/inets/src/http_client/httpc.erl26
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl27
-rw-r--r--lib/inets/src/http_client/httpc_manager.erl197
3 files changed, 189 insertions, 61 deletions
diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl
index f4802fb96d..b6e7708353 100644
--- a/lib/inets/src/http_client/httpc.erl
+++ b/lib/inets/src/http_client/httpc.erl
@@ -39,6 +39,7 @@
cookie_header/1, cookie_header/2, cookie_header/3,
which_cookies/0, which_cookies/1,
reset_cookies/0, reset_cookies/1,
+ which_sessions/0, which_sessions/1,
stream_next/1,
default_profile/0,
profile_name/1, profile_name/2,
@@ -267,6 +268,7 @@ set_option(Key, Value, Profile) ->
%% Reason - term()
%% Description: Retrieves the current options.
%%-------------------------------------------------------------------------
+
get_options() ->
record_info(fields, options).
@@ -373,8 +375,6 @@ cookie_header(Url, Opts, Profile)
{error, {not_started, Profile}}
end.
-
-
%%--------------------------------------------------------------------------
%% which_cookies() -> [cookie()]
@@ -398,6 +398,28 @@ which_cookies(Profile) ->
%%--------------------------------------------------------------------------
+%% which_sessions() -> {GoodSession, BadSessions, NonSessions}
+%% which_sessions(Profile) -> {GoodSession, BadSessions, NonSessions}
+%%
+%% Description: Debug function, dumping the sessions database, sorted
+%% into three groups (Good-, Bad- and Non-sessions).
+%%-------------------------------------------------------------------------
+which_sessions() ->
+ which_sessions(default_profile()).
+
+which_sessions(Profile) ->
+ ?hcrt("which sessions", [{profile, Profile}]),
+ try
+ begin
+ httpc_manager:which_sessions(profile_name(Profile))
+ end
+ catch
+ exit:{noproc, _} ->
+ {[], [], []}
+ end.
+
+
+%%--------------------------------------------------------------------------
%% info() -> list()
%% info(Profile) -> list()
%%
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index fb6879bf4d..923213d34d 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -1713,7 +1713,32 @@ update_session(ProfileName, #session{id = SessionId} = Session, Pos, Value) ->
catch
error:undef -> % This could happen during code upgrade
Session2 = erlang:setelement(Pos, Session, Value),
- insert_session(Session2, ProfileName)
+ insert_session(Session2, ProfileName);
+ T:E ->
+ error_logger:error_msg("Failed updating session: "
+ "~n ProfileName: ~p"
+ "~n SessionId: ~p"
+ "~n Pos: ~p"
+ "~n Value: ~p"
+ "~nwhen"
+ "~n Session (db) info: ~p"
+ "~n Session (db): ~p"
+ "~n Session (record): ~p"
+ "~n T: ~p"
+ "~n E: ~p",
+ [ProfileName, SessionId, Pos, Value,
+ (catch httpc_manager:which_session_info(ProfileName)),
+ Session,
+ (catch httpc_manager:lookup_session(ProfileName, SessionId)),
+ T, E]),
+ exit({failed_updating_session,
+ [{profile, ProfileName},
+ {session_id, SessionId},
+ {pos, Pos},
+ {value, Value},
+ {etype, T},
+ {error, E},
+ {stacktrace, erlang:get_stacktrace()}]})
end.
diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl
index b225b43214..3612b331e7 100644
--- a/lib/inets/src/http_client/httpc_manager.erl
+++ b/lib/inets/src/http_client/httpc_manager.erl
@@ -34,8 +34,11 @@
retry_request/2,
redirect_request/2,
insert_session/2,
+ lookup_session/2,
update_session/4,
delete_session/2,
+ which_sessions/1,
+ which_session_info/1,
set_options/2,
get_options/2,
store_cookies/3,
@@ -59,17 +62,9 @@
options = #options{}
}).
--record(handler_info,
- {
- id, % Id of the request: request_id()
- starter, % Pid of the handler starter process (temp): pid()
- handler, % Pid of the handler process: pid()
- from, % From for the request: from()
- state % State of the handler: initiating | started | operational | canceled
- }).
-
-define(DELAY, 500).
+
%%====================================================================
%% Internal Application API
%%====================================================================
@@ -195,13 +190,28 @@ insert_session(Session, ProfileName) ->
%%--------------------------------------------------------------------
+%% Function: lookup_session(SessionId, ProfileName) -> _
+%% SessionId - term()
+%% ProfileName - atom()
+%%
+%% Description: Looks up a session record in the httpc manager
+%% table <ProfileName>__session_db.
+%%--------------------------------------------------------------------
+
+lookup_session(SessionId, ProfileName) ->
+ SessionDbName = session_db_name(ProfileName),
+ ?hcrt("lookup session", [{session_id, SessionId}, {profile, ProfileName}]),
+ ets:lookup(SessionDbName, SessionId).
+
+
+%%--------------------------------------------------------------------
%% Function: update_session(ProfileName, SessionId, Pos, Value) -> _
%% Session - #session{}
%% ProfileName - atom()
%%
%% Description: Update, only one field (Pos) of the session record
%% identified by the SessionId, the session information
-%% of the httpc manager table <ProfileName>_session_db.
+%% of the httpc manager table <ProfileName>__session_db.
%% Intended to be called by the httpc request handler process.
%%--------------------------------------------------------------------
@@ -216,12 +226,12 @@ update_session(ProfileName, SessionId, Pos, Value) ->
%%--------------------------------------------------------------------
-%% Function: delete_session(SessionId, ProfileName) -> _
+%% Function: delete_session(SessionId, ProfileName) -> void()
%% SessionId - {{Host, Port}, HandlerPid}
%% ProfileName - atom()
%%
%% Description: Deletes session information from the httpc manager
-%% table httpc_manager_session_db_<Profile>. Intended to be called by
+%% table <ProfileName>__session_db. Intended to be called by
%% the httpc request handler process.
%%--------------------------------------------------------------------
@@ -232,6 +242,57 @@ delete_session(SessionId, ProfileName) ->
%%--------------------------------------------------------------------
+%% Function: which sessions(ProfileName) -> SessionsInfo
+%% ProfileName - atom()
+%% SessionsInfo - {GoodSessions, BadSessions, NonSessions}
+%% GoodSessions - [#session{}]
+%% BadSessions - [tuple()]
+%% NonSessions - [term()]
+%%
+%% Description: Produces a list of all sessions in the session db.
+%% Used for debugging and since that is the intent, there is some
+%% checking and transforming done, which produces the results.
+%%--------------------------------------------------------------------
+
+which_sessions(ProfileName) ->
+ ?hcrt("which_sessions", [{profile, ProfileName}]),
+ SessionDbName = session_db_name(ProfileName),
+ which_sessions2(SessionDbName).
+
+which_sessions2(SessionDbName) ->
+ Sessions = which_sessions_order(ets:tab2list(SessionDbName)),
+ GoodSessions = [GoodSession || {good_session, GoodSession} <- Sessions],
+ BadSessions = [BadSession || {bad_session, BadSession} <- Sessions],
+ NonSessions = [NonSession || {non_session, NonSession} <- Sessions],
+ {lists:keysort(#session.id, GoodSessions),
+ lists:keysort(#session.id, BadSessions),
+ lists:sort(NonSessions)}.
+
+which_sessions_order([]) ->
+ [];
+which_sessions_order([Session|Sessions]) when is_record(Session, session) ->
+ [{good_session, Session} | which_sessions_order(Sessions)];
+which_sessions_order([BadSession|Sessions])
+ when is_tuple(BadSession) andalso
+ (element(1, BadSession) =:= session) ->
+ [{bad_session, BadSession} | which_sessions_order(Sessions)];
+which_sessions_order([NonSession|Sessions]) ->
+ [{non_session, NonSession} | which_sessions_order(Sessions)].
+
+
+%%--------------------------------------------------------------------
+%% Function: which session_info(ProfileName) -> list()
+%%
+%% Description: Produces a ets table info list of the sessions table
+%%--------------------------------------------------------------------
+
+which_session_info(ProfileName) ->
+ SessionDbName = session_db_name(ProfileName),
+ ?hcrt("which_session_info", [{profile, ProfileName}]),
+ ets:info(SessionDbName).
+
+
+%%--------------------------------------------------------------------
%% Function: set_options(Options, ProfileName) -> ok
%%
%% Options = [Option]
@@ -379,8 +440,7 @@ do_init(ProfileName, CookiesDir) ->
%% Create handler db
?hcrt("create handler/request db", []),
HandlerDbName = handler_db_name(ProfileName),
- ets:new(HandlerDbName,
- [protected, set, named_table, {keypos, #handler_info.id}]),
+ ets:new(HandlerDbName, [protected, set, named_table, {keypos, 1}]),
%% Cookie DB
?hcrt("create cookie db", []),
@@ -414,9 +474,10 @@ handle_call({request, Request}, _, State) ->
{stop, Error, httpc_response:error(Request, Error), State}
end;
-handle_call({cancel_request, RequestId}, From, State) ->
+handle_call({cancel_request, RequestId}, From,
+ #state{handler_db = HandlerDb} = State) ->
?hcri("cancel_request", [{request_id, RequestId}]),
- case ets:lookup(State#state.handler_db, RequestId) of
+ case ets:lookup(HandlerDb, RequestId) of
[] ->
%% The request has allready compleated make sure
%% it is deliverd to the client process queue so
@@ -428,9 +489,9 @@ handle_call({cancel_request, RequestId}, From, State) ->
{noreply, State};
[{_, Pid, _}] ->
httpc_handler:cancel(RequestId, Pid, From),
- {noreply, State#state{cancel =
- [{RequestId, Pid, From} |
- State#state.cancel]}}
+ {noreply,
+ State#state{cancel =
+ [{RequestId, Pid, From} | State#state.cancel]}}
end;
handle_call(reset_cookies, _, #state{cookie_db = CookieDb} = State) ->
@@ -457,8 +518,8 @@ handle_call({which_cookies, Url, Options}, _,
handle_call({get_options, OptionItems}, _, #state{options = Options} = State) ->
?hcrv("get options", [{option_items, OptionItems}]),
- Reply = [{OptionItem, get_option(OptionItem, Options)} || OptionItem <-
- OptionItems],
+ Reply = [{OptionItem, get_option(OptionItem, Options)} ||
+ OptionItem <- OptionItems],
{reply, Reply, State};
handle_call(info, _, State) ->
@@ -645,7 +706,7 @@ code_change(_,
code_change(_, State, _) ->
{ok, State}.
-%% This function is to catch everything that calls through the cracks...
+%% This function is used to catch everything that falls through the cracks...
update_session_table(SessionDB, Transform) ->
ets:safe_fixtable(SessionDB, true),
update_session_table(SessionDB, ets:first(SessionDB), Transform),
@@ -673,40 +734,56 @@ update_session_table(SessionDB, Key, Transform) ->
%%--------------------------------------------------------------------
get_manager_info(#state{handler_db = HDB,
- cookie_db = CDB} = _State) ->
+ session_db = SDB,
+ cookie_db = CDB,
+ options = Options} = _State) ->
HandlerInfo = get_handler_info(HDB),
+ SessionInfo = which_sessions2(SDB),
+ OptionsInfo =
+ [{Item, get_option(Item, Options)} ||
+ Item <- record_info(fields, options)],
CookieInfo = httpc_cookie:which_cookies(CDB),
- [{handlers, HandlerInfo}, {cookies, CookieInfo}].
+ [{handlers, HandlerInfo},
+ {sessions, SessionInfo},
+ {options, OptionsInfo},
+ {cookies, CookieInfo}].
+
+sort_handlers(Unsorted) ->
+ sort_handlers2(lists:keysort(1, Unsorted)).
+
+sort_handlers2([]) ->
+ [];
+sort_handlers2([{HandlerPid, RequestId}|L]) ->
+ {Handler, Rest} = sort_handlers2(HandlerPid, [RequestId], L),
+ [Handler | sort_handlers2(Rest)].
+
+sort_handlers2(HandlerPid, Reqs, []) ->
+ {{HandlerPid, lists:sort(Reqs)}, []};
+sort_handlers2(HandlerPid, Reqs, [{HandlerPid, ReqId}|Rest]) ->
+ sort_handlers2(HandlerPid, [ReqId|Reqs], Rest);
+sort_handlers2(HandlerPid1, Reqs, [{HandlerPid2, _}|_] = Rest)
+ when HandlerPid1 =/= HandlerPid2 ->
+ {{HandlerPid1, lists:sort(Reqs)}, Rest}.
get_handler_info(Tab) ->
- Pattern = #handler_info{handler = '$1',
- state = '$2',
- _ = '_'},
- Handlers1 = [{Pid, State} || [Pid, State] <- ets:match(Tab, Pattern)],
- F = fun({Pid, State} = Elem, Acc) when State =/= canceled ->
- case lists:keymember(Pid, 1, Acc) of
- true ->
- Acc;
- false ->
- [Elem | Acc]
- end;
- (_, Acc) ->
- Acc
- end,
- Handlers2 = lists:foldl(F, [], Handlers1),
- Handlers3 = [{Pid, State,
- case (catch httpc_handler:info(Pid)) of
- {'EXIT', _} ->
+ Pattern = {'$2', '$1', '_'},
+ Handlers1 = [{Pid, Id} || [Pid, Id] <- ets:match(Tab, Pattern)],
+ Handlers2 = sort_handlers(Handlers1),
+ Handlers3 = [{Pid, Reqs,
+ try
+ begin
+ httpc_handler:info(Pid)
+ end
+ catch
+ _:_ ->
%% Why would this crash?
%% Only if the process has died, but we don't
%% know about it?
- [];
- Else ->
- Else
- end} ||
- {Pid, State} <- Handlers2],
+ []
+ end} || {Pid, Reqs} <- Handlers2],
Handlers3.
+
handle_request(#request{settings =
#http_options{version = "HTTP/0.9"}} = Request,
State) ->
@@ -758,19 +835,21 @@ handle_request(Request, State = #state{options = Options}) ->
{reply, {ok, NewRequest#request.id}, State}.
-start_handler(Request, State) ->
+start_handler(#request{id = Id,
+ from = From} = Request,
+ #state{profile_name = ProfileName,
+ handler_db = HandlerDb,
+ options = Options}) ->
{ok, Pid} =
case is_inets_manager() of
true ->
httpc_handler_sup:start_child([whereis(httpc_handler_sup),
- Request, State#state.options,
- State#state.profile_name]);
+ Request, Options, ProfileName]);
false ->
- httpc_handler:start_link(self(), Request, State#state.options,
- State#state.profile_name)
+ httpc_handler:start_link(self(), Request, Options, ProfileName)
end,
- ets:insert(State#state.handler_db, {Request#request.id,
- Pid, Request#request.from}),
+ HandlerInfo = {Id, Pid, From},
+ ets:insert(HandlerDb, HandlerInfo),
erlang:monitor(process, Pid).
@@ -827,12 +906,14 @@ select_session(Candidates, Max) ->
{ok, HandlerPid}
end.
-pipeline_or_keep_alive(Request, HandlerPid, State) ->
+pipeline_or_keep_alive(#request{id = Id,
+ from = From} = Request,
+ HandlerPid,
+ #state{handler_db = HandlerDb} = State) ->
case (catch httpc_handler:send(Request, HandlerPid)) of
ok ->
- ets:insert(State#state.handler_db, {Request#request.id,
- HandlerPid,
- Request#request.from});
+ HandlerInfo = {Id, HandlerPid, From},
+ ets:insert(HandlerDb, HandlerInfo);
_ -> % timeout pipelining failed
start_handler(Request, State)
end.