]> granicus.if.org Git - ejabberd/commitdiff
Remove mod_http_bind and migration code to mod_bosh
authorPaweł Chmielowski <pchmielowski@process-one.net>
Mon, 2 Jan 2017 14:53:25 +0000 (15:53 +0100)
committerPaweł Chmielowski <pchmielowski@process-one.net>
Mon, 2 Jan 2017 14:53:25 +0000 (15:53 +0100)
src/ejabberd_config.erl
src/ejabberd_http.erl
src/ejabberd_http_bind.erl [deleted file]
src/ejabberd_socket.erl
src/mod_bosh.erl
src/mod_http_bind.erl [deleted file]

index e930e36b165541909eb06078df25b81b1eafef0b..5417063831afe4ddd134a525a9812c37d8dd3fa1 100644 (file)
@@ -1041,6 +1041,7 @@ replace_module(mod_shared_roster_odbc) -> {mod_shared_roster, sql};
 replace_module(mod_vcard_odbc) -> {mod_vcard, sql};
 replace_module(mod_vcard_xupdate_odbc) -> {mod_vcard_xupdate, sql};
 replace_module(mod_pubsub_odbc) -> {mod_pubsub, sql};
+replace_module(mod_http_bind) -> mod_bosh;
 replace_module(Module) ->
     case is_elixir_module(Module) of
         true  -> expand_elixir_module(Module);
index c0c7bbbd6863aef744261c8d4ba51e3e043c01cc..513559b94dd7c41045875a3ff4ad24ef2cfa5cc5 100644 (file)
@@ -135,7 +135,7 @@ init({SockMod, Socket}, Opts) ->
               false -> []
             end,
     Bind = case proplists:get_bool(http_bind, Opts) of
-             true -> [{[<<"http-bind">>], mod_http_bind}];
+            true -> [{[<<"http-bind">>], mod_bosh}];
              false -> []
            end,
     XMLRPC = case proplists:get_bool(xmlrpc, Opts) of
@@ -150,9 +150,14 @@ init({SockMod, Socket}, Opts) ->
                                   ({Path, Mod}) -> {Path, Mod}
                                 end, Hs),
 
-                                [{str:tokens(
-                                    iolist_to_binary(Path), <<"/">>),
-                                  Mod} || {Path, Mod} <- Hs1]
+                               Hs2 = [{str:tokens(
+                                         iolist_to_binary(Path), <<"/">>),
+                                       Mod} || {Path, Mod} <- Hs1],
+                               [{Path,
+                                 case Mod of
+                                     mod_http_bind -> mod_bosh;
+                                     _ -> Mod
+                                 end} || {Path, Mod} <- Hs2]
                         end, []),
     RequestHandlers = DefinedHandlers ++ Captcha ++ Register ++
         Admin ++ Bind ++ XMLRPC,
diff --git a/src/ejabberd_http_bind.erl b/src/ejabberd_http_bind.erl
deleted file mode 100644 (file)
index ea64b3c..0000000
+++ /dev/null
@@ -1,1211 +0,0 @@
-%%%----------------------------------------------------------------------
-%%% File    : ejabberd_http_bind.erl
-%%% Author  : Stefan Strigler <steve@zeank.in-berlin.de>
-%%% Purpose : Implements XMPP over BOSH (XEP-0206)
-%%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de>
-%%% Modified: may 2009 by Mickael Remond, Alexey Schepin
-%%%
-%%%
-%%% ejabberd, Copyright (C) 2002-2016   ProcessOne
-%%%
-%%% This program is free software; you can redistribute it and/or
-%%% modify it under the terms of the GNU General Public License as
-%%% published by the Free Software Foundation; either version 2 of the
-%%% License, or (at your option) any later version.
-%%%
-%%% This program is distributed in the hope that it will be useful,
-%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
-%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-%%% General Public License for more details.
-%%%
-%%% You should have received a copy of the GNU General Public License along
-%%% with this program; if not, write to the Free Software Foundation, Inc.,
-%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-%%%
-%%%----------------------------------------------------------------------
-
--module(ejabberd_http_bind).
-
--protocol({xep, 124, '1.11'}).
--protocol({xep, 206, '1.4'}).
-
--behaviour(gen_fsm).
-
-%% External exports
--export([start_link/4,
-        init/1,
-        handle_event/3,
-        handle_sync_event/4,
-        code_change/4,
-        handle_info/3,
-        terminate/3,
-        send/2,
-        send_xml/2,
-        sockname/1,
-        peername/1,
-        setopts/2,
-        controlling_process/2,
-        become_controller/2,
-        custom_receiver/1,
-        reset_stream/1,
-        change_shaper/2,
-        monitor/1,
-        close/1,
-        start/5,
-        handle_session_start/8,
-        handle_http_put/7,
-        http_put/7,
-        http_get/2,
-        prepare_response/4,
-        process_request/3]).
-
--include("ejabberd.hrl").
--include("logger.hrl").
-
--include("xmpp.hrl").
-
--include("ejabberd_http.hrl").
-
--include("http_bind.hrl").
-
--record(http_bind,
-       {id, pid, to, hold, wait, process_delay, version}).
-
--define(NULL_PEER, {{0, 0, 0, 0}, 0}).
-
-%% http binding request
--record(hbr, {rid,
-             key,
-             out}).
-
--record(state, {id,
-               rid = none,
-               key,
-               socket,
-               output = "",
-               input = queue:new(),
-               waiting_input = false,
-               shaper_state,
-               shaper_timer,
-               last_receiver,
-               last_poll,
-               http_receiver,
-               out_of_order_receiver = false,
-               wait_timer,
-               ctime = 0,
-               timer,
-               pause = 0,
-               unprocessed_req_list = [], % list of request that have been delayed for proper reordering: {Request, PID}
-               req_list = [], % list of requests (cache)
-               max_inactivity,
-               max_pause,
-               ip = ?NULL_PEER
-              }).
-
-%% Internal request format:
--record(http_put, {rid,
-                  attrs,
-                  payload,
-                  payload_size,
-                  hold,
-                  stream,
-                  ip}).
-
-%%-define(DBGFSM, true).
--ifdef(DBGFSM).
-
--define(FSMOPTS, [{debug, [trace]}]).
-
--else.
-
--define(FSMOPTS, []).
-
--endif.
-
-%% Wait 100ms before continue processing, to allow the client provide more related stanzas.
--define(BOSH_VERSION, <<"1.8">>).
-
--define(NS_BOSH, <<"urn:xmpp:xbosh">>).
-
--define(NS_HTTP_BIND,
-       <<"http://jabber.org/protocol/httpbind">>).
-
--define(MAX_REQUESTS, 2).
-
--define(MIN_POLLING, 2000000).
-
--define(MAX_WAIT, 3600).
-
--define(MAX_INACTIVITY, 30000).
-
--define(MAX_PAUSE, 120).
-
--define(PROCESS_DELAY_DEFAULT, 100).
-
--define(PROCESS_DELAY_MIN, 0).
-
--define(PROCESS_DELAY_MAX, 1000).
-
--define(PROCNAME_MHB, ejabberd_mod_http_bind).
-
-start(XMPPDomain, Sid, Key, IP, HOpts) ->
-    ?DEBUG("Starting session", []),
-    case catch gen_fsm:start(?MODULE,
-                           [Sid, Key, IP, HOpts],
-                           ?FSMOPTS)
-    of
-       {ok, Pid} -> {ok, Pid};
-       _ -> check_bind_module(XMPPDomain),
-             {error, "Cannot start HTTP bind session"}
-    end.
-
-start_link(Sid, Key, IP, HOpts) ->
-    gen_fsm:start_link(?MODULE, [Sid, Key, IP, HOpts], ?FSMOPTS).
-
-send({http_bind, FsmRef, _IP}, Packet) ->
-    gen_fsm:sync_send_all_state_event(FsmRef,
-                                     {send, Packet}).
-
-send_xml({http_bind, FsmRef, _IP}, Packet) ->
-    gen_fsm:sync_send_all_state_event(FsmRef,
-                                     {send_xml, Packet}).
-
-setopts({http_bind, FsmRef, _IP}, Opts) ->
-    case lists:member({active, once}, Opts) of
-       true ->
-           gen_fsm:send_all_state_event(FsmRef, {activate, self()});
-       _ ->
-           ok
-    end.
-
-controlling_process(_Socket, _Pid) -> ok.
-
-custom_receiver({http_bind, FsmRef, _IP}) ->
-    {receiver, ?MODULE, FsmRef}.
-
-become_controller(FsmRef, C2SPid) ->
-    gen_fsm:send_all_state_event(FsmRef,
-                                {become_controller, C2SPid}).
-
-reset_stream({http_bind, _FsmRef, _IP}) ->
-    ok.
-
-change_shaper({http_bind, FsmRef, _IP}, Shaper) ->
-    gen_fsm:send_all_state_event(FsmRef,
-                                {change_shaper, Shaper}).
-
-monitor({http_bind, FsmRef, _IP}) ->
-    erlang:monitor(process, FsmRef).
-
-close({http_bind, FsmRef, _IP}) ->
-    catch gen_fsm:sync_send_all_state_event(FsmRef,
-                                           {stop, close}).
-
-sockname(_Socket) -> {ok, ?NULL_PEER}.
-
-peername({http_bind, _FsmRef, IP}) -> {ok, IP}.
-
-
-%% Entry point for data coming from client through ejabberd HTTP server:
-process_request(Data, IP, HOpts) ->
-    Opts1 = ejabberd_c2s_config:get_c2s_limits(),
-    Opts = [{xml_socket, true} | Opts1],
-    MaxStanzaSize = case lists:keysearch(max_stanza_size, 1,
-                                        Opts)
-                       of
-                     {value, {_, Size}} -> Size;
-                     _ -> infinity
-                   end,
-    PayloadSize = iolist_size(Data),
-    case catch parse_request(Data, PayloadSize,
-                            MaxStanzaSize)
-       of
-      %% No existing session:
-      {ok, {<<"">>, Rid, Attrs, Payload}} ->
-         case fxml:get_attr_s(<<"to">>, Attrs) of
-           <<"">> ->
-               ?DEBUG("Session not created (Improper addressing)", []),
-               {200, ?HEADER,
-                <<"<body type='terminate' condition='improper-ad"
-                  "dressing' xmlns='",
-                  (?NS_HTTP_BIND)/binary, "'/>">>};
-           XmppDomain ->
-                NXmppDomain = jid:nameprep(XmppDomain),
-               Sid = p1_sha:sha(term_to_binary({p1_time_compat:monotonic_time(), make_ref()})),
-               case start(NXmppDomain, Sid, <<"">>, IP, HOpts) of
-                 {error, _} ->
-                     {500, ?HEADER,
-                      <<"<body type='terminate' condition='internal-se"
-                        "rver-error' xmlns='",
-                        (?NS_HTTP_BIND)/binary,
-                        "'>Internal Server Error</body>">>};
-                 {ok, Pid} ->
-                     handle_session_start(Pid, NXmppDomain, Sid, Rid, Attrs,
-                                          Payload, PayloadSize, IP)
-               end
-         end;
-      %% Existing session
-      {ok, {Sid, Rid, Attrs, Payload1}} ->
-         StreamStart = case fxml:get_attr_s(<<"xmpp:restart">>,
-                                           Attrs)
-                           of
-                         <<"true">> -> true;
-                         _ -> false
-                       end,
-         Payload2 = case fxml:get_attr_s(<<"type">>, Attrs) of
-                      <<"terminate">> ->
-                          Payload1 ++ [{xmlstreamend, <<"stream:stream">>}];
-                      _ -> Payload1
-                    end,
-         handle_http_put(Sid, Rid, Attrs, Payload2, PayloadSize,
-                         StreamStart, IP);
-      {size_limit, Sid} ->
-         case mnesia:dirty_read({http_bind, Sid}) of
-           {error, _} -> {404, ?HEADER, <<"">>};
-           {ok, #http_bind{pid = FsmRef}} ->
-               gen_fsm:sync_send_all_state_event(FsmRef,
-                                                 {stop, close}),
-               {200, ?HEADER,
-                <<"<body type='terminate' condition='undefined-c"
-                  "ondition' xmlns='",
-                  (?NS_HTTP_BIND)/binary, "'>Request Too Large</body>">>}
-         end;
-      _ ->
-         ?DEBUG("Received bad request: ~p", [Data]),
-         {400, ?HEADER, <<"">>}
-    end.
-
-handle_session_start(Pid, XmppDomain, Sid, Rid, Attrs,
-                    Payload, PayloadSize, IP) ->
-    ?DEBUG("got pid: ~p", [Pid]),
-    Wait = case str:to_integer(fxml:get_attr_s(<<"wait">>,
-                                             Attrs))
-              of
-            {error, _} -> ?MAX_WAIT;
-            {CWait, _} ->
-                if CWait > (?MAX_WAIT) -> ?MAX_WAIT;
-                   true -> CWait
-                end
-          end,
-    Hold = case str:to_integer(fxml:get_attr_s(<<"hold">>,
-                                             Attrs))
-              of
-            {error, _} -> (?MAX_REQUESTS) - 1;
-            {CHold, _} ->
-                if CHold > (?MAX_REQUESTS) - 1 -> (?MAX_REQUESTS) - 1;
-                   true -> CHold
-                end
-          end,
-    Pdelay = case
-              str:to_integer(fxml:get_attr_s(<<"process-delay">>,
-                                            Attrs))
-                of
-              {error, _} -> ?PROCESS_DELAY_DEFAULT;
-              {CPdelay, _}
-                  when ((?PROCESS_DELAY_MIN) =< CPdelay) and
-                         (CPdelay =< (?PROCESS_DELAY_MAX)) ->
-                  CPdelay;
-              {CPdelay, _} ->
-                  lists:max([lists:min([CPdelay, ?PROCESS_DELAY_MAX]),
-                             ?PROCESS_DELAY_MIN])
-            end,
-    Version = case catch
-                    list_to_float(binary_to_list(fxml:get_attr_s(<<"ver">>, Attrs)))
-                 of
-               {'EXIT', _} -> 0.0;
-               V -> V
-             end,
-    XmppVersion = fxml:get_attr_s(<<"xmpp:version">>, Attrs),
-    ?DEBUG("Create session: ~p", [Sid]),
-    mnesia:dirty_write(
-      #http_bind{id = Sid,
-                 pid = Pid,
-                 to = {XmppDomain,
-                       XmppVersion},
-                 hold = Hold,
-                 wait = Wait,
-                 process_delay = Pdelay,
-                 version = Version
-                }),
-    handle_http_put(Sid, Rid, Attrs, Payload, PayloadSize, true, IP).
-
-%%%----------------------------------------------------------------------
-%%% Callback functions from gen_fsm
-%%%----------------------------------------------------------------------
-
-init([Sid, Key, IP, HOpts]) ->
-    ?DEBUG("started: ~p", [{Sid, Key, IP}]),
-    Opts1 = ejabberd_c2s_config:get_c2s_limits(),
-    SOpts = lists:filtermap(fun({stream_management, _}) -> true;
-                               ({max_ack_queue, _}) -> true;
-                               ({ack_timeout, _}) -> true;
-                               ({resume_timeout, _}) -> true;
-                               ({max_resume_timeout, _}) -> true;
-                               ({resend_on_timeout, _}) -> true;
-                               (_) -> false
-                            end, HOpts),
-
-    Opts = [{xml_socket, true} | SOpts ++ Opts1],
-    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}}.
-
-handle_event({become_controller, C2SPid}, StateName, StateData) ->
-    case StateData#state.input of
-      cancel ->
-         {next_state, StateName,
-          StateData#state{waiting_input = C2SPid}};
-      Input ->
-         lists:foreach(fun (Event) -> C2SPid ! Event end,
-                       queue:to_list(Input)),
-         {next_state, StateName,
-          StateData#state{input = queue:new(),
-                          waiting_input = C2SPid}}
-    end;
-handle_event({change_shaper, Shaper}, StateName,
-            StateData) ->
-    NewShaperState = shaper:new(Shaper),
-    {next_state, StateName,
-     StateData#state{shaper_state = NewShaperState}};
-handle_event(_Event, StateName, StateData) ->
-    {next_state, StateName, StateData}.
-
-handle_sync_event({send_xml, Packet}, _From, StateName,
-                 #state{http_receiver = undefined} = StateData) ->
-    Output = [Packet | StateData#state.output],
-    Reply = ok,
-    {reply, Reply, StateName,
-     StateData#state{output = Output}};
-handle_sync_event({send_xml, Packet}, _From, StateName,
-                 #state{out_of_order_receiver = true} = StateData) ->
-    Output = [Packet | StateData#state.output],
-    Reply = ok,
-    {reply, Reply, StateName,
-     StateData#state{output = Output}};
-handle_sync_event({send_xml, Packet}, _From, StateName,
-                 StateData) ->
-    Output = [Packet | StateData#state.output],
-    cancel_timer(StateData#state.timer),
-    Timer = set_inactivity_timer(StateData#state.pause,
-                                StateData#state.max_inactivity),
-    HTTPReply = {ok, Output},
-    gen_fsm:reply(StateData#state.http_receiver, HTTPReply),
-    cancel_timer(StateData#state.wait_timer),
-    Rid = StateData#state.rid,
-    ReqList = [#hbr{rid = Rid, key = StateData#state.key,
-                   out = Output}
-              | [El
-                 || El <- StateData#state.req_list, El#hbr.rid /= Rid]],
-    Reply = ok,
-    {reply, Reply, StateName,
-     StateData#state{output = [], http_receiver = undefined,
-                    req_list = ReqList, wait_timer = undefined,
-                    timer = Timer}};
-
-handle_sync_event({stop,close}, _From, _StateName, StateData) ->
-    Reply = ok,
-    {stop, normal, Reply, StateData};
-handle_sync_event({stop,stream_closed}, _From, _StateName, StateData) ->
-    Reply = ok,
-    {stop, normal, Reply, StateData};
-handle_sync_event({stop,Reason}, _From, _StateName, StateData) ->
-    ?DEBUG("Closing bind session ~p - Reason: ~p", [StateData#state.id, Reason]),
-    Reply = ok,
-    {stop, normal, Reply, StateData};
-%% HTTP PUT: Receive packets from the client
-handle_sync_event(#http_put{rid = Rid}, _From,
-                 StateName, StateData)
-    when StateData#state.shaper_timer /= undefined ->
-    Pause = case
-             erlang:read_timer(StateData#state.shaper_timer)
-               of
-             false -> 0;
-             P -> P
-           end,
-    Reply = {wait, Pause},
-    ?DEBUG("Shaper timer for RID ~p: ~p", [Rid, Reply]),
-    {reply, Reply, StateName, StateData};
-handle_sync_event(#http_put{payload_size =
-                               PayloadSize} =
-                     Request,
-                 _From, StateName, StateData) ->
-    ?DEBUG("New request: ~p", [Request]),
-    {NewShaperState, NewShaperTimer} =
-       update_shaper(StateData#state.shaper_state,
-                     PayloadSize),
-    handle_http_put_event(Request, StateName,
-                         StateData#state{shaper_state = NewShaperState,
-                                         shaper_timer = NewShaperTimer});
-%% HTTP GET: send packets to the client
-handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) ->
-    TNow = p1_time_compat:system_time(micro_seconds),
-    if (Hold > 0) and
-       ((StateData#state.output == []) or (StateData#state.rid < Rid)) and
-       ((TNow - StateData#state.ctime) < (Wait*1000*1000)) and
-       (StateData#state.rid =< Rid) and
-       (StateData#state.pause == 0) ->
-           send_receiver_reply(StateData#state.http_receiver, {ok, empty}),
-           cancel_timer(StateData#state.wait_timer),
-           WaitTimer = erlang:start_timer(Wait * 1000, self(), []),
-           cancel_timer(StateData#state.timer),
-           {next_state, StateName, StateData#state{
-                                     http_receiver = From,
-                                     out_of_order_receiver = StateData#state.rid < Rid,
-                                     wait_timer = WaitTimer,
-                                     timer = undefined}};
-       true ->
-           cancel_timer(StateData#state.timer),
-           Reply = {ok, StateData#state.output},
-           ReqList = [#hbr{rid = Rid,
-                           key = StateData#state.key,
-                           out = StateData#state.output}
-                     | [El
-                        || El <- StateData#state.req_list,
-                           El#hbr.rid /= Rid]],
-           if (StateData#state.http_receiver /= undefined) and
-                       StateData#state.out_of_order_receiver ->
-                   {reply, Reply, StateName,
-                       StateData#state{output = [], timer = undefined,
-                           req_list = ReqList,
-                           out_of_order_receiver = false}};
-               true ->
-                   send_receiver_reply(StateData#state.http_receiver, {ok, empty}),
-                   cancel_timer(StateData#state.wait_timer),
-                   Timer = set_inactivity_timer(StateData#state.pause,
-                           StateData#state.max_inactivity),
-                   {reply, Reply, StateName,
-                       StateData#state{output = [],
-                           http_receiver = undefined,
-                           wait_timer = undefined,
-                           timer = Timer,
-                           req_list = ReqList}}
-           end
-    end;
-handle_sync_event(peername, _From, StateName,
-                 StateData) ->
-    Reply = {ok, StateData#state.ip},
-    {reply, Reply, StateName, StateData};
-handle_sync_event(_Event, _From, StateName,
-                 StateData) ->
-    Reply = ok, {reply, Reply, StateName, StateData}.
-
-code_change(_OldVsn, StateName, StateData, _Extra) ->
-    {ok, StateName, StateData}.
-
-handle_info({timeout, Timer, _}, _StateName,
-           #state{id = SID, timer = Timer} = StateData) ->
-    ?INFO_MSG("Session timeout. Closing the HTTP bind "
-             "session: ~p",
-             [SID]),
-    {stop, normal, StateData};
-handle_info({timeout, WaitTimer, _}, StateName,
-           #state{wait_timer = WaitTimer} = StateData) ->
-    if StateData#state.http_receiver /= undefined ->
-          cancel_timer(StateData#state.timer),
-          Timer = set_inactivity_timer(StateData#state.pause,
-                                       StateData#state.max_inactivity),
-          gen_fsm:reply(StateData#state.http_receiver,
-                        {ok, empty}),
-          Rid = StateData#state.rid,
-          ReqList = [#hbr{rid = Rid, key = StateData#state.key,
-                          out = []}
-                     | [El
-                        || El <- StateData#state.req_list, El#hbr.rid /= Rid]],
-          {next_state, StateName,
-           StateData#state{http_receiver = undefined,
-                           req_list = ReqList, wait_timer = undefined,
-                           timer = Timer}};
-       true -> {next_state, StateName, StateData}
-    end;
-handle_info({timeout, ShaperTimer, _}, StateName,
-           #state{shaper_timer = ShaperTimer} = StateData) ->
-    {next_state, StateName, StateData#state{shaper_timer = undefined}};
-
-handle_info(_, StateName, StateData) ->
-    {next_state, StateName, StateData}.
-
-terminate(_Reason, _StateName, StateData) ->
-    ?DEBUG("terminate: Deleting session ~s",
-          [StateData#state.id]),
-    mnesia:dirty_delete({http_bind, StateData#state.id}),
-    send_receiver_reply(StateData#state.http_receiver,
-                       {ok, terminate}),
-    case StateData#state.waiting_input of
-      false -> ok;
-      C2SPid -> gen_fsm:send_event(C2SPid, closed)
-    end,
-    ok.
-
-%%%----------------------------------------------------------------------
-%%% Internal functions
-%%%----------------------------------------------------------------------
-
-%% PUT / Get processing:
-handle_http_put_event(#http_put{rid = Rid,
-                               attrs = Attrs, hold = Hold} =
-                         Request,
-                     StateName, StateData) ->
-    ?DEBUG("New request: ~p", [Request]),
-    RidAllow = rid_allow(StateData#state.rid, Rid, Attrs,
-                        Hold, StateData#state.max_pause),
-    case RidAllow of
-      buffer ->
-         ?DEBUG("Buffered request: ~p", [Request]),
-         PendingRequests = StateData#state.unprocessed_req_list,
-         Requests = lists:keydelete(Rid, 2, PendingRequests),
-         ReqList = [#hbr{rid = Rid, key = StateData#state.key,
-                         out = []}
-                    | [El
-                       || El <- StateData#state.req_list,
-                          El#hbr.rid > Rid - 1 - Hold]],
-         ?DEBUG("reqlist: ~p", [ReqList]),
-         UnprocessedReqList = [Request | Requests],
-         cancel_timer(StateData#state.timer),
-         Timer = set_inactivity_timer(0,
-                                      StateData#state.max_inactivity),
-         {reply, ok, StateName,
-          StateData#state{unprocessed_req_list =
-                              UnprocessedReqList,
-                          req_list = ReqList, timer = Timer},
-          hibernate};
-      _ ->
-         process_http_put(Request, StateName, StateData,
-                          RidAllow)
-    end.
-
-process_http_put(#http_put{rid = Rid, attrs = Attrs,
-                          payload = Payload, hold = Hold, stream = StreamTo,
-                          ip = IP} =
-                    Request,
-                StateName, StateData, RidAllow) ->
-    ?DEBUG("Actually processing request: ~p", [Request]),
-    Key = fxml:get_attr_s(<<"key">>, Attrs),
-    NewKey = fxml:get_attr_s(<<"newkey">>, Attrs),
-    KeyAllow = case RidAllow of
-                repeat -> true;
-                false -> false;
-                {true, _} ->
-                    case StateData#state.key of
-                      <<"">> -> true;
-                      OldKey ->
-                          NextKey = p1_sha:sha(Key),
-                          ?DEBUG("Key/OldKey/NextKey: ~s/~s/~s",
-                                 [Key, OldKey, NextKey]),
-                          if OldKey == NextKey -> true;
-                             true -> ?DEBUG("wrong key: ~s", [Key]), false
-                          end
-                    end
-              end,
-    TNow = p1_time_compat:system_time(micro_seconds),
-    LastPoll = if Payload == [] -> TNow;
-                 true -> 0
-              end,
-    if (Payload == []) and (Hold == 0) and
-        (TNow - StateData#state.last_poll < (?MIN_POLLING)) ->
-          Reply = {error, polling_too_frequently},
-          {reply, Reply, StateName, StateData};
-       KeyAllow ->
-          case RidAllow of
-            false ->
-                Reply = {error, not_exists},
-                {reply, Reply, StateName, StateData};
-            repeat ->
-                ?DEBUG("REPEATING ~p", [Rid]),
-                case [El#hbr.out
-                      || El <- StateData#state.req_list, El#hbr.rid == Rid]
-                    of
-                  [] -> {error, not_exists};
-                  [Out | _XS] ->
-                      if (Rid == StateData#state.rid) and
-                           (StateData#state.http_receiver /= undefined) ->
-                             {reply, ok, StateName, StateData};
-                         true ->
-                             Reply = {repeat, lists:reverse(Out)},
-                             {reply, Reply, StateName,
-                              StateData#state{last_poll = LastPoll}}
-                      end
-                end;
-            {true, Pause} ->
-                SaveKey = if NewKey == <<"">> -> Key;
-                             true -> NewKey
-                          end,
-                ?DEBUG(" -- SaveKey: ~s~n", [SaveKey]),
-                ReqList1 = [El
-                            || El <- StateData#state.req_list,
-                               El#hbr.rid > Rid - 1 - Hold],
-                ReqList = case lists:keymember(Rid, #hbr.rid, ReqList1)
-                              of
-                            true -> ReqList1;
-                            false ->
-                                [#hbr{rid = Rid, key = StateData#state.key,
-                                      out = []}
-                                 | ReqList1]
-                          end,
-                ?DEBUG("reqlist: ~p", [ReqList]),
-                cancel_timer(StateData#state.timer),
-                Timer = set_inactivity_timer(Pause,
-                                             StateData#state.max_inactivity),
-                case StateData#state.waiting_input of
-                  false ->
-                      Input = lists:foldl(fun queue:in/2,
-                                          StateData#state.input, Payload),
-                      Reply = ok,
-                      process_buffered_request(Reply, StateName,
-                                               StateData#state{input = Input,
-                                                               rid = Rid,
-                                                               key = SaveKey,
-                                                               ctime = TNow,
-                                                               timer = Timer,
-                                                               pause = Pause,
-                                                               last_poll =
-                                                                   LastPoll,
-                                                               req_list =
-                                                                   ReqList,
-                                                               ip = IP});
-                  C2SPid ->
-                      case StreamTo of
-                        {To, <<"">>} ->
-                            gen_fsm:send_event(C2SPid,
-                                               {xmlstreamstart,
-                                                <<"stream:stream">>,
-                                                [{<<"to">>, To},
-                                                 {<<"xmlns">>, ?NS_CLIENT},
-                                                 {<<"xmlns:stream">>,
-                                                  ?NS_STREAM}]});
-                        {To, Version} ->
-                            gen_fsm:send_event(C2SPid,
-                                               {xmlstreamstart,
-                                                <<"stream:stream">>,
-                                                [{<<"to">>, To},
-                                                 {<<"xmlns">>, ?NS_CLIENT},
-                                                 {<<"version">>, Version},
-                                                 {<<"xmlns:stream">>,
-                                                  ?NS_STREAM}]});
-                        _ -> ok
-                      end,
-                      MaxInactivity = get_max_inactivity(StreamTo,
-                                                         StateData#state.max_inactivity),
-                      MaxPause = get_max_inactivity(StreamTo,
-                                                    StateData#state.max_pause),
-                      ?DEBUG("really sending now: ~p", [Payload]),
-                      lists:foreach(fun ({xmlstreamend, End}) ->
-                                            gen_fsm:send_event(C2SPid,
-                                                               {xmlstreamend,
-                                                                End});
-                                        (El) ->
-                                            gen_fsm:send_event(C2SPid,
-                                                               {xmlstreamelement,
-                                                                El})
-                                    end,
-                                    Payload),
-                      Reply = ok,
-                      process_buffered_request(Reply, StateName,
-                                               StateData#state{input =
-                                                                   queue:new(),
-                                                               rid = Rid,
-                                                               key = SaveKey,
-                                                               ctime = TNow,
-                                                               timer = Timer,
-                                                               pause = Pause,
-                                                               last_poll =
-                                                                   LastPoll,
-                                                               req_list =
-                                                                   ReqList,
-                                                               max_inactivity =
-                                                                   MaxInactivity,
-                                                               max_pause =
-                                                                   MaxPause,
-                                                               ip = IP})
-                end
-          end;
-       true ->
-          Reply = {error, bad_key},
-          {reply, Reply, StateName, StateData}
-    end.
-
-process_buffered_request(Reply, StateName, StateData) ->
-    Rid = StateData#state.rid,
-    Requests = StateData#state.unprocessed_req_list,
-    case lists:keysearch(Rid + 1, 2, Requests) of
-      {value, Request} ->
-         ?DEBUG("Processing buffered request: ~p", [Request]),
-         NewRequests = lists:keydelete(Rid + 1, 2, Requests),
-         handle_http_put_event(Request, StateName,
-                               StateData#state{unprocessed_req_list =
-                                                   NewRequests});
-      _ -> {reply, Reply, StateName, StateData, hibernate}
-    end.
-
-handle_http_put(Sid, Rid, Attrs, Payload, PayloadSize,
-               StreamStart, IP) ->
-    case http_put(Sid, Rid, Attrs, Payload, PayloadSize,
-                 StreamStart, IP)
-       of
-      {error, not_exists} ->
-         ?DEBUG("no session associated with sid: ~p", [Sid]),
-         {404, ?HEADER, <<"">>};
-      {{error, Reason}, Sess} ->
-         ?DEBUG("Error on HTTP put. Reason: ~p", [Reason]),
-         handle_http_put_error(Reason, Sess);
-      {{repeat, OutPacket}, Sess} ->
-         ?DEBUG("http_put said 'repeat!' ...~nOutPacket: ~p",
-                [OutPacket]),
-         send_outpacket(Sess, OutPacket);
-      {{wait, Pause}, _Sess} ->
-         ?DEBUG("Trafic Shaper: Delaying request ~p", [Rid]),
-         timer:sleep(Pause),
-         handle_http_put(Sid, Rid, Attrs, Payload, PayloadSize,
-                         StreamStart, IP);
-      {ok, Sess} ->
-         prepare_response(Sess, Rid, [], StreamStart)
-    end.
-
-http_put(Sid, Rid, Attrs, Payload, PayloadSize,
-        StreamStart, IP) ->
-    ?DEBUG("Looking for session: ~p", [Sid]),
-    case mnesia:dirty_read({http_bind, Sid}) of
-       [] ->
-           {error, not_exists};
-       [#http_bind{pid = FsmRef, hold=Hold,
-                   to= {To, StreamVersion}} = Sess] ->
-           NewStream = case StreamStart of
-               true -> {To, StreamVersion};
-               _ -> <<"">>
-           end,
-           {gen_fsm:sync_send_all_state_event(
-                   FsmRef, #http_put{rid = Rid,
-                           attrs = Attrs,
-                           payload = Payload,
-                           payload_size = PayloadSize,
-                           hold = Hold,
-                           stream = NewStream,
-                           ip = IP},
-                       30000), Sess}
-    end.
-
-handle_http_put_error(Reason,
-                     #http_bind{pid = FsmRef, version = Version})
-    when Version >= 0 ->
-    gen_fsm:sync_send_all_state_event(FsmRef,
-                                     {stop, {put_error, Reason}}),
-    case Reason of
-      not_exists ->
-         {200, ?HEADER,
-          fxml:element_to_binary(#xmlel{name = <<"body">>,
-                                       attrs =
-                                           [{<<"xmlns">>, ?NS_HTTP_BIND},
-                                            {<<"type">>, <<"terminate">>},
-                                            {<<"condition">>,
-                                             <<"item-not-found">>}],
-                                       children = []})};
-      bad_key ->
-         {200, ?HEADER,
-          fxml:element_to_binary(#xmlel{name = <<"body">>,
-                                       attrs =
-                                           [{<<"xmlns">>, ?NS_HTTP_BIND},
-                                            {<<"type">>, <<"terminate">>},
-                                            {<<"condition">>,
-                                             <<"item-not-found">>}],
-                                       children = []})};
-      polling_too_frequently ->
-         {200, ?HEADER,
-          fxml:element_to_binary(#xmlel{name = <<"body">>,
-                                       attrs =
-                                           [{<<"xmlns">>, ?NS_HTTP_BIND},
-                                            {<<"type">>, <<"terminate">>},
-                                            {<<"condition">>,
-                                             <<"policy-violation">>}],
-                                       children = []})}
-    end;
-handle_http_put_error(Reason,
-                     #http_bind{pid = FsmRef}) ->
-    gen_fsm:sync_send_all_state_event(FsmRef,
-                                     {stop, {put_error_no_version, Reason}}),
-    case Reason of
-      not_exists -> %% bad rid
-         ?DEBUG("Closing HTTP bind session (Bad rid).", []),
-         {404, ?HEADER, <<"">>};
-      bad_key ->
-         ?DEBUG("Closing HTTP bind session (Bad key).", []),
-         {404, ?HEADER, <<"">>};
-      polling_too_frequently ->
-         ?DEBUG("Closing HTTP bind session (User polling "
-                "too frequently).",
-                []),
-         {403, ?HEADER, <<"">>}
-    end.
-
-%% Control RID ordering
-rid_allow(none, _NewRid, _Attrs, _Hold, _MaxPause) ->
-    {true, 0};
-rid_allow(OldRid, NewRid, Attrs, Hold, MaxPause) ->
-    ?DEBUG("Previous rid / New rid: ~p/~p",
-          [OldRid, NewRid]),
-    if
-      %% We did not miss any packet, we can process it immediately:
-      NewRid == OldRid + 1 ->
-         case catch
-                binary_to_integer(fxml:get_attr_s(<<"pause">>,
-                                                        Attrs))
-             of
-           {'EXIT', _} -> {true, 0};
-           Pause1 when Pause1 =< MaxPause ->
-               ?DEBUG("got pause: ~p", [Pause1]), {true, Pause1};
-           _ -> {true, 0}
-         end;
-      %% We have missed packets, we need to cached it to process it later on:
-      (OldRid < NewRid) and (NewRid =< OldRid + Hold + 1) ->
-         buffer;
-      (NewRid =< OldRid) and (NewRid > OldRid - Hold - 1) ->
-         repeat;
-      true -> false
-    end.
-
-update_shaper(ShaperState, PayloadSize) ->
-    {NewShaperState, Pause} = shaper:update(ShaperState,
-                                           PayloadSize),
-    if Pause > 0 ->
-          ShaperTimer = erlang:start_timer(Pause, self(),
-                                           activate),
-          {NewShaperState, ShaperTimer};
-       true -> {NewShaperState, undefined}
-    end.
-
-prepare_response(Sess, Rid, OutputEls, StreamStart) ->
-    receive  after Sess#http_bind.process_delay -> ok end,
-    case catch http_get(Sess, Rid) of
-      {ok, cancel} ->
-         {200, ?HEADER,
-          <<"<body type='error' xmlns='", (?NS_HTTP_BIND)/binary,
-            "'/>">>};
-      {ok, empty} ->
-         {200, ?HEADER,
-          <<"<body xmlns='", (?NS_HTTP_BIND)/binary, "'/>">>};
-      {ok, terminate} ->
-         {200, ?HEADER,
-          <<"<body type='terminate' xmlns='",
-            (?NS_HTTP_BIND)/binary, "'/>">>};
-      {ok, ROutPacket} ->
-         OutPacket = lists:reverse(ROutPacket),
-         ?DEBUG("OutPacket: ~p", [OutputEls ++ OutPacket]),
-         prepare_outpacket_response(Sess, Rid,
-                                    OutputEls ++ OutPacket, StreamStart);
-      {'EXIT', {shutdown, _}} ->
-         {200, ?HEADER,
-          <<"<body type='terminate' condition='system-shut"
-            "down' xmlns='",
-            (?NS_HTTP_BIND)/binary, "'/>">>};
-      {'EXIT', _Reason} ->
-         {200, ?HEADER,
-          <<"<body type='terminate' xmlns='",
-            (?NS_HTTP_BIND)/binary, "'/>">>}
-    end.
-
-%% Send output payloads on establised sessions
-prepare_outpacket_response(Sess, _Rid, OutPacket,
-                          false) ->
-    case catch send_outpacket(Sess, OutPacket) of
-      {'EXIT', _Reason} ->
-         ?DEBUG("Error in sending packet ~p ", [_Reason]),
-         {200, ?HEADER,
-          <<"<body type='terminate' xmlns='",
-            (?NS_HTTP_BIND)/binary, "'/>">>};
-      SendRes -> SendRes
-    end;
-%% Handle a new session along with its output payload
-prepare_outpacket_response(#http_bind{id = Sid,
-                                     wait = Wait, hold = Hold, to = To} =
-                              _Sess,
-                          _Rid, OutPacket, true) ->
-    case OutPacket of
-      [{xmlstreamstart, _, OutAttrs} | Els] ->
-         AuthID = fxml:get_attr_s(<<"id">>, OutAttrs),
-         From = fxml:get_attr_s(<<"from">>, OutAttrs),
-         Version = fxml:get_attr_s(<<"version">>, OutAttrs),
-         OutEls = case Els of
-                    [] -> [];
-                    [{xmlstreamelement,
-                      #xmlel{name = <<"stream:features">>,
-                             attrs = StreamAttribs, children = StreamEls}}
-                     | StreamTail] ->
-                        TypedTail = [check_default_xmlns(OEl)
-                                     || {xmlstreamelement, OEl} <- StreamTail],
-                        [#xmlel{name = <<"stream:features">>,
-                                attrs =
-                                    [{<<"xmlns:stream">>, ?NS_STREAM}] ++
-                                      StreamAttribs,
-                                children = StreamEls}]
-                          ++ TypedTail;
-                    StreamTail ->
-                        [check_default_xmlns(OEl)
-                         || {xmlstreamelement, OEl} <- StreamTail]
-                  end,
-         case OutEls of
-           [#xmlel{name = <<"stream:error">>}] ->
-               {200, ?HEADER,
-                <<"<body type='terminate' condition='host-unknow"
-                  "n' xmlns='",
-                  (?NS_HTTP_BIND)/binary, "'/>">>};
-           _ ->
-               BOSH_attribs = [{<<"authid">>, AuthID},
-                               {<<"xmlns:xmpp">>, ?NS_BOSH},
-                               {<<"xmlns:stream">>, ?NS_STREAM}]
-                                ++
-                                case OutEls of
-                                  [] -> [];
-                                  _ -> [{<<"xmpp:version">>, Version}]
-                                end,
-               MaxInactivity = get_max_inactivity(To, ?MAX_INACTIVITY),
-               MaxPause = get_max_pause(To),
-               {200, ?HEADER,
-                fxml:element_to_binary(#xmlel{name = <<"body">>,
-                                             attrs =
-                                                 [{<<"xmlns">>, ?NS_HTTP_BIND},
-                                                  {<<"sid">>, Sid},
-                                                  {<<"wait">>,
-                                                   integer_to_binary(Wait)},
-                                                  {<<"requests">>,
-                                                   integer_to_binary(Hold + 1)},
-                                                  {<<"inactivity">>,
-                                                   integer_to_binary(
-                                                     trunc(MaxInactivity / 1000))},
-                                                  {<<"maxpause">>,
-                                                   integer_to_binary(MaxPause)},
-                                                  {<<"polling">>,
-                                                   integer_to_binary(
-                                                     trunc((?MIN_POLLING) / 1000000))},
-                                                  {<<"ver">>, ?BOSH_VERSION},
-                                                  {<<"from">>, From},
-                                                  {<<"secure">>, <<"true">>}]
-                                                   ++ BOSH_attribs,
-                                             children = OutEls})}
-         end;
-      _ ->
-         {200, ?HEADER,
-          <<"<body type='terminate' condition='internal-se"
-            "rver-error' xmlns='",
-            (?NS_HTTP_BIND)/binary, "'/>">>}
-    end.
-
-http_get(#http_bind{pid = FsmRef, wait = Wait,
-                   hold = Hold},
-        Rid) ->
-    gen_fsm:sync_send_all_state_event(FsmRef,
-                                     {http_get, Rid, Wait, Hold},
-                                     2 * (?MAX_WAIT) * 1000).
-
-send_outpacket(#http_bind{pid = FsmRef}, OutPacket) ->
-    case OutPacket of
-      [] ->
-         {200, ?HEADER,
-          <<"<body xmlns='", (?NS_HTTP_BIND)/binary, "'/>">>};
-      [{xmlstreamend, _}] ->
-         gen_fsm:sync_send_all_state_event(FsmRef,
-                                           {stop, stream_closed}),
-         {200, ?HEADER,
-          <<"<body xmlns='", (?NS_HTTP_BIND)/binary, "'/>">>};
-      _ ->
-         AllElements = lists:all(fun ({xmlstreamelement,
-                                       #xmlel{name = <<"stream:error">>}}) ->
-                                         false;
-                                     ({xmlstreamelement, _}) -> true;
-                                     ({xmlstreamraw, _}) -> true;
-                                     (_) -> false
-                                 end,
-                                 OutPacket),
-         case AllElements of
-           true ->
-               TypedEls = lists:foldl(fun ({xmlstreamelement, El},
-                                           Acc) ->
-                                              Acc ++
-                                                [fxml:element_to_binary(check_default_xmlns(El))];
-                                          ({xmlstreamraw, R}, Acc) ->
-                                              Acc ++ [R]
-                                      end,
-                                      [], OutPacket),
-               Body = <<"<body xmlns='", (?NS_HTTP_BIND)/binary, "'>",
-                        (iolist_to_binary(TypedEls))/binary, "</body>">>,
-               ?DEBUG(" --- outgoing data --- ~n~s~n --- END "
-                      "--- ~n",
-                      [Body]),
-               {200, ?HEADER, Body};
-           false ->
-               case OutPacket of
-                 [{xmlstreamstart, _, _} | SEls] ->
-                     OutEls = case SEls of
-                                [{xmlstreamelement,
-                                  #xmlel{name = <<"stream:features">>,
-                                         attrs = StreamAttribs,
-                                         children = StreamEls}}
-                                 | StreamTail] ->
-                                    TypedTail = [check_default_xmlns(OEl)
-                                                 || {xmlstreamelement, OEl}
-                                                        <- StreamTail],
-                                    [#xmlel{name = <<"stream:features">>,
-                                            attrs =
-                                                [{<<"xmlns:stream">>,
-                                                  ?NS_STREAM}]
-                                                  ++ StreamAttribs,
-                                            children = StreamEls}]
-                                      ++ TypedTail;
-                                StreamTail ->
-                                    [check_default_xmlns(OEl)
-                                     || {xmlstreamelement, OEl} <- StreamTail]
-                              end,
-                     {200, ?HEADER,
-                      fxml:element_to_binary(#xmlel{name = <<"body">>,
-                                                   attrs =
-                                                       [{<<"xmlns">>,
-                                                         ?NS_HTTP_BIND}],
-                                                   children = OutEls})};
-                 _ ->
-                     SErrCond = lists:filter(fun ({xmlstreamelement,
-                                                   #xmlel{name =
-                                                              <<"stream:error">>}}) ->
-                                                     true;
-                                                 (_) -> false
-                                             end,
-                                             OutPacket),
-                     StreamErrCond = case SErrCond of
-                                       [] -> null;
-                                       [{xmlstreamelement,
-                                         #xmlel{} = StreamErrorTag}
-                                        | _] ->
-                                           [StreamErrorTag]
-                                     end,
-                     gen_fsm:sync_send_all_state_event(FsmRef,
-                                                       {stop,
-                                                        {stream_error,
-                                                         OutPacket}}),
-                     case StreamErrCond of
-                       null ->
-                           {200, ?HEADER,
-                            <<"<body type='terminate' condition='internal-se"
-                              "rver-error' xmlns='",
-                              (?NS_HTTP_BIND)/binary, "'/>">>};
-                       _ ->
-                           {200, ?HEADER,
-                            <<"<body type='terminate' condition='remote-stre"
-                              "am-error' xmlns='",
-                              (?NS_HTTP_BIND)/binary, "' ", "xmlns:stream='",
-                              (?NS_STREAM)/binary, "'>",
-                              (elements_to_string(StreamErrCond))/binary,
-                              "</body>">>}
-                     end
-               end
-         end
-    end.
-
-parse_request(Data, PayloadSize, MaxStanzaSize) ->
-    ?DEBUG("--- incoming data --- ~n~s~n --- END "
-          "--- ",
-          [Data]),
-    case fxml_stream:parse_element(Data) of
-      #xmlel{name = <<"body">>, attrs = Attrs,
-            children = Els} ->
-         Xmlns = fxml:get_attr_s(<<"xmlns">>, Attrs),
-         if Xmlns /= (?NS_HTTP_BIND) -> {error, bad_request};
-            true ->
-                case catch
-                       binary_to_integer(fxml:get_attr_s(<<"rid">>,
-                                                               Attrs))
-                    of
-                  {'EXIT', _} -> {error, bad_request};
-                  Rid ->
-                      FixedEls = lists:filter(fun (I) ->
-                                                      case I of
-                                                        #xmlel{} -> true;
-                                                        _ -> false
-                                                      end
-                                              end,
-                                              Els),
-                      Sid = fxml:get_attr_s(<<"sid">>, Attrs),
-                      if PayloadSize =< MaxStanzaSize ->
-                             {ok, {Sid, Rid, Attrs, FixedEls}};
-                         true -> {size_limit, Sid}
-                      end
-                end
-         end;
-      #xmlel{} -> {error, bad_request};
-      {error, _Reason} -> {error, bad_request}
-    end.
-
-send_receiver_reply(undefined, _Reply) -> ok;
-send_receiver_reply(Receiver, Reply) ->
-    gen_fsm:reply(Receiver, Reply).
-
-%% Cancel timer and empty message queue.
-cancel_timer(undefined) -> ok;
-cancel_timer(Timer) ->
-    erlang:cancel_timer(Timer),
-    receive {timeout, Timer, _} -> ok after 0 -> ok end.
-
-%% If client asked for a pause (pause > 0), we apply the pause value
-%% as inactivity timer:
-set_inactivity_timer(Pause, _MaxInactivity)
-    when Pause > 0 ->
-    erlang:start_timer(Pause * 1000, self(), []);
-%% Otherwise, we apply the max_inactivity value as inactivity timer:
-set_inactivity_timer(_Pause, MaxInactivity) ->
-    erlang:start_timer(MaxInactivity, self(), []).
-
-elements_to_string([]) -> [];
-elements_to_string([El | Els]) ->
-    [fxml:element_to_binary(El) | elements_to_string(Els)].
-
-%% @spec (To, Default::integer()) -> integer()
-%% where To = [] | {Host::string(), Version::string()}
-get_max_inactivity({Host, _}, Default) ->
-    case gen_mod:get_module_opt(Host, mod_http_bind, max_inactivity,
-                                fun(I) when is_integer(I), I>0 -> I end,
-                                undefined)
-       of
-      Seconds when is_integer(Seconds) -> Seconds * 1000;
-      undefined -> Default
-    end;
-get_max_inactivity(_, Default) -> Default.
-
-get_max_pause({Host, _}) ->
-    gen_mod:get_module_opt(Host, mod_http_bind, max_pause,
-                           fun(I) when is_integer(I), I>0 -> I end,
-                          ?MAX_PAUSE);
-get_max_pause(_) -> ?MAX_PAUSE.
-
-check_default_xmlns(#xmlel{name = Name, attrs = Attrs,
-                          children = Els} =
-                       El) ->
-    case fxml:get_tag_attr_s(<<"xmlns">>, El) of
-      <<"">> ->
-         #xmlel{name = Name,
-                attrs = [{<<"xmlns">>, ?NS_CLIENT} | Attrs],
-                children = Els};
-      _ -> El
-    end;
-check_default_xmlns(El) -> El.
-
-%% Check that mod_http_bind has been defined in config file.
-%% Print a warning in log file if this is not the case.
-check_bind_module(XmppDomain) ->
-    case gen_mod:is_loaded(XmppDomain, mod_http_bind) of
-      true -> true;
-      false ->
-         ?ERROR_MSG("You are trying to use BOSH (HTTP Bind) "
-                    "in host ~p, but the module mod_http_bind "
-                    "is not started in that host. Configure "
-                    "your BOSH client to connect to the correct "
-                    "host, or add your desired host to the "
-                    "configuration, or check your 'modules' "
-                    "section in your ejabberd configuration "
-                    "file.",
-                    [XmppDomain]),
-            false
-    end.
index e83fd3f3148b55fd739ed0a7a5c8bde83949917e..f49f768cb37c6e5fdc4b7d90c2f549cb5a4d8cb0 100644 (file)
 -include("ejabberd.hrl").
 -include("logger.hrl").
 
--type sockmod() :: ejabberd_http_bind |
-                  ejabberd_bosh |
+-type sockmod() :: ejabberd_bosh |
                    ejabberd_http_ws |
                    gen_tcp | fast_tls | ezlib.
 -type receiver() :: pid () | atom().
 -type socket() :: pid() | inet:socket() |
                   fast_tls:tls_socket() |
                  ezlib:zlib_socket() |
-                 ejabberd_bosh:bind_socket() |
-                  ejabberd_http_bind:bind_socket().
+                 ejabberd_bosh:bind_socket().
 
 -record(socket_state, {sockmod = gen_tcp :: sockmod(),
                        socket = self() :: socket(),
@@ -231,7 +229,6 @@ get_transport(#socket_state{sockmod = SockMod,
                fast_tls -> tls_zlib
            end;
        ejabberd_bosh -> http_bind;
-       ejabberd_http_bind -> http_bind;
        ejabberd_http_ws -> websocket
     end.
 
index 038218739a6b169231cf245b33b5f60c0aacd660..d3eda4734907274eb44f47d618a536b66e2ec318 100644 (file)
@@ -82,37 +82,6 @@ process(_Path, _Request) ->
      #xmlel{name = <<"h1">>, attrs = [],
            children = [{xmlcdata, <<"400 Bad Request">>}]}}.
 
-get_human_html_xmlel() ->
-    Heading = <<"ejabberd ", (jlib:atom_to_binary(?MODULE))/binary>>,
-    #xmlel{name = <<"html">>,
-          attrs =
-              [{<<"xmlns">>, <<"http://www.w3.org/1999/xhtml">>}],
-          children =
-              [#xmlel{name = <<"head">>, attrs = [],
-                      children =
-                          [#xmlel{name = <<"title">>, attrs = [],
-                                  children = [{xmlcdata, Heading}]}]},
-               #xmlel{name = <<"body">>, attrs = [],
-                      children =
-                          [#xmlel{name = <<"h1">>, attrs = [],
-                                  children = [{xmlcdata, Heading}]},
-                           #xmlel{name = <<"p">>, attrs = [],
-                                  children =
-                                      [{xmlcdata, <<"An implementation of ">>},
-                                       #xmlel{name = <<"a">>,
-                                              attrs =
-                                                  [{<<"href">>,
-                                                    <<"http://xmpp.org/extensions/xep-0206.html">>}],
-                                              children =
-                                                  [{xmlcdata,
-                                                    <<"XMPP over BOSH (XEP-0206)">>}]}]},
-                           #xmlel{name = <<"p">>, attrs = [],
-                                  children =
-                                      [{xmlcdata,
-                                        <<"This web page is only informative. To "
-                                          "use HTTP-Bind you need a Jabber/XMPP "
-                                          "client that supports it.">>}]}]}]}.
-
 open_session(SID, Pid) ->
     Session = #bosh{sid = SID, timestamp = p1_time_compat:timestamp(), pid = Pid},
     lists:foreach(
@@ -294,3 +263,130 @@ mod_opt_type(prebind) ->
     fun (B) when is_boolean(B) -> B end;
 mod_opt_type(_) ->
     [json, max_concat, max_inactivity, max_pause, prebind].
+
+
+%%%----------------------------------------------------------------------
+%%% Help Web Page
+%%%----------------------------------------------------------------------
+
+get_human_html_xmlel() ->
+    Heading = <<"ejabberd ",
+               (iolist_to_binary(atom_to_list(?MODULE)))/binary>>,
+    #xmlel{name = <<"html">>,
+          attrs =
+              [{<<"xmlns">>, <<"http://www.w3.org/1999/xhtml">>}],
+          children =
+              [#xmlel{name = <<"head">>,
+                      children =
+                          [#xmlel{name = <<"title">>,
+                                  children = [{xmlcdata, Heading}]},
+                           #xmlel{name = <<"style">>,
+                                  children = [{xmlcdata, get_style_cdata()}]}]},
+               #xmlel{name = <<"body">>,
+                      children =
+                          [#xmlel{name = <<"div">>,
+                                  attrs = [{<<"class">>, <<"container">>}],
+                                  children = get_container_children(Heading)}]}]}.
+
+get_container_children(Heading) ->
+    [#xmlel{name = <<"div">>,
+           attrs = [{<<"class">>, <<"section">>}],
+           children =
+               [#xmlel{name = <<"div">>,
+                       attrs = [{<<"class">>, <<"block">>}],
+                       children =
+                           [#xmlel{name = <<"a">>,
+                                   attrs = [{<<"href">>, <<"https://www.ejabberd.im">>}],
+                                   children =
+                                       [#xmlel{name = <<"img">>,
+                                               attrs = [{<<"height">>, <<"32">>},
+                                                        {<<"src">>, get_image_src()}]}]}]}]},
+     #xmlel{name = <<"div">>,
+           attrs = [{<<"class">>, <<"white section">>}],
+           children =
+               [#xmlel{name = <<"div">>,
+                       attrs = [{<<"class">>, <<"block">>}],
+                       children =
+                           [#xmlel{name = <<"h1">>, children = [{xmlcdata, Heading}]},
+                            #xmlel{name = <<"p">>, children =
+                                       [{xmlcdata, <<"An implementation of ">>},
+                                        #xmlel{name = <<"a">>,
+                                               attrs = [{<<"href">>, <<"http://xmpp.org/extensions/xep-0206.html">>}],
+                                               children = [{xmlcdata, <<"XMPP over BOSH (XEP-0206)">>}]}]},
+                            #xmlel{name = <<"p">>, children =
+                                       [{xmlcdata, <<"This web page is only informative. To "
+                                                     "use HTTP-Bind you need a Jabber/XMPP "
+                                                     "client that supports it.">>}]}]}]},
+     #xmlel{name = <<"div">>,
+           attrs = [{<<"class">>, <<"section">>}],
+           children =
+               [#xmlel{name = <<"div">>,
+                       attrs = [{<<"class">>, <<"block">>}],
+                       children =
+                           [#xmlel{name = <<"a">>,
+                                   attrs = [{<<"href">>, <<"https://www.ejabberd.im">>},
+                                            {<<"title">>, <<"ejabberd XMPP server">>}],
+                                   children = [{xmlcdata, <<"ejabberd">>}]},
+                            {xmlcdata, <<" is maintained by ">>},
+                            #xmlel{name = <<"a">>,
+                                   attrs = [{<<"href">>, <<"https://www.process-one.net">>},
+                                            {<<"title">>, <<"ProcessOne - Leader in Instant Messaging and Push Solutions">>}],
+                                   children = [{xmlcdata, <<"ProcessOne">>}]} ]}]}
+    ].
+
+get_style_cdata() ->
+    <<"
+      body {
+       margin: 0;
+       padding: 0;
+       font-family: sans-serif;
+       color: #fff;
+      }
+      h1 {
+       font-size: 3em;
+       color: #444;
+      }
+      p {
+       line-height: 1.5em;
+       color: #888;
+      }
+      a {
+       color: #fff;
+      }
+      a:hover,
+      a:active {
+       text-decoration: underline;
+      }
+      .container {
+       position: absolute;
+       top: 0;
+       left: 0;
+       right: 0;
+       bottom: 0;
+       background: #424A55;
+       background-image: -webkit-linear-gradient(270deg, rgba(48,52,62,0) 24%, #30353e 100%);
+       background-image: linear-gradient(-180deg, rgba(48,52,62,0) 24%, #30353e 100%);
+      }
+      .section {
+       padding: 3em;
+      }
+      .white.section {
+       background: #fff;
+       border-bottom: 4px solid #41AFCA;
+      }
+      .white.section a {
+       text-decoration: none;
+       color: #41AFCA;
+      }
+      .white.section a:hover,
+      .white.section a:active {
+        text-decoration: underline;
+      }
+      .block {
+       margin: 0 auto;
+       max-width: 900px;
+       width: 100%;
+      }">>.
+
+get_image_src() ->
+    <<"data:image/png;base64,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">>.
diff --git a/src/mod_http_bind.erl b/src/mod_http_bind.erl
deleted file mode 100644 (file)
index 68500f2..0000000
+++ /dev/null
@@ -1,239 +0,0 @@
-%%%----------------------------------------------------------------------
-%%% File    : mod_http_bind.erl
-%%% Author  : Stefan Strigler <steve@zeank.in-berlin.de>
-%%% Purpose : Implementation of XMPP over BOSH (XEP-0206)
-%%% Created : Tue Feb 20 13:15:52 CET 2007
-%%%
-%%%
-%%% ejabberd, Copyright (C) 2002-2016   ProcessOne
-%%%
-%%% This program is free software; you can redistribute it and/or
-%%% modify it under the terms of the GNU General Public License as
-%%% published by the Free Software Foundation; either version 2 of the
-%%% License, or (at your option) any later version.
-%%%
-%%% This program is distributed in the hope that it will be useful,
-%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
-%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-%%% General Public License for more details.
-%%%
-%%% You should have received a copy of the GNU General Public License along
-%%% with this program; if not, write to the Free Software Foundation, Inc.,
-%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-%%%
-%%%----------------------------------------------------------------------
-
-%%%----------------------------------------------------------------------
-%%% This module acts as a bridge to ejabberd_http_bind which implements
-%%% the real stuff, this is to handle the new pluggable architecture for
-%%% extending ejabberd's http service.
-%%%----------------------------------------------------------------------
-
--module(mod_http_bind).
-
--author('steve@zeank.in-berlin.de').
-
-%%-define(ejabberd_debug, true).
-
--behaviour(gen_mod).
-
--export([start/2, stop/1, process/2, mod_opt_type/1, depends/2]).
-
--include("ejabberd.hrl").
--include("logger.hrl").
-
--include("xmpp.hrl").
-
--include("ejabberd_http.hrl").
-
--include("http_bind.hrl").
-
--define(PROCNAME_MHB, ejabberd_mod_http_bind).
-
-%% Duplicated from ejabberd_http_bind.
-%% TODO: move to hrl file.
--record(http_bind,
-       {id, pid, to, hold, wait, process_delay, version}).
-
-%%%----------------------------------------------------------------------
-%%% API
-%%%----------------------------------------------------------------------
-
-process([], #request{method = 'POST', data = <<>>}) ->
-    ?DEBUG("Bad Request: no data", []),
-    {400, ?HEADER,
-     #xmlel{name = <<"h1">>, children = [{xmlcdata, <<"400 Bad Request">>}]}};
-process([],
-       #request{method = 'POST', data = Data, ip = IP, opts = Opts}) ->
-    ?DEBUG("Incoming data: ~s", [Data]),
-    ejabberd_http_bind:process_request(Data, IP, Opts);
-process([], #request{method = 'GET', data = <<>>}) ->
-    {200, ?HEADER, get_human_html_xmlel()};
-process([], #request{method = 'OPTIONS', data = <<>>}) ->
-    {200, ?OPTIONS_HEADER, <<>>};
-process([], #request{method = 'HEAD'}) ->
-    {200, ?HEADER, <<>>};
-process(_Path, _Request) ->
-    ?DEBUG("Bad Request: ~p", [_Request]),
-    {400, ?HEADER,
-     #xmlel{name = <<"h1">>, children = [{xmlcdata, <<"400 Bad Request">>}]}}.
-
-%%%----------------------------------------------------------------------
-%%% BEHAVIOUR CALLBACKS
-%%%----------------------------------------------------------------------
-start(_Host, _Opts) ->
-    setup_database().
-
-stop(_Host) ->
-    ok.
-
-setup_database() ->
-    migrate_database(),
-    ejabberd_mnesia:create(?MODULE, http_bind,
-                       [{ram_copies, [node()]},
-                        {attributes, record_info(fields, http_bind)}]).
-
-migrate_database() ->
-    case catch mnesia:table_info(http_bind, attributes) of
-        [id, pid, to, hold, wait, process_delay, version] ->
-           ok;
-        _ ->
-           %% Since the stored information is not important, instead
-           %% of actually migrating data, let's just destroy the table
-           mnesia:delete_table(http_bind)
-    end.
-
-mod_opt_type(max_inactivity) ->
-    fun (I) when is_integer(I), I > 0 -> I end;
-mod_opt_type(max_pause) ->
-    fun (I) when is_integer(I), I > 0 -> I end;
-mod_opt_type(_) -> [max_inactivity, max_pause].
-
-depends(_Host, _Opts) ->
-    [].
-
-%%%----------------------------------------------------------------------
-%%% Help Web Page
-%%%----------------------------------------------------------------------
-
-get_human_html_xmlel() ->
-    Heading = <<"ejabberd ",
-               (iolist_to_binary(atom_to_list(?MODULE)))/binary>>,
-    #xmlel{name = <<"html">>,
-          attrs =
-              [{<<"xmlns">>, <<"http://www.w3.org/1999/xhtml">>}],
-          children =
-              [#xmlel{name = <<"head">>,
-                      children =
-                          [#xmlel{name = <<"title">>,
-                                  children = [{xmlcdata, Heading}]},
-                           #xmlel{name = <<"style">>,
-                                  children = [{xmlcdata, get_style_cdata()}]}]},
-               #xmlel{name = <<"body">>,
-                      children =
-                          [#xmlel{name = <<"div">>,
-                                  attrs = [{<<"class">>, <<"container">>}],
-                                  children = get_container_children(Heading)}]}]}.
-
-get_container_children(Heading) ->
-    [#xmlel{name = <<"div">>,
-           attrs = [{<<"class">>, <<"section">>}],
-           children =
-               [#xmlel{name = <<"div">>,
-                       attrs = [{<<"class">>, <<"block">>}],
-                       children =
-                           [#xmlel{name = <<"a">>,
-                                   attrs = [{<<"href">>, <<"https://www.ejabberd.im">>}],
-                                   children =
-                                       [#xmlel{name = <<"img">>,
-                                               attrs = [{<<"height">>, <<"32">>},
-                                                        {<<"src">>, get_image_src()}]}]}]}]},
-     #xmlel{name = <<"div">>,
-           attrs = [{<<"class">>, <<"white section">>}],
-           children =
-               [#xmlel{name = <<"div">>,
-                       attrs = [{<<"class">>, <<"block">>}],
-                       children =
-                           [#xmlel{name = <<"h1">>, children = [{xmlcdata, Heading}]},
-                            #xmlel{name = <<"p">>, children =
-                                       [{xmlcdata, <<"An implementation of ">>},
-                                        #xmlel{name = <<"a">>,
-                                               attrs = [{<<"href">>, <<"http://xmpp.org/extensions/xep-0206.html">>}],
-                                               children = [{xmlcdata, <<"XMPP over BOSH (XEP-0206)">>}]}]},
-                            #xmlel{name = <<"p">>, children =
-                                       [{xmlcdata, <<"This web page is only informative. To "
-                                                     "use HTTP-Bind you need a Jabber/XMPP "
-                                                     "client that supports it.">>}]}]}]},
-     #xmlel{name = <<"div">>,
-           attrs = [{<<"class">>, <<"section">>}],
-           children =
-               [#xmlel{name = <<"div">>,
-                       attrs = [{<<"class">>, <<"block">>}],
-                       children =
-                           [#xmlel{name = <<"a">>,
-                                   attrs = [{<<"href">>, <<"https://www.ejabberd.im">>},
-                                            {<<"title">>, <<"ejabberd XMPP server">>}],
-                                   children = [{xmlcdata, <<"ejabberd">>}]},
-                            {xmlcdata, <<" is maintained by ">>},
-                            #xmlel{name = <<"a">>,
-                                   attrs = [{<<"href">>, <<"https://www.process-one.net">>},
-                                            {<<"title">>, <<"ProcessOne - Leader in Instant Messaging and Push Solutions">>}],
-                                   children = [{xmlcdata, <<"ProcessOne">>}]} ]}]}
-    ].
-
-get_style_cdata() ->
-    <<"
-      body {
-        margin: 0;
-        padding: 0;
-        font-family: sans-serif;
-        color: #fff;
-      }
-      h1 {
-        font-size: 3em;
-        color: #444;
-      }
-      p {
-        line-height: 1.5em;
-        color: #888;
-      }
-      a {
-        color: #fff;
-      }
-      a:hover,
-      a:active {
-        text-decoration: underline;
-      }
-      .container {
-        position: absolute;
-        top: 0;
-        left: 0;
-        right: 0;
-        bottom: 0;
-        background: #424A55;
-        background-image: -webkit-linear-gradient(270deg, rgba(48,52,62,0) 24%, #30353e 100%);
-        background-image: linear-gradient(-180deg, rgba(48,52,62,0) 24%, #30353e 100%);
-      }
-      .section {
-        padding: 3em;
-      }
-      .white.section {
-        background: #fff;
-        border-bottom: 4px solid #41AFCA;
-      }
-      .white.section a {
-        text-decoration: none;
-        color: #41AFCA;
-      }
-      .white.section a:hover,
-      .white.section a:active {
-         text-decoration: underline;
-      }
-      .block {
-        margin: 0 auto;
-        max-width: 900px;
-        width: 100%;
-      }">>.
-
-get_image_src() ->
-    <<"data:image/png;base64,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">>.