1 %%%----------------------------------------------------------------------
2 %%% File    : mod_http_bind.erl
3 %%% Author  : Stefan Strigler <[email protected]>
4 %%% Purpose : Implementation of XMPP over BOSH (XEP-0206)
5 %%% Created : Tue Feb 20 13:15:52 CET 2007
6 %%%
7 %%%
8 %%% ejabberd, Copyright (C) 2002-2012   ProcessOne
9 %%%
10 %%% This program is free software; you can redistribute it and/or
11 %%% modify it under the terms of the GNU General Public License as
12 %%% published by the Free Software Foundation; either version 2 of the
13 %%% License, or (at your option) any later version.
14 %%%
15 %%% This program is distributed in the hope that it will be useful,
16 %%% but WITHOUT ANY WARRANTY; without even the implied warranty of
17 %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 %%% General Public License for more details.
19 %%%
20 %%% You should have received a copy of the GNU General Public License
21 %%% along with this program; if not, write to the Free Software
22 %%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
23 %%% 02111-1307 USA
24 %%%
25 %%%----------------------------------------------------------------------
26 
27 
28 %%%----------------------------------------------------------------------
29 %%% This module acts as a bridge to ejabberd_http_bind which implements
30 %%% the real stuff, this is to handle the new pluggable architecture for
31 %%% extending ejabberd's http service.
32 %%%----------------------------------------------------------------------
33 
34 
35 -module(mod_http_bind).
36 
37 -author('[email protected]').
38 
39 %%-define(ejabberd_debug, true).
40 
41 
42 -behaviour(gen_mod).
43 
44 -export([start/2, stop/1, process/2]).
45 
46 -include_lib("exmpp/include/exmpp.hrl").
47 
48 -include("ejabberd.hrl").
49 
50 -include("jlib.hrl").
51 
52 -include("ejabberd_http.hrl").
53 
54 -include("http_bind.hrl").
55 
56 -define(PROCNAME_MHB, ejabberd_mod_http_bind).
57 
58 %% Duplicated from ejabberd_http_bind.
59 %% TODO: move to hrl file.
60 -record(http_bind, {id, pid, to, hold, wait, process_delay, version}).
61 
62 %%%----------------------------------------------------------------------
63 %%% API
64 %%%----------------------------------------------------------------------
65 
66 
67 process([], #request{method = 'POST', data = []}) ->
68     ?DEBUG("Bad Request: no data", []),
69     {400, ?HEADER,
70      #xmlel{name = h1,
71 	    children = [#xmlcdata{cdata = <<"400 Bad Request">>}]}};
72 process([], #request{method = 'POST', data = Data, ip = IP}) ->
73     ?DEBUG("Incoming data: ~s", [Data]), ejabberd_http_bind:process_request(Data, IP);
74 process([], #request{method = 'GET', data = []}) ->
75     {200, ?HEADER, get_human_html_xmlel()};
76 process([], #request{method = 'OPTIONS', data = []}) -> {200, ?OPTIONS_HEADER, []};
77 process(_Path, _Request) ->
78     ?DEBUG("Bad Request: ~p", [_Request]),
79     {400, ?HEADER,
80      #xmlel{name = h1,
81 	    children = [#xmlcdata{cdata = <<"400 Bad Request">>}]}}.
82 
83 get_human_html_xmlel() ->
84     Heading = list_to_binary("ejabberd " ++ atom_to_list(?MODULE)),
85     H = #xmlel{name = h1, children = [#xmlcdata{cdata = Heading}]},
86     Par1 = #xmlel{name = p,
87 		  children =
88 		      [#xmlcdata{cdata = <<"An implementation of ">>},
89 		       #xmlel{name = a,
90 			      attrs =
91 				  [#xmlattr{name = <<"href">>,
92 					    value =
93 						<<"http://xmpp.org/extensions/xep-0206.html">>}],
94 			      children =
95 				  [#xmlcdata{cdata =
96 						 <<"XMPP over BOSH (XEP-0206)">>}]}]},
97     Par2 = #xmlel{name = p,
98 		  children =
99 		      [#xmlcdata{cdata =
100 				     <<"This web page is only informative. To use HTTP-Bind you need a Jabber/XMPP client that supports it.">>}]},
101     #xmlel{name = html,
102 	   attrs =
103 	       [#xmlattr{name = <<"xmlns">>,
104 			 value = <<"http://www.w3.org/1999/xhtml">>}],
105 	   children =
106 	       [#xmlel{name = head,
107 		       children =
108 			   [#xmlel{name = title,
109 				   children = [#xmlcdata{cdata = Heading}]}]},
110 		#xmlel{name = body, children = [H, Par1, Par2]}]}.
111 
112 %%%----------------------------------------------------------------------
113 %%% BEHAVIOUR CALLBACKS
114 %%%----------------------------------------------------------------------
115 start(Host, Opts) when is_list(Host) -> start(list_to_binary(Host), Opts);
116 start(HostB, _Opts) ->
117     setup_database(),
118     Proc = gen_mod:get_module_proc(HostB, ?PROCNAME_MHB),
119     ChildSpec = {Proc, {ejabberd_tmp_sup, start_link, [Proc, ejabberd_http_bind]},
120 		 permanent, infinity, supervisor, [ejabberd_tmp_sup]},
121     supervisor:start_child(ejabberd_sup, ChildSpec).
122 
123 stop(Host) ->
124     Proc = gen_mod:get_module_proc(Host, ?PROCNAME_MHB),
125     supervisor:terminate_child(ejabberd_sup, Proc),
126     supervisor:delete_child(ejabberd_sup, Proc).
127 
128 setup_database() ->
129     migrate_database(),
130     mnesia:create_table(http_bind,
131 			[{ram_copies, [node()]}, {local_content, true},
132 			 {attributes, record_info(fields, http_bind)}]),
133     mnesia:add_table_copy(http_bind, node(), ram_copies).
134 
135 migrate_database() ->
136     case catch mnesia:table_info(http_bind, attributes) of
137       [id, pid, to, hold, wait, process_delay, version] -> ok;
138       _ ->
139 	              %% Since the stored information is not important, instead
140 		      %% of actually migrating data, let's just destroy the table
141 	  mnesia:delete_table(http_bind)
142     end,
143     case catch mnesia:table_info(http_bind, local_content) of
144       false -> mnesia:delete_table(http_bind);
145       _ -> ok
146     end.