* src/web/ejabberd_http.erl: Authentication check moved to

ejabberd_web.erl
* src/web/ejabberd_web.erl: Likewise

* src/web/Makefile.in: Added ejabberd_http.hrl dependency

* src/web/ejabberd_http_poll.erl: Updated to use {active, once}
socket mode

* src/mod_irc/mod_irc.erl: Updated to use gen_server behaviour and
ejabberd supervision tree
* src/mod_irc/mod_irc_connection.erl: Likewise

SVN Revision: 498
This commit is contained in:
Alexey Shchepin 2006-02-03 03:28:15 +00:00
parent facefdb6e4
commit dc57e75e8f
9 changed files with 291 additions and 172 deletions

View File

@ -1,3 +1,18 @@
2006-02-03 Alexey Shchepin <alexey@sevcom.net>
* src/web/ejabberd_http.erl: Authentication check moved to
ejabberd_web.erl
* src/web/ejabberd_web.erl: Likewise
* src/web/Makefile.in: Added ejabberd_http.hrl dependency
* src/web/ejabberd_http_poll.erl: Updated to use {active, once}
socket mode
* src/mod_irc/mod_irc.erl: Updated to use gen_server behaviour and
ejabberd supervision tree
* src/mod_irc/mod_irc_connection.erl: Likewise
2006-02-02 Mickael Remond <mickael.remond@process-one.net>
* src/configure.ac: --prefix option can now override the default
@ -9,6 +24,7 @@
* src/mod_pubsub/mod_pubsub.erl: Updated to use gen_server
behaviour and ejabberd supervision tree
* src/mod_echo.erl: Likewise
2006-02-01 Alexey Shchepin <alexey@sevcom.net>

View File

@ -10,12 +10,20 @@
-author('alexey@sevcom.net').
-vsn('$Revision$ ').
-behaviour(gen_server).
-behaviour(gen_mod).
-export([start/2, init/2, stop/1,
%% API
-export([start_link/2,
start/2,
stop/1,
closed_connection/3,
get_user_and_encoding/3]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-include("ejabberd.hrl").
-include("jlib.hrl").
@ -24,9 +32,51 @@
-record(irc_connection, {jid_server_host, pid}).
-record(irc_custom, {us_host, data}).
-record(state, {host, server_host, access}).
-define(PROCNAME, ejabberd_mod_irc).
%%====================================================================
%% API
%%====================================================================
%%--------------------------------------------------------------------
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
%% Description: Starts the server
%%--------------------------------------------------------------------
start_link(Host, Opts) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []).
start(Host, Opts) ->
start_supervisor(Host),
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
ChildSpec =
{Proc,
{?MODULE, start_link, [Host, Opts]},
temporary,
1000,
worker,
[?MODULE]},
supervisor:start_child(ejabberd_sup, ChildSpec).
stop(Host) ->
stop_supervisor(Host),
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
gen_server:call(Proc, stop),
supervisor:delete_child(ejabberd_sup, Proc).
%%====================================================================
%% gen_server callbacks
%%====================================================================
%%--------------------------------------------------------------------
%% Function: init(Args) -> {ok, State} |
%% {ok, State, Timeout} |
%% ignore |
%% {stop, Reason}
%% Description: Initiates the server
%%--------------------------------------------------------------------
init([Host, Opts]) ->
iconv:start(),
mnesia:create_table(irc_custom,
[{disc_copies, [node()]},
@ -34,38 +84,97 @@ start(Host, Opts) ->
MyHost = gen_mod:get_opt(host, Opts, "irc." ++ Host),
update_table(MyHost),
Access = gen_mod:get_opt(access, Opts, all),
register(gen_mod:get_module_proc(Host, ?PROCNAME),
spawn(?MODULE, init, [MyHost, Access])).
init(Host, Access) ->
catch ets:new(irc_connection, [named_table,
public,
{keypos, #irc_connection.jid_server_host}]),
ejabberd_router:register_route(Host),
loop(Host, Access).
ejabberd_router:register_route(MyHost),
{ok, #state{host = MyHost,
server_host = Host,
access = Access}}.
loop(Host, Access) ->
receive
{route, From, To, Packet} ->
case catch do_route(Host, Access, From, To, Packet) of
{'EXIT', Reason} ->
?ERROR_MSG("~p", [Reason]);
_ ->
ok
end,
loop(Host, Access);
stop ->
ejabberd_router:unregister_route(Host),
ok;
%%--------------------------------------------------------------------
%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
%% {reply, Reply, State, Timeout} |
%% {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, Reply, State} |
%% {stop, Reason, State}
%% Description: Handling call messages
%%--------------------------------------------------------------------
handle_call(stop, _From, State) ->
{stop, normal, ok, State}.
%%--------------------------------------------------------------------
%% Function: handle_cast(Msg, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% Description: Handling cast messages
%%--------------------------------------------------------------------
handle_cast(_Msg, State) ->
{noreply, State}.
%%--------------------------------------------------------------------
%% Function: handle_info(Info, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% Description: Handling all non call/cast messages
%%--------------------------------------------------------------------
handle_info({route, From, To, Packet},
#state{host = Host,
server_host = ServerHost,
access = Access} = State) ->
case catch do_route(Host, ServerHost, Access, From, To, Packet) of
{'EXIT', Reason} ->
?ERROR_MSG("~p", [Reason]);
_ ->
loop(Host, Access)
end.
ok
end,
{noreply, State};
handle_info(_Info, State) ->
{noreply, State}.
%%--------------------------------------------------------------------
%% Function: terminate(Reason, State) -> void()
%% Description: This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any necessary
%% cleaning up. When it returns, the gen_server terminates with Reason.
%% The return value is ignored.
%%--------------------------------------------------------------------
terminate(_Reason, State) ->
ejabberd_router:unregister_route(State#state.host),
ok.
do_route(Host, Access, From, To, Packet) ->
%%--------------------------------------------------------------------
%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
%% Description: Convert process state when code is changed
%%--------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
start_supervisor(Host) ->
Proc = gen_mod:get_module_proc(Host, ejabberd_mod_irc_sup),
ChildSpec =
{Proc,
{ejabberd_tmp_sup, start_link,
[Proc, mod_irc_connection]},
permanent,
infinity,
supervisor,
[ejabberd_tmp_sup]},
supervisor:start_child(ejabberd_sup, ChildSpec).
stop_supervisor(Host) ->
Proc = gen_mod:get_module_proc(Host, ejabberd_mod_irc_sup),
supervisor:terminate_child(ejabberd_sup, Proc),
supervisor:delete_child(ejabberd_sup, Proc).
do_route(Host, ServerHost, Access, From, To, Packet) ->
case acl:match_rule(Host, Access, From) of
allow ->
do_route1(Host, From, To, Packet);
do_route1(Host, ServerHost, From, To, Packet);
_ ->
{xmlelement, _Name, Attrs, _Els} = Packet,
Lang = xml:get_attr_s("xml:lang", Attrs),
@ -75,7 +184,7 @@ do_route(Host, Access, From, To, Packet) ->
ejabberd_router:route(To, From, Err)
end.
do_route1(Host, From, To, Packet) ->
do_route1(Host, ServerHost, From, To, Packet) ->
#jid{user = ChanServ, resource = Resource} = To,
{xmlelement, _Name, Attrs, _Els} = Packet,
case ChanServ of
@ -132,7 +241,7 @@ do_route1(Host, From, To, Packet) ->
{Username, Encoding} = get_user_and_encoding(
Host, From, Server),
{ok, Pid} = mod_irc_connection:start(
From, Host, Server,
From, Host, ServerHost, Server,
Username, Encoding),
ets:insert(
irc_connection,
@ -174,12 +283,6 @@ do_route1(Host, From, To, Packet) ->
end.
stop(Host) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
Proc ! stop,
{wait, Proc}.
closed_connection(Host, From, Server) ->
ets:delete(irc_connection, {From, Server, Host}).

View File

@ -13,7 +13,7 @@
-behaviour(gen_fsm).
%% External exports
-export([start/5, route_chan/4, route_nick/3]).
-export([start_link/5, start/6, route_chan/4, route_nick/3]).
%% gen_fsm callbacks
-export([init/1,
@ -47,8 +47,14 @@
%%%----------------------------------------------------------------------
%%% API
%%%----------------------------------------------------------------------
start(From, Host, Server, Username, Encoding) ->
gen_fsm:start(?MODULE, [From, Host, Server, Username, Encoding], ?FSMOPTS).
start(From, Host, ServerHost, Server, Username, Encoding) ->
Supervisor = gen_mod:get_module_proc(ServerHost, ejabberd_mod_irc_sup),
supervisor:start_child(
Supervisor, [From, Host, Server, Username, Encoding]).
start_link(From, Host, Server, Username, Encoding) ->
gen_fsm:start_link(?MODULE, [From, Host, Server, Username, Encoding],
?FSMOPTS).
%%%----------------------------------------------------------------------
%%% Callback functions from gen_fsm

View File

@ -97,10 +97,11 @@ start(Host, ServerHost, Access, Room, Opts) ->
start_link(Host, ServerHost, Access, Room, Creator, Nick) ->
gen_fsm:start_link(?MODULE, [Host, ServerHost, Access, Room, Creator, Nick],
?FSMOPTS).
?FSMOPTS).
start_link(Host, ServerHost, Access, Room, Opts) ->
gen_fsm:start_link(?MODULE, [Host, ServerHost, Access, Room, Opts], ?FSMOPTS).
gen_fsm:start_link(?MODULE, [Host, ServerHost, Access, Room, Opts],
?FSMOPTS).
%%%----------------------------------------------------------------------
%%% Callback functions from gen_fsm

View File

@ -19,7 +19,7 @@ OBJS = \
all: $(OBJS)
$(OUTDIR)/%.beam: %.erl
$(OUTDIR)/%.beam: %.erl ejabberd_http.hrl
@ERLC@ -W $(EFLAGS) -o $(OUTDIR) $<

View File

@ -8,7 +8,7 @@
-module(ejabberd_http).
-author('alexey@sevcom.net').
-vsn('$Revision$ ').
-vsn('$Revision$ ').
%% External exports
-export([start/2,
@ -201,60 +201,34 @@ process_request(#state{request_method = 'GET',
request_lang = Lang,
use_http_poll = UseHTTPPoll,
use_web_admin = UseWebAdmin} = State) ->
US = case Auth of
{SJID, P} ->
case jlib:string_to_jid(SJID) of
error ->
unauthorized;
#jid{user = U, server = S} ->
case ejabberd_auth:check_password(U, S, P) of
true ->
{U, S};
false ->
unauthorized
end
end;
_ ->
undefined
end,
case US of
unauthorized ->
make_xhtml_output(
State,
401,
[{"WWW-Authenticate", "basic realm=\"ejabberd\""}],
ejabberd_web:make_xhtml([{xmlelement, "h1", [],
[{xmlcdata, "401 Unauthorized"}]}]));
_ ->
case (catch url_decode_q_split(Path)) of
{'EXIT', _} ->
process_request(false);
{NPath, Query} ->
LQuery = case (catch parse_urlencoded(Query)) of
{'EXIT', _Reason} ->
[];
LQ ->
LQ
end,
LPath = string:tokens(NPath, "/"),
Request = #request{method = 'GET',
path = LPath,
q = LQuery,
us = US,
lang = Lang},
case ejabberd_web:process_get({UseHTTPPoll, UseWebAdmin},
Request) of
El when element(1, El) == xmlelement ->
make_xhtml_output(State, 200, [], El);
{Status, Headers, El} when
element(1, El) == xmlelement ->
make_xhtml_output(State, Status, Headers, El);
Text when is_list(Text) ->
make_text_output(State, 200, [], Text);
{Status, Headers, Text} when
is_list(Text) ->
make_text_output(State, Status, Headers, Text)
end
case (catch url_decode_q_split(Path)) of
{'EXIT', _} ->
process_request(false);
{NPath, Query} ->
LQuery = case (catch parse_urlencoded(Query)) of
{'EXIT', _Reason} ->
[];
LQ ->
LQ
end,
LPath = string:tokens(NPath, "/"),
Request = #request{method = 'GET',
path = LPath,
q = LQuery,
auth = Auth,
lang = Lang},
case ejabberd_web:process_get({UseHTTPPoll, UseWebAdmin},
Request) of
El when element(1, El) == xmlelement ->
make_xhtml_output(State, 200, [], El);
{Status, Headers, El} when
element(1, El) == xmlelement ->
make_xhtml_output(State, Status, Headers, El);
Text when is_list(Text) ->
make_text_output(State, 200, [], Text);
{Status, Headers, Text} when
is_list(Text) ->
make_text_output(State, Status, Headers, Text)
end
end;
@ -268,68 +242,42 @@ process_request(#state{request_method = 'POST',
use_http_poll = UseHTTPPoll,
use_web_admin = UseWebAdmin} = State)
when is_integer(Len) ->
US = case Auth of
{SJID, P} ->
case jlib:string_to_jid(SJID) of
error ->
unauthorized;
#jid{user = U, server = S} ->
case ejabberd_auth:check_password(U, S, P) of
true ->
{U, S};
false ->
unauthorized
end
end;
_ ->
undefined
end,
case US of
unauthorized ->
make_xhtml_output(
State,
401,
[{"WWW-Authenticate", "basic realm=\"ejabberd\""}],
ejabberd_web:make_xhtml([{xmlelement, "h1", [],
[{xmlcdata, "401 Unauthorized"}]}]));
case SockMod of
gen_tcp ->
inet:setopts(Socket, [{packet, 0}]);
_ ->
case SockMod of
gen_tcp ->
inet:setopts(Socket, [{packet, 0}]);
_ ->
ok
end,
Data = recv_data(State, Len),
?DEBUG("client data: ~p~n", [Data]),
case (catch url_decode_q_split(Path)) of
{'EXIT', _} ->
process_request(false);
{NPath, Query} ->
LPath = string:tokens(NPath, "/"),
LQuery = case (catch parse_urlencoded(Data)) of
{'EXIT', _Reason} ->
[];
LQ ->
LQ
end,
Request = #request{method = 'POST',
path = LPath,
q = LQuery,
us = US,
data = Data,
lang = Lang},
case ejabberd_web:process_get({UseHTTPPoll, UseWebAdmin},
Request) of
El when element(1, El) == xmlelement ->
make_xhtml_output(State, 200, [], El);
{Status, Headers, El} when
element(1, El) == xmlelement ->
make_xhtml_output(State, Status, Headers, El);
Text when is_list(Text) ->
make_text_output(State, 200, [], Text);
{Status, Headers, Text} when is_list(Text) ->
make_text_output(State, Status, Headers, Text)
end
ok
end,
Data = recv_data(State, Len),
?DEBUG("client data: ~p~n", [Data]),
case (catch url_decode_q_split(Path)) of
{'EXIT', _} ->
process_request(false);
{NPath, Query} ->
LPath = string:tokens(NPath, "/"),
LQuery = case (catch parse_urlencoded(Data)) of
{'EXIT', _Reason} ->
[];
LQ ->
LQ
end,
Request = #request{method = 'POST',
path = LPath,
q = LQuery,
auth = Auth,
data = Data,
lang = Lang},
case ejabberd_web:process_get({UseHTTPPoll, UseWebAdmin},
Request) of
El when element(1, El) == xmlelement ->
make_xhtml_output(State, 200, [], El);
{Status, Headers, El} when
element(1, El) == xmlelement ->
make_xhtml_output(State, Status, Headers, El);
Text when is_list(Text) ->
make_text_output(State, 200, [], Text);
{Status, Headers, Text} when is_list(Text) ->
make_text_output(State, Status, Headers, Text)
end
end;

View File

@ -10,6 +10,7 @@
path,
q = [],
us,
auth,
lang = "",
data = ""
}).

View File

@ -21,7 +21,8 @@
handle_info/3,
terminate/3,
send/2,
recv/3,
setopts/2,
controlling_process/2,
close/1,
process_request/1]).
@ -66,8 +67,16 @@ start_link(ID, Key) ->
send({http_poll, FsmRef}, Packet) ->
gen_fsm:sync_send_all_state_event(FsmRef, {send, Packet}).
recv({http_poll, FsmRef}, _Length, Timeout) ->
gen_fsm:sync_send_all_state_event(FsmRef, recv, Timeout).
setopts({http_poll, FsmRef}, Opts) ->
case lists:member({active, once}, Opts) of
true ->
gen_fsm:sync_send_all_state_event(FsmRef, activate);
_ ->
ok
end.
controlling_process(_Socket, _Pid) ->
ok.
close({http_poll, FsmRef}) ->
catch gen_fsm:sync_send_all_state_event(FsmRef, close).
@ -138,7 +147,8 @@ process_request(_Request) ->
init([ID, Key]) ->
?INFO_MSG("started: ~p", [{ID, Key}]),
Opts = [], % TODO
ejabberd_c2s:start({?MODULE, {http_poll, self()}}, Opts),
{ok, C2SPid} = ejabberd_c2s:start({?MODULE, {http_poll, self()}}, Opts),
ejabberd_c2s:become_controller(C2SPid),
Timer = erlang:start_timer(?HTTP_POLL_TIMEOUT, self(), []),
{ok, loop, #state{id = ID,
key = Key,
@ -188,14 +198,14 @@ handle_sync_event({send, Packet}, From, StateName, StateData) ->
Reply = ok,
{reply, Reply, StateName, StateData#state{output = Output}};
handle_sync_event(recv, From, StateName, StateData) ->
handle_sync_event(activate, From, StateName, StateData) ->
case StateData#state.input of
"" ->
{next_state, StateName, StateData#state{waiting_input = From}};
{reply, ok, StateName, StateData#state{waiting_input = From}};
Input ->
Reply = {ok, list_to_binary(Input)},
{reply, Reply, StateName, StateData#state{input = "",
waiting_input = false}}
From ! {tcp, {http_poll, self()}, list_to_binary(Input)},
{reply, ok, StateName, StateData#state{input = "",
waiting_input = false}}
end;
handle_sync_event(stop, From, StateName, StateData) ->
@ -225,8 +235,9 @@ handle_sync_event({http_put, Key, NewKey, Packet},
Reply = ok,
{reply, Reply, StateName, StateData#state{input = Input,
key = NewKey}};
Receiver ->
gen_fsm:reply(Receiver, {ok, list_to_binary(Packet)}),
{Receiver, _Tag} ->
Receiver ! {tcp, {http_poll, self()},
list_to_binary(Packet)},
cancel_timer(StateData#state.timer),
Timer = erlang:start_timer(?HTTP_POLL_TIMEOUT, self(), []),
Reply = ok,

View File

@ -8,7 +8,7 @@
-module(ejabberd_web).
-author('alexey@sevcom.net').
-vsn('$Revision$ ').
-vsn('$Revision$ ').
%% External exports
-export([make_xhtml/1,
@ -50,13 +50,29 @@ make_xhtml(Els) ->
process_get({_, true},
#request{us = US,
#request{auth = Auth,
path = ["admin", "server", SHost | RPath],
q = Query,
lang = Lang} = Request) ->
Host = jlib:nameprep(SHost),
case lists:member(Host, ?MYHOSTS) of
true ->
US = case Auth of
{SJID, P} ->
case jlib:string_to_jid(SJID) of
error ->
unauthorized;
#jid{user = U, server = S} ->
case ejabberd_auth:check_password(U, S, P) of
true ->
{U, S};
false ->
unauthorized
end
end;
_ ->
unauthorized
end,
case US of
{User, Server} ->
case acl:match_rule(
@ -65,7 +81,8 @@ process_get({_, true},
{401, [], make_xhtml([?XC("h1", "Not Allowed")])};
allow ->
ejabberd_web_admin:process_admin(
Host, Request#request{path = RPath})
Host, Request#request{path = RPath,
us = US})
end;
undefined ->
{401,
@ -78,10 +95,26 @@ process_get({_, true},
end;
process_get({_, true},
#request{us = US,
#request{auth = Auth,
path = ["admin" | RPath],
q = Query,
lang = Lang} = Request) ->
US = case Auth of
{SJID, P} ->
case jlib:string_to_jid(SJID) of
error ->
unauthorized;
#jid{user = U, server = S} ->
case ejabberd_auth:check_password(U, S, P) of
true ->
{U, S};
false ->
unauthorized
end
end;
_ ->
undefined
end,
case US of
{User, Server} ->
case acl:match_rule(
@ -90,7 +123,8 @@ process_get({_, true},
{401, [], make_xhtml([?XC("h1", "Not Allowed")])};
allow ->
ejabberd_web_admin:process_admin(
global, Request#request{path = RPath})
global, Request#request{path = RPath,
us = US})
end;
undefined ->
{401,
@ -100,8 +134,7 @@ process_get({_, true},
end;
process_get({true, _},
#request{us = _US,
path = ["http-poll" | RPath],
#request{path = ["http-poll" | RPath],
q = _Query,
lang = _Lang} = Request) ->
ejabberd_http_poll:process_request(Request#request{path = RPath});