mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-22 16:20:52 +01:00
Removed receive_loop (thanks to Alexey Shchepin)
SVN Revision: 2296
This commit is contained in:
parent
68754c4b5d
commit
5f07b4bf9b
@ -4,7 +4,7 @@
|
|||||||
%%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as
|
%%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as
|
||||||
%%% HTTP Binding)
|
%%% HTTP Binding)
|
||||||
%%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de>
|
%%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de>
|
||||||
%%% Id : $Id: ejabberd_http_bind.erl 440 2007-12-06 22:36:21Z badlop $
|
%%% Id : $Id: ejabberd_http_bind.erl 449 2007-12-18 15:00:10Z alexey $
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
-module(ejabberd_http_bind).
|
-module(ejabberd_http_bind).
|
||||||
@ -50,6 +50,8 @@
|
|||||||
waiting_input = false,
|
waiting_input = false,
|
||||||
last_receiver,
|
last_receiver,
|
||||||
last_poll,
|
last_poll,
|
||||||
|
http_receiver,
|
||||||
|
wait_timer,
|
||||||
ctime = 0,
|
ctime = 0,
|
||||||
timer,
|
timer,
|
||||||
pause=0,
|
pause=0,
|
||||||
@ -72,7 +74,7 @@
|
|||||||
|
|
||||||
-define(MAX_REQUESTS, 2). % number of simultaneous requests
|
-define(MAX_REQUESTS, 2). % number of simultaneous requests
|
||||||
-define(MIN_POLLING, 2000000). % don't poll faster than that or we will
|
-define(MIN_POLLING, 2000000). % don't poll faster than that or we will
|
||||||
% shoot you (time in µsec)
|
% shoot you (time in sec)
|
||||||
-define(MAX_WAIT, 3600). % max num of secs to keep a request on hold
|
-define(MAX_WAIT, 3600). % max num of secs to keep a request on hold
|
||||||
-define(MAX_INACTIVITY, 30000). % msecs to wait before terminating
|
-define(MAX_INACTIVITY, 30000). % msecs to wait before terminating
|
||||||
% idle sessions
|
% idle sessions
|
||||||
@ -283,8 +285,30 @@ handle_event(_Event, StateName, StateData) ->
|
|||||||
%%----------------------------------------------------------------------
|
%%----------------------------------------------------------------------
|
||||||
handle_sync_event({send, Packet}, _From, StateName, StateData) ->
|
handle_sync_event({send, Packet}, _From, StateName, StateData) ->
|
||||||
Output = [StateData#state.output | Packet],
|
Output = [StateData#state.output | Packet],
|
||||||
|
if
|
||||||
|
StateData#state.http_receiver /= undefined ->
|
||||||
|
HTTPReply = case Output of
|
||||||
|
[[]| OutPacket] ->
|
||||||
|
{ok, OutPacket};
|
||||||
|
_ ->
|
||||||
|
{ok, Output}
|
||||||
|
end,
|
||||||
|
gen_fsm:reply(StateData#state.http_receiver, HTTPReply),
|
||||||
|
if
|
||||||
|
StateData#state.wait_timer /= undefined ->
|
||||||
|
cancel_timer(StateData#state.wait_timer);
|
||||||
|
true ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
Reply = ok,
|
Reply = ok,
|
||||||
{reply, Reply, StateName, StateData#state{output = Output}};
|
{reply, Reply, StateName,
|
||||||
|
StateData#state{output = [],
|
||||||
|
http_receiver = undefined,
|
||||||
|
wait_timer = undefined}};
|
||||||
|
true ->
|
||||||
|
Reply = ok,
|
||||||
|
{reply, Reply, StateName, StateData#state{output = Output}}
|
||||||
|
end;
|
||||||
|
|
||||||
handle_sync_event(stop, _From, _StateName, StateData) ->
|
handle_sync_event(stop, _From, _StateName, StateData) ->
|
||||||
Reply = ok,
|
Reply = ok,
|
||||||
@ -333,7 +357,7 @@ handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo},
|
|||||||
"" ->
|
"" ->
|
||||||
true;
|
true;
|
||||||
OldKey ->
|
OldKey ->
|
||||||
NextKey = string:to_lower(
|
NextKey = jlib:tolower(
|
||||||
hex(binary_to_list(
|
hex(binary_to_list(
|
||||||
crypto:sha(Key)))),
|
crypto:sha(Key)))),
|
||||||
?DEBUG("Key/OldKey/NextKey: ~s/~s/~s",
|
?DEBUG("Key/OldKey/NextKey: ~s/~s/~s",
|
||||||
@ -464,18 +488,29 @@ handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo},
|
|||||||
{reply, Reply, StateName, StateData}
|
{reply, Reply, StateName, StateData}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
handle_sync_event({http_get, Rid, Wait, Hold}, _From, StateName, StateData) ->
|
handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) ->
|
||||||
%% setup timer
|
%% setup timer
|
||||||
cancel_timer(StateData#state.timer),
|
cancel_timer(StateData#state.timer),
|
||||||
if
|
Timer = if
|
||||||
StateData#state.pause > 0 ->
|
StateData#state.pause > 0 ->
|
||||||
Timer = erlang:start_timer(
|
erlang:start_timer(
|
||||||
StateData#state.pause*1000, self(), []);
|
StateData#state.pause*1000, self(), []);
|
||||||
true ->
|
true ->
|
||||||
Timer = erlang:start_timer(
|
erlang:start_timer(
|
||||||
?MAX_INACTIVITY, self(), [])
|
?MAX_INACTIVITY, self(), [])
|
||||||
end,
|
end,
|
||||||
|
if
|
||||||
|
StateData#state.http_receiver /= undefined ->
|
||||||
|
gen_fsm:reply(StateData#state.http_receiver, {ok, empty});
|
||||||
|
true ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
if
|
||||||
|
StateData#state.wait_timer /= undefined ->
|
||||||
|
cancel_timer(StateData#state.wait_timer);
|
||||||
|
true ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
{_,TSec,TMSec} = now(),
|
{_,TSec,TMSec} = now(),
|
||||||
TNow = TSec*1000*1000 + TMSec,
|
TNow = TSec*1000*1000 + TMSec,
|
||||||
if
|
if
|
||||||
@ -487,11 +522,25 @@ handle_sync_event({http_get, Rid, Wait, Hold}, _From, StateName, StateData) ->
|
|||||||
(StateData#state.pause == 0) ->
|
(StateData#state.pause == 0) ->
|
||||||
Output = StateData#state.output,
|
Output = StateData#state.output,
|
||||||
ReqList = StateData#state.req_list,
|
ReqList = StateData#state.req_list,
|
||||||
Reply = {ok, keep_on_hold};
|
WaitTimer = erlang:start_timer(Wait * 1000, self(), []),
|
||||||
|
{next_state, StateName, StateData#state{
|
||||||
|
input = "",
|
||||||
|
output = Output,
|
||||||
|
http_receiver = From,
|
||||||
|
wait_timer = WaitTimer,
|
||||||
|
timer = Timer,
|
||||||
|
req_list = ReqList}};
|
||||||
(StateData#state.input == "cancel") ->
|
(StateData#state.input == "cancel") ->
|
||||||
Output = StateData#state.output,
|
Output = StateData#state.output,
|
||||||
ReqList = StateData#state.req_list,
|
ReqList = StateData#state.req_list,
|
||||||
Reply = {ok, cancel};
|
Reply = {ok, cancel},
|
||||||
|
{reply, Reply, StateName, StateData#state{
|
||||||
|
input = "",
|
||||||
|
output = Output,
|
||||||
|
http_receiver = undefined,
|
||||||
|
wait_timer = undefined,
|
||||||
|
timer = Timer,
|
||||||
|
req_list = ReqList}};
|
||||||
true ->
|
true ->
|
||||||
case StateData#state.output of
|
case StateData#state.output of
|
||||||
[[]| OutPacket] ->
|
[[]| OutPacket] ->
|
||||||
@ -508,13 +557,15 @@ handle_sync_event({http_get, Rid, Wait, Hold}, _From, StateName, StateData) ->
|
|||||||
[El || El <- StateData#state.req_list,
|
[El || El <- StateData#state.req_list,
|
||||||
El#hbr.rid /= Rid ]
|
El#hbr.rid /= Rid ]
|
||||||
],
|
],
|
||||||
Output = ""
|
Output = "",
|
||||||
end,
|
|
||||||
{reply, Reply, StateName, StateData#state{
|
{reply, Reply, StateName, StateData#state{
|
||||||
input = "",
|
input = "",
|
||||||
output = Output,
|
output = Output,
|
||||||
|
http_receiver = undefined,
|
||||||
|
wait_timer = undefined,
|
||||||
timer = Timer,
|
timer = Timer,
|
||||||
req_list = ReqList}};
|
req_list = ReqList}}
|
||||||
|
end;
|
||||||
|
|
||||||
handle_sync_event(_Event, _From, StateName, StateData) ->
|
handle_sync_event(_Event, _From, StateName, StateData) ->
|
||||||
Reply = ok,
|
Reply = ok,
|
||||||
@ -534,6 +585,18 @@ handle_info({timeout, Timer, _}, _StateName,
|
|||||||
?DEBUG("ding dong", []),
|
?DEBUG("ding dong", []),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
|
handle_info({timeout, Timer, _}, StateName,
|
||||||
|
#state{wait_timer = Timer} = StateData) ->
|
||||||
|
if
|
||||||
|
StateData#state.http_receiver /= undefined ->
|
||||||
|
gen_fsm:reply(StateData#state.http_receiver, {ok, empty}),
|
||||||
|
{next_state, StateName,
|
||||||
|
StateData#state{http_receiver = undefined,
|
||||||
|
wait_timer = undefined}};
|
||||||
|
true ->
|
||||||
|
{next_state, StateName, StateData}
|
||||||
|
end;
|
||||||
|
|
||||||
handle_info(_, StateName, StateData) ->
|
handle_info(_, StateName, StateData) ->
|
||||||
{next_state, StateName, StateData}.
|
{next_state, StateName, StateData}.
|
||||||
|
|
||||||
@ -574,7 +637,7 @@ handle_http_put(Sid, Rid, Attrs, Payload, StreamStart) ->
|
|||||||
[OutPacket]),
|
[OutPacket]),
|
||||||
send_outpacket(Sess, OutPacket);
|
send_outpacket(Sess, OutPacket);
|
||||||
{ok, Sess} ->
|
{ok, Sess} ->
|
||||||
receive_loop(Sess, Rid, Attrs, StreamStart)
|
prepare_response(Sess, Rid, Attrs, StreamStart)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
http_put(Sid, Rid, Attrs, Payload, StreamStart) ->
|
http_put(Sid, Rid, Attrs, Payload, StreamStart) ->
|
||||||
@ -632,22 +695,17 @@ handle_http_put_error(Reason, #http_bind{pid=FsmRef}) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
receive_loop(Sess, Rid, Attrs, StreamStart) ->
|
|
||||||
receive
|
|
||||||
after 100 -> ok
|
|
||||||
end,
|
|
||||||
prepare_response(Sess, Rid, Attrs, StreamStart).
|
|
||||||
|
|
||||||
prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold}=Sess,
|
prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold}=Sess,
|
||||||
Rid, Attrs, StreamStart) ->
|
Rid, Attrs, StreamStart) ->
|
||||||
case http_get(Sess, Rid) of
|
receive after 100 -> ok end,
|
||||||
{ok, keep_on_hold} ->
|
case catch http_get(Sess, Rid) of
|
||||||
receive_loop(Sess, Rid, Attrs, StreamStart);
|
|
||||||
{ok, cancel} ->
|
{ok, cancel} ->
|
||||||
%% actually it would be better if we could completely
|
%% actually it would be better if we could completely
|
||||||
%% cancel this request, but then we would have to hack
|
%% cancel this request, but then we would have to hack
|
||||||
%% ejabberd_http and I'm too lazy now
|
%% ejabberd_http and I'm too lazy now
|
||||||
{200, ?HEADER, "<body type='error' xmlns='"++?NS_HTTP_BIND++"'/>"};
|
{200, ?HEADER, "<body type='error' xmlns='"++?NS_HTTP_BIND++"'/>"};
|
||||||
|
{ok, empty} ->
|
||||||
|
{200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"};
|
||||||
{ok, OutPacket} ->
|
{ok, OutPacket} ->
|
||||||
?DEBUG("OutPacket: ~s", [OutPacket]),
|
?DEBUG("OutPacket: ~s", [OutPacket]),
|
||||||
case StreamStart of
|
case StreamStart of
|
||||||
@ -724,12 +782,14 @@ prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold}=Sess,
|
|||||||
{"secure", "true"} %% we're always being secure
|
{"secure", "true"} %% we're always being secure
|
||||||
] ++ BOSH_attribs,OutEls})}
|
] ++ BOSH_attribs,OutEls})}
|
||||||
end
|
end
|
||||||
end
|
end;
|
||||||
|
{'EXIT', _Reason} ->
|
||||||
|
{200, ?HEADER, "<body type='terminate' xmlns='"++?NS_HTTP_BIND++"'/>"}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
http_get(#http_bind{pid = FsmRef, wait = Wait, hold = Hold}, Rid) ->
|
http_get(#http_bind{pid = FsmRef, wait = Wait, hold = Hold}, Rid) ->
|
||||||
gen_fsm:sync_send_all_state_event(FsmRef,
|
gen_fsm:sync_send_all_state_event(
|
||||||
{http_get, Rid, Wait, Hold}).
|
FsmRef, {http_get, Rid, Wait, Hold}, 2 * ?MAX_WAIT * 1000).
|
||||||
|
|
||||||
send_outpacket(#http_bind{pid = FsmRef}, OutPacket) ->
|
send_outpacket(#http_bind{pid = FsmRef}, OutPacket) ->
|
||||||
case OutPacket of
|
case OutPacket of
|
||||||
@ -793,7 +853,7 @@ send_outpacket(#http_bind{pid = FsmRef}, OutPacket) ->
|
|||||||
StreamError ->
|
StreamError ->
|
||||||
StreamErrCond =
|
StreamErrCond =
|
||||||
case xml_stream:parse_element(
|
case xml_stream:parse_element(
|
||||||
"<stream:stream>"++OutPacket) of
|
"<stream:stream>" ++ OutPacket) of
|
||||||
El when element(1, El) == xmlelement ->
|
El when element(1, El) == xmlelement ->
|
||||||
case xml:get_subtag(El, "stream:error") of
|
case xml:get_subtag(El, "stream:error") of
|
||||||
false ->
|
false ->
|
||||||
@ -844,7 +904,7 @@ parse_request(Data) ->
|
|||||||
Xmlns /= ?NS_HTTP_BIND ->
|
Xmlns /= ?NS_HTTP_BIND ->
|
||||||
{error, bad_request};
|
{error, bad_request};
|
||||||
true ->
|
true ->
|
||||||
case list_to_integer(xml:get_attr_s("rid", Attrs)) of
|
case catch list_to_integer(xml:get_attr_s("rid", Attrs)) of
|
||||||
{'EXIT', _} ->
|
{'EXIT', _} ->
|
||||||
{error, bad_request};
|
{error, bad_request};
|
||||||
Rid ->
|
Rid ->
|
||||||
|
Loading…
Reference in New Issue
Block a user