25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-11-22 16:20:52 +01:00

Bosh compliance: honor xmpp:version (thanks to Stefan Strigler)

SVN Revision: 2275
This commit is contained in:
Badlop 2009-06-16 18:24:38 +00:00
parent 01dc4611b9
commit 5048b6bdaf

View File

@ -3,12 +3,12 @@
%%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Author : Stefan Strigler <steve@zeank.in-berlin.de>
%%% Purpose : HTTP Binding support (JEP-0124) %%% Purpose : HTTP Binding support (JEP-0124)
%%% 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 156 2007-06-25 09:22:57Z cromain $ %%% Id : $Id: ejabberd_http_bind.erl 239 2007-08-03 10:54:00Z sstrigler $
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
-module(ejabberd_http_bind). -module(ejabberd_http_bind).
-author('steve@zeank.in-berlin.de'). -author('steve@zeank.in-berlin.de').
-vsn('$Rev: 156 $'). -vsn('$Rev: 239 $').
-behaviour(gen_fsm). -behaviour(gen_fsm).
@ -64,6 +64,8 @@
-define(FSMOPTS, []). -define(FSMOPTS, []).
-endif. -endif.
-define(BOSH_VERSION, "1.6").
-define(MAX_REQUESTS, 2). % number of simultaneous requests -define(MAX_REQUESTS, 2). % number of simultaneous requests
-define(MIN_POLLING, "2"). % don't poll faster than that or we will -define(MIN_POLLING, "2"). % don't poll faster than that or we will
% shoot you % shoot you
@ -119,106 +121,108 @@ process_request(Data) ->
"condition='improper-addressing' " "condition='improper-addressing' "
"xmlns='http://jabber.org/protocol/httpbind'/>"}; "xmlns='http://jabber.org/protocol/httpbind'/>"};
true -> true ->
Sid = if Sid =
(ParsedSid == "") -> if
%% create new session (ParsedSid == "") ->
NewSid = sha:sha(term_to_binary({now(), make_ref()})), %% create new session
{ok, Pid} = start(NewSid, Key), NewSid = sha:sha(term_to_binary({now(), make_ref()})),
?DEBUG("got pid: ~p", [Pid]), {ok, Pid} = start(NewSid, Key),
Wait = case ?DEBUG("got pid: ~p", [Pid]),
string:to_integer(xml:get_attr_s("wait",Attrs)) Wait = case
of string:to_integer(xml:get_attr_s("wait",Attrs))
{error, _} -> of
?MAX_WAIT; {error, _} ->
{CWait, _} -> ?MAX_WAIT;
if {CWait, _} ->
(CWait > ?MAX_WAIT) -> if
?MAX_WAIT; (CWait > ?MAX_WAIT) ->
true -> ?MAX_WAIT;
CWait true ->
end CWait
end, end
Hold = case end,
string:to_integer( Hold = case
xml:get_attr_s("hold",Attrs)) string:to_integer(
of xml:get_attr_s("hold",Attrs))
{error, _} -> of
(?MAX_REQUESTS - 1); {error, _} ->
{CHold, _} -> (?MAX_REQUESTS - 1);
if {CHold, _} ->
(CHold > (?MAX_REQUESTS - 1)) -> if
(?MAX_REQUESTS - 1); (CHold > (?MAX_REQUESTS - 1)) ->
true -> (?MAX_REQUESTS - 1);
CHold true ->
end CHold
end, end
mnesia:transaction( end,
fun() -> XmppVersion = xml:get_attr_s("xmpp:version", Attrs),
mnesia:write(#http_bind{id = NewSid, mnesia:transaction(
pid = Pid, fun() ->
to = XmppDomain, mnesia:write(#http_bind{id = NewSid,
wait = Wait, pid = Pid,
hold = Hold}) to = {XmppDomain, XmppVersion},
end), wait = Wait,
StreamStart = if hold = Hold})
(XmppDomain /= "") -> end),
true; StreamStart = if
true -> (XmppDomain /= "") ->
false true;
end, true ->
InPacket = Packet, false
NewSid; end,
true -> InPacket = Packet,
%% old session NewSid;
Type = xml:get_attr_s("type",Attrs), true ->
StreamStart = %% old session
case xml:get_attr_s("xmpp:restart",Attrs) of Type = xml:get_attr_s("type",Attrs),
"true" -> StreamStart =
true; case xml:get_attr_s("xmpp:restart",Attrs) of
_ -> "true" ->
false true;
end, _ ->
Wait = ?MAX_WAIT, false
Hold = (?MAX_REQUESTS - 1), end,
if Wait = ?MAX_WAIT,
(Type == "terminate") -> Hold = (?MAX_REQUESTS - 1),
%% terminate session if
InPacket = Packet ++ "</stream:stream>"; (Type == "terminate") ->
true -> %% terminate session
InPacket = Packet InPacket = Packet ++ "</stream:stream>";
end, true ->
ParsedSid InPacket = Packet
end, end,
%% ?DEBUG("~n InPacket: ~s ~n", [InPacket]), ParsedSid
case http_put(Sid, Rid, Key, NewKey, Hold, InPacket, StreamStart) of end,
{error, not_exists} -> %% ?DEBUG("~n InPacket: ~s ~n", [InPacket]),
?DEBUG("no session associated with sid: ~p", [Sid]), case http_put(Sid, Rid, Key, NewKey, Hold, InPacket, StreamStart) of
{404, ?HEADER, ""}; {error, not_exists} ->
{error, bad_key} -> ?DEBUG("no session associated with sid: ~p", [Sid]),
?DEBUG("bad key: ~s", [Key]), {404, ?HEADER, ""};
case mnesia:dirty_read({http_bind, Sid}) of {error, bad_key} ->
[] -> ?DEBUG("bad key: ~s", [Key]),
{404, ?HEADER, ""}; case mnesia:dirty_read({http_bind, Sid}) of
[#http_bind{pid = FsmRef}] -> [] ->
gen_fsm:sync_send_all_state_event(FsmRef,stop), {404, ?HEADER, ""};
{404, ?HEADER, ""} [#http_bind{pid = FsmRef}] ->
end; gen_fsm:sync_send_all_state_event(FsmRef,stop),
{error, polling_too_frequently} -> {404, ?HEADER, ""}
?DEBUG("polling too frequently: ~p", [Sid]), end;
case mnesia:dirty_read({http_bind, Sid}) of {error, polling_too_frequently} ->
[] -> %% unlikely! (?) ?DEBUG("polling too frequently: ~p", [Sid]),
{404, ?HEADER, ""}; case mnesia:dirty_read({http_bind, Sid}) of
[#http_bind{pid = FsmRef}] -> [] -> %% unlikely! (?)
gen_fsm:sync_send_all_state_event(FsmRef,stop), {404, ?HEADER, ""};
{403, ?HEADER, ""} [#http_bind{pid = FsmRef}] ->
end; gen_fsm:sync_send_all_state_event(FsmRef,stop),
{repeat, OutPacket} -> {403, ?HEADER, ""}
?DEBUG("http_put said 'repeat!' ...~nOutPacket: ~p", end;
[OutPacket]), {repeat, OutPacket} ->
send_outpacket(Sid, OutPacket); ?DEBUG("http_put said 'repeat!' ...~nOutPacket: ~p",
ok -> [OutPacket]),
receive_loop(Sid,ParsedSid,Rid,Wait,Hold,Attrs) send_outpacket(Sid, OutPacket);
end ok ->
receive_loop(Sid,ParsedSid,Rid,Wait,Hold,Attrs)
end
end; end;
_ -> _ ->
{400, ?HEADER, ""} {400, ?HEADER, ""}
@ -278,6 +282,16 @@ prepare_response(Sid,ParsedSid,Rid,Wait,Hold,Attrs) ->
"condition='host-unknown' " "condition='host-unknown' "
"xmlns='http://jabber.org/protocol/httpbind'/>"}; "xmlns='http://jabber.org/protocol/httpbind'/>"};
true -> true ->
BOSH_attribs =
[{"authid", AuthID},
{"xmlns:xmpp", "urn:xmpp:xbosh"},
{"xmlns:stream","http://etherx.jabber.org/streams"}] ++
case OutEls of
[] ->
[];
_ ->
[{"xmpp:version", "1.0"}]
end,
{200, ?HEADER, {200, ?HEADER,
xml:element_to_string( xml:element_to_string(
{xmlelement,"body", {xmlelement,"body",
@ -289,8 +303,10 @@ prepare_response(Sid,ParsedSid,Rid,Wait,Hold,Attrs) ->
{"inactivity", {"inactivity",
integer_to_list(trunc(?MAX_INACTIVITY/1000))}, integer_to_list(trunc(?MAX_INACTIVITY/1000))},
{"polling", ?MIN_POLLING}, {"polling", ?MIN_POLLING},
{"authid", AuthID} {"ver", ?BOSH_VERSION},
],OutEls})} {"from", To},
{"secure", "true"} %% we're always being secure
] ++ BOSH_attribs,OutEls})}
end end
end end
end. end.
@ -480,7 +496,7 @@ handle_sync_event(stop, _From, _StateName, StateData) ->
Reply = ok, Reply = ok,
{stop, normal, Reply, StateData}; {stop, normal, Reply, StateData};
handle_sync_event({http_put, Rid, Key, NewKey, Hold, Packet, StartTo}, handle_sync_event({http_put, Rid, Key, NewKey, Hold, Packet, StreamTo},
_From, StateName, StateData) -> _From, StateName, StateData) ->
%% check if Rid valid %% check if Rid valid
RidAllow = case Rid of RidAllow = case Rid of
@ -602,14 +618,17 @@ handle_sync_event({http_put, Rid, Key, NewKey, Hold, Packet, StartTo},
}}; }};
{Receiver, _Tag} -> {Receiver, _Tag} ->
SendPacket = SendPacket =
if case StreamTo of
StartTo /= "" -> {To, ""} ->
["<stream:stream to='", ["<stream:stream to='", To, "' "
StartTo, "xmlns='jabber:client' "
"' xmlns='jabber:client' "
%%"version='1.0' "
"xmlns:stream='http://etherx.jabber.org/streams'>"] ++ Packet; "xmlns:stream='http://etherx.jabber.org/streams'>"] ++ Packet;
true -> {To, Version} ->
["<stream:stream to='", To, "' "
"xmlns='jabber:client' "
"version='", Version, "' "
"xmlns:stream='http://etherx.jabber.org/streams'>"] ++ Packet;
_ ->
Packet Packet
end, end,
?DEBUG("really sending now: ~s", [SendPacket]), ?DEBUG("really sending now: ~s", [SendPacket]),
@ -732,12 +751,12 @@ http_put(Sid, Rid, Key, NewKey, Hold, Packet, Restart) ->
[] -> [] ->
?DEBUG("not found",[]), ?DEBUG("not found",[]),
{error, not_exists}; {error, not_exists};
[#http_bind{pid = FsmRef,to=To}] -> [#http_bind{pid = FsmRef,to=StreamTo}] ->
case Restart of case Restart of
true -> true ->
?DEBUG("restart requested for ~s", [To]), ?DEBUG("restart requested for ~s", [To]),
gen_fsm:sync_send_all_state_event( gen_fsm:sync_send_all_state_event(
FsmRef, {http_put, Rid, Key, NewKey, Hold, Packet, To}); FsmRef, {http_put, Rid, Key, NewKey, Hold, Packet, StreamTo});
_ -> _ ->
gen_fsm:sync_send_all_state_event( gen_fsm:sync_send_all_state_event(
FsmRef, {http_put, Rid, Key, NewKey, Hold, Packet, ""}) FsmRef, {http_put, Rid, Key, NewKey, Hold, Packet, ""})