diff --git a/include/ejabberd_http.hrl b/include/ejabberd_http.hrl index 73f5aa960..fd956f08e 100644 --- a/include/ejabberd_http.hrl +++ b/include/ejabberd_http.hrl @@ -31,5 +31,6 @@ host = <<"">> :: binary(), port = 5280 :: inet:port_number(), tp = http, % :: protocol(), + opts = [] :: list(), headers = [] :: [{atom() | binary(), binary()}]}). diff --git a/rebar.config.script b/rebar.config.script index e1186a037..4e2d347ff 100644 --- a/rebar.config.script +++ b/rebar.config.script @@ -56,7 +56,7 @@ Deps = [{p1_cache_tab, ".*", {git, "git://github.com/processone/cache_tab"}}, {esip, ".*", {git, "git://github.com/processone/p1_sip"}}, {p1_stun, ".*", {git, "git://github.com/processone/stun"}}, {p1_yaml, ".*", {git, "git://github.com/processone/p1_yaml"}}, - {xmlrpc, ".*", {git, "git://github.com/rds13/xmlrpc"}}, + {ehyperloglog, ".*", {git, "https://github.com/vaxelfel/eHyperLogLog.git"}}, {p1_utils, ".*", {git, "git://github.com/processone/p1_utils"}}], ConfigureCmd = fun(Pkg, Flags) -> diff --git a/src/ejabberd_http.erl b/src/ejabberd_http.erl index c5b5758ae..162d5ac73 100644 --- a/src/ejabberd_http.erl +++ b/src/ejabberd_http.erl @@ -65,6 +65,7 @@ request_tp, request_headers = [], end_of_request = false, + options = [], default_host, trail = <<>> }). @@ -133,6 +134,10 @@ init({SockMod, Socket}, Opts) -> true -> [{[<<"http-poll">>], ejabberd_http_poll}]; false -> [] end, + XMLRPC = case proplists:get_bool(xmlrpc, Opts) of + true -> [{[], ejabberd_xmlrpc}]; + false -> [] + end, DefinedHandlers = gen_mod:get_opt( request_handlers, Opts, fun(Hs) -> @@ -141,7 +146,7 @@ init({SockMod, Socket}, Opts) -> Mod} || {Path, Mod} <- Hs] end, []), RequestHandlers = DefinedHandlers ++ Captcha ++ Register ++ - Admin ++ Bind ++ Poll, + Admin ++ Bind ++ Poll ++ XMLRPC, ?DEBUG("S: ~p~n", [RequestHandlers]), DefaultHost = gen_mod:get_opt(default_host, Opts, fun(A) -> A end, undefined), @@ -150,6 +155,7 @@ init({SockMod, Socket}, Opts) -> State = #state{sockmod = SockMod1, socket = Socket1, default_host = DefaultHost, + options = Opts, request_handlers = RequestHandlers}, receive_headers(State). @@ -359,7 +365,7 @@ process(Handlers, Request) -> false -> process(HandlersLeft, Request) end. -process_request(#state{request_method = Method, +process_request(#state{request_method = Method, options = Options, request_path = {abs_path, Path}, request_auth = Auth, request_lang = Lang, request_handlers = RequestHandlers, request_host = Host, request_port = Port, @@ -389,6 +395,7 @@ process_request(#state{request_method = Method, IP = analyze_ip_xff(IPHere, XFF, Host), Request = #request{method = Method, path = LPath, + opts = Options, q = LQuery, auth = Auth, lang = Lang, @@ -413,7 +420,7 @@ process_request(#state{request_method = Method, make_text_output(State, Status, Headers, Output) end end; -process_request(#state{request_method = Method, +process_request(#state{request_method = Method, options = Options, request_path = {abs_path, Path}, request_auth = Auth, request_content_length = Len, request_lang = Lang, sockmod = SockMod, socket = Socket, request_host = Host, @@ -450,6 +457,7 @@ process_request(#state{request_method = Method, Request = #request{method = Method, path = LPath, q = LQuery, + opts = Options, auth = Auth, data = Data, lang = Lang, diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index d2dc0fb73..515cf7348 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -201,11 +201,7 @@ listen_tcp(PortIP, Module, SockOpts, Port, IPS) -> catch _:_ -> [] end, - DeliverAs = case Module of - ejabberd_xmlrpc -> list; - _ -> binary - end, - Res = gen_tcp:listen(Port, [DeliverAs, + Res = gen_tcp:listen(Port, [binary, {packet, 0}, {active, false}, {reuseaddr, true}, diff --git a/src/ejabberd_xmlrpc.erl b/src/ejabberd_xmlrpc.erl index a289196a3..c393cbe4b 100644 --- a/src/ejabberd_xmlrpc.erl +++ b/src/ejabberd_xmlrpc.erl @@ -17,11 +17,12 @@ -author('badlop@process-one.net'). --export([start/2, handler/2, socket_type/0, transform_listen_option/2]). +-export([start/2, handler/2, process/2, socket_type/0, + transform_listen_option/2]). -include("ejabberd.hrl"). -include("logger.hrl"). - +-include("ejabberd_http.hrl"). -include("mod_roster.hrl"). -include("jlib.hrl"). @@ -170,12 +171,14 @@ %% ----------------------------- start({gen_tcp = _SockMod, Socket}, Opts) -> - %MaxSessions = gen_mod:get_opt(maxsessions, Opts, - % fun(I) when is_integer(I), I>0 -> I end, - % 10), - Timeout = gen_mod:get_opt(timeout, Opts, - fun(I) when is_integer(I), I>0 -> I end, - 5000), + ejabberd_http:start({gen_tcp, Socket}, [{xmlrpc, true}|Opts]). + +socket_type() -> raw. + +%% ----------------------------- +%% HTTP interface +%% ----------------------------- +process(_, #request{method = 'POST', data = Data, opts = Opts}) -> AccessCommandsOpts = gen_mod:get_opt(access_commands, Opts, fun(L) when is_list(L) -> L end, []), @@ -201,19 +204,28 @@ start({gen_tcp = _SockMod, Socket}, Opts) -> [?MODULE, Wrong]), [] end, AccessCommandsOpts), - GetAuth = case [ACom - || {Ac, _, _} = ACom <- AccessCommands, Ac /= all] - of - [] -> false; - _ -> true + GetAuth = case [ACom || {Ac, _, _} = ACom <- AccessCommands, Ac /= all] of + [] -> false; + _ -> true end, - Handler = {?MODULE, handler}, - State = #state{access_commands = AccessCommands, - get_auth = GetAuth}, - Pid = proc_lib:spawn(xmlrpc_http, handler, [Socket, Timeout, Handler, State]), - {ok, Pid}. - -socket_type() -> raw. + State = #state{access_commands = AccessCommands, get_auth = GetAuth}, + case xmlrpc_decode:payload(Data) of + {error, _} = Err -> + ?ERROR_MSG("XML-RPC request ~s failed with reason: ~p", + [Data, Err]), + {400, [], + #xmlel{name = <<"h1">>, attrs = [], + children = [{xmlcdata, <<"Malformed Request">>}]}}; + {ok, RPC} -> + ?DEBUG("got XML-RPC request: ~p", [RPC]), + {false, Result} = handler(State, RPC), + {ok, XML} = xmlrpc_encode:payload(Result), + {200, [], [{<<"Content-Type">>, <<"text/xml">>}], XML} + end; +process(_, _) -> + {400, [], + #xmlel{name = <<"h1">>, attrs = [], + children = [{xmlcdata, <<"400 Bad Request">>}]}}. %% ----------------------------- %% Access verification