mirror of
https://github.com/processone/ejabberd.git
synced 2024-07-14 23:44:18 +02:00
HTTP prebinding support (TECH-1327)
Example configuration: {modules, [ ... {mod_http_bind, [{prebind, true}]}, ... ]}
This commit is contained in:
parent
b6a637c121
commit
302294faec
|
@ -273,7 +273,18 @@ init([{SockMod, Socket}, Opts, FSMLimitOpts]) ->
|
|||
ip = IP,
|
||||
redirect = Redirect,
|
||||
fsm_limit_opts = FSMLimitOpts},
|
||||
{ok, wait_for_stream, StateData, ?C2S_OPEN_TIMEOUT}
|
||||
case get_jid_from_opts(Opts) of
|
||||
{ok, #jid{user = U, server = Server, resource = R} = JID} ->
|
||||
?GEN_FSM:send_event(self(), open_session),
|
||||
{ok, wait_for_session, StateData#state{
|
||||
user = U,
|
||||
server = Server,
|
||||
resource = R,
|
||||
jid = JID,
|
||||
lang = ""}};
|
||||
_ ->
|
||||
{ok, wait_for_stream, StateData, ?C2S_OPEN_TIMEOUT}
|
||||
end
|
||||
end;
|
||||
init([StateName, StateData, _FSMLimitOpts]) ->
|
||||
MRef = (StateData#state.sockmod):monitor(StateData#state.socket),
|
||||
|
@ -1084,6 +1095,11 @@ wait_for_session({xmlstreamelement, El}, StateData) ->
|
|||
fsm_next_state(wait_for_session, StateData)
|
||||
end;
|
||||
|
||||
wait_for_session(open_session, StateData) ->
|
||||
El = {xmlelement, "iq", [{"type", "set"}, {"id", "session"}],
|
||||
[{xmlelement, "session", [{"xmlns", ?NS_SESSION}], []}]},
|
||||
wait_for_session({xmlstreamelement, El}, StateData);
|
||||
|
||||
wait_for_session(timeout, StateData) ->
|
||||
{stop, normal, StateData};
|
||||
|
||||
|
@ -3497,3 +3513,21 @@ need_redirect(#state{redirect = true, user = User, server = Server}) ->
|
|||
end;
|
||||
need_redirect(_) ->
|
||||
false.
|
||||
|
||||
get_jid_from_opts(Opts) ->
|
||||
case lists:keysearch(jid, 1, Opts) of
|
||||
{value, {_, JIDValue}} ->
|
||||
JID = case JIDValue of
|
||||
{_U, _S, _R} ->
|
||||
jlib:make_jid(JIDValue);
|
||||
_ when is_binary(JIDValue) ->
|
||||
jlib:string_to_jid(binary_to_list(JIDValue));
|
||||
_ when is_list(JIDValue) ->
|
||||
jlib:string_to_jid(JIDValue);
|
||||
_ ->
|
||||
JIDValue
|
||||
end,
|
||||
{ok, JID};
|
||||
_ ->
|
||||
error
|
||||
end.
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
-behaviour(gen_fsm).
|
||||
|
||||
%% External exports
|
||||
-export([start_link/3,
|
||||
-export([start_link/4,
|
||||
init/1,
|
||||
handle_event/3,
|
||||
handle_sync_event/4,
|
||||
|
@ -70,6 +70,7 @@
|
|||
wait_timer,
|
||||
ctime = 0,
|
||||
timer,
|
||||
jid,
|
||||
pause=0,
|
||||
unprocessed_req_list = [], % list of request that have been delayed for proper reordering: {Request, PID}
|
||||
req_list = [], % list of requests (cache)
|
||||
|
@ -124,7 +125,7 @@
|
|||
start(XMPPDomain, Sid, Key, IP) ->
|
||||
?DEBUG("Starting session", []),
|
||||
SupervisorProc = gen_mod:get_module_proc(XMPPDomain, ?PROCNAME_MHB),
|
||||
case catch supervisor:start_child(SupervisorProc, [Sid, Key, IP]) of
|
||||
case catch supervisor:start_child(SupervisorProc, [XMPPDomain, Sid, Key, IP]) of
|
||||
{ok, Pid} ->
|
||||
{ok, Pid};
|
||||
{error, _} = Err ->
|
||||
|
@ -140,8 +141,8 @@ start(XMPPDomain, Sid, Key, IP) ->
|
|||
{error, Exit}
|
||||
end.
|
||||
|
||||
start_link(Sid, Key, IP) ->
|
||||
gen_fsm:start_link(?MODULE, [Sid, Key, IP], ?FSMOPTS).
|
||||
start_link(ServerHost, Sid, Key, IP) ->
|
||||
gen_fsm:start_link(?MODULE, [ServerHost, Sid, Key, IP], ?FSMOPTS).
|
||||
|
||||
send({http_bind, FsmRef, _IP}, Packet) ->
|
||||
gen_fsm:sync_send_all_state_event(FsmRef, {send, Packet}).
|
||||
|
@ -333,7 +334,7 @@ handle_session_start(Pid, XmppDomain, Sid, Rid, Attrs,
|
|||
%% ignore |
|
||||
%% {stop, StopReason}
|
||||
%%----------------------------------------------------------------------
|
||||
init([Sid, Key, IP]) ->
|
||||
init([ServerHost, Sid, Key, IP]) ->
|
||||
?DEBUG("started: ~p", [{Sid, Key, IP}]),
|
||||
|
||||
%% Read c2s options from the first ejabberd_c2s configuration in
|
||||
|
@ -348,15 +349,25 @@ init([Sid, Key, IP]) ->
|
|||
Shaper = none,
|
||||
ShaperState = shaper:new(Shaper),
|
||||
Socket = {http_bind, self(), IP},
|
||||
ejabberd_socket:start(ejabberd_c2s, ?MODULE, Socket, Opts),
|
||||
Timer = erlang:start_timer(?MAX_INACTIVITY, self(), []),
|
||||
{ok, loop, #state{id = Sid,
|
||||
key = Key,
|
||||
socket = Socket,
|
||||
shaper_state = ShaperState,
|
||||
max_inactivity = ?MAX_INACTIVITY,
|
||||
max_pause = ?MAX_PAUSE,
|
||||
timer = Timer}}.
|
||||
State = #state{id = Sid,
|
||||
key = Key,
|
||||
socket = Socket,
|
||||
shaper_state = ShaperState,
|
||||
max_inactivity = ?MAX_INACTIVITY,
|
||||
max_pause = ?MAX_PAUSE,
|
||||
timer = Timer},
|
||||
case gen_mod:get_module_opt(ServerHost, mod_http_bind,
|
||||
prebind, false) of
|
||||
true ->
|
||||
JID = make_random_jid(ServerHost),
|
||||
ejabberd_socket:start(ejabberd_c2s, ?MODULE, Socket,
|
||||
[{jid, JID} | Opts]),
|
||||
{ok, loop, State#state{jid = JID}};
|
||||
false ->
|
||||
ejabberd_socket:start(ejabberd_c2s, ?MODULE, Socket, Opts),
|
||||
{ok, loop, State}
|
||||
end.
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: handle_event/3
|
||||
|
@ -469,6 +480,11 @@ handle_sync_event(#http_put{payload_size = PayloadSize} = Request,
|
|||
shaper_timer = NewShaperTimer});
|
||||
|
||||
%% HTTP GET: send packets to the client
|
||||
handle_sync_event({http_get, _Rid, _Wait, _Hold}, _From,
|
||||
StateName, #state{jid = JID} = StateData)
|
||||
when JID /= undefined ->
|
||||
%% This is a pre-bind state
|
||||
{reply, {ok, {prebind, JID}}, StateName, StateData#state{jid = undefined}};
|
||||
handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) ->
|
||||
%% setup timer
|
||||
send_receiver_reply(StateData#state.http_receiver, {ok, empty}),
|
||||
|
@ -745,15 +761,16 @@ process_http_put(#http_put{rid = Rid, attrs = Attrs, payload = Payload,
|
|||
ip = IP
|
||||
});
|
||||
C2SPid ->
|
||||
JID = StateData#state.jid,
|
||||
case StreamTo of
|
||||
{To, ""} ->
|
||||
{To, ""} when JID == undefined ->
|
||||
gen_fsm:send_event(
|
||||
C2SPid,
|
||||
{xmlstreamstart, "stream:stream",
|
||||
[{"to", To},
|
||||
{"xmlns", ?NS_CLIENT},
|
||||
{"xmlns:stream", ?NS_STREAM}]});
|
||||
{To, Version} ->
|
||||
{To, Version} when JID == undefined ->
|
||||
gen_fsm:send_event(
|
||||
C2SPid,
|
||||
{xmlstreamstart, "stream:stream",
|
||||
|
@ -950,6 +967,16 @@ prepare_response(Sess, Rid, OutputEls, StreamStart) ->
|
|||
{200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"};
|
||||
{ok, terminate} ->
|
||||
{200, ?HEADER, "<body type='terminate' xmlns='"++?NS_HTTP_BIND++"'/>"};
|
||||
{ok, {prebind, JID}} ->
|
||||
{200, ?HEADER,
|
||||
xml:element_to_string(
|
||||
{xmlelement, "body",
|
||||
[{"xmlns", ?NS_HTTP_BIND}, {"sid", Sess#http_bind.id},
|
||||
{"rid", integer_to_list(Rid + 1)}],
|
||||
[{xmlelement, "iq", [{"id", "pre_bind"}, {"type", "result"}],
|
||||
[{xmlelement, "bind", [{"xmlns", ?NS_BIND}],
|
||||
[{xmlelement, "jid", [],
|
||||
[{xmlcdata, jlib:jid_to_string(JID)}]}]}]}]})};
|
||||
{ok, ROutPacket} ->
|
||||
OutPacket = lists:reverse(ROutPacket),
|
||||
?DEBUG("OutPacket: ~p", [OutputEls++OutPacket]),
|
||||
|
@ -1308,3 +1335,8 @@ get_session(SID) ->
|
|||
_ ->
|
||||
{error, enoent}
|
||||
end.
|
||||
|
||||
make_random_jid(Host) ->
|
||||
%% Copied from cyrsasl_anonymous.erl
|
||||
User = lists:concat([randoms:get_string() | tuple_to_list(now())]),
|
||||
jlib:make_jid(User, Host, randoms:get_string()).
|
||||
|
|
Loading…
Reference in New Issue
Block a user