diff options
Diffstat (limited to 'lib/inets')
32 files changed, 1311 insertions, 1481 deletions
diff --git a/lib/inets/doc/src/Makefile b/lib/inets/doc/src/Makefile index 1a8e1c7ca8..961bfa838d 100644 --- a/lib/inets/doc/src/Makefile +++ b/lib/inets/doc/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2012. All Rights Reserved. +# Copyright Ericsson AB 1997-2015. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -52,6 +52,7 @@ XML_REF3_FILES = \ httpc.xml\ httpd.xml \ httpd_conf.xml \ + httpd_custom_api.xml \ httpd_socket.xml \ httpd_util.xml \ mod_alias.xml \ diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml index 4178cb7d4c..6984408932 100644 --- a/lib/inets/doc/src/httpc.xml +++ b/lib/inets/doc/src/httpc.xml @@ -366,7 +366,7 @@ filename() = string() <tag><c><![CDATA[receiver]]></c></tag> <item> <p>Defines how the client will deliver the result of an - asynchroneous request (<c>sync</c> has the value + asynchronous request (<c>sync</c> has the value <c>false</c>). </p> <taglist> diff --git a/lib/inets/doc/src/httpd.xml b/lib/inets/doc/src/httpd.xml index e40660ab39..e6aa8d5e07 100644 --- a/lib/inets/doc/src/httpd.xml +++ b/lib/inets/doc/src/httpd.xml @@ -162,6 +162,20 @@ in the apache like configuration file. </p> </item> + <marker id="profile"></marker> + <tag>{profile, atom()}</tag> + <item> + <p>Used together with <seealso marker="prop_bind_address"><c>bind_address</c></seealso> + and <seealso marker="prop_port"><c>port</c></seealso> to uniquely identify + a HTTP server. This can be useful in a virtualized environment, + where there can + be more that one server that has the same bind_address and port. + If this property is not explicitly set, it is assumed that the + <seealso marker="prop_bind_address"><c>bind_address</c></seealso> and + <seealso marker="prop_port"><c>port</c></seealso>uniquely identifies the HTTP server. + </p> + </item> + <marker id="prop_socket_type"></marker> <tag>{socket_type, ip_comm | {essl, Config::proplist()}}</tag> <item> @@ -176,6 +190,8 @@ <p>Note that this option is only used when the option <c>socket_type</c> has the value <c>ip_comm</c>. </p> </item> + + <marker id="prop_minimum_bytes_per_second"></marker> <tag>{minimum_bytes_per_second, integer()}</tag> <item> @@ -204,7 +220,15 @@ <marker id="props_limit"></marker> <p><em>Limit properties</em> </p> - <taglist> + <taglist> + + <marker id="prop_customize"></marker> + <tag>{customize, atom()}</tag> + <item> + <p>A callback module to customize the inets HTTP servers behaviour + see <seealso marker="http_custom_api"> httpd_custom_api</seealso> </p> + </item> + <marker id="prop_disable_chunked_encoding"></marker> <tag>{disable_chunked_transfer_encoding_send, boolean()}</tag> <item> @@ -927,19 +951,22 @@ bytes <func> <marker id="info2"></marker> <name>info(Address, Port) -> </name> + <name>info(Address, Port, Profile) -> </name> + <name>info(Address, Port, Profile, Properties) -> [{Option, Value}] </name> <name>info(Address, Port, Properties) -> [{Option, Value}] </name> <fsummary>Fetches information about the HTTP server</fsummary> <type> <v>Address = ip_address()</v> <v>Port = integer()</v> + <v>Profile = atom()</v> <v>Properties = [property()]</v> <v>Option = property()</v> <v>Value = term()</v> </type> <desc> <p>Fetches information about the HTTP server. When called with - only the Address and Port all properties are fetched, when - called with a list of specific properties they are fetched. + only the Address, Port and Profile, if relevant, all properties are fetched. + When called with a list of specific properties they are fetched. Available properties are the same as the server's start options. </p> diff --git a/lib/inets/doc/src/httpd_custom_api.xml b/lib/inets/doc/src/httpd_custom_api.xml new file mode 100644 index 0000000000..faf1d277df --- /dev/null +++ b/lib/inets/doc/src/httpd_custom_api.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2015</year><year>2015</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>httpd_custom_api</title> + <file>httpd_custom_api.xml</file> + </header> + <module>httpd_custom_api</module> + <modulesummary>Behaviour with optional callbacks to customize the inets HTTP server.</modulesummary> + <description> + <p> The module implementing this behaviour shall be supplied to to the servers + configuration with the option <seealso marker="httpd:prop_customize"> customize</seealso></p> + + </description> + <funcs> + <func> + <name>response_header({HeaderName, HeaderValue}) -> {true, Header} | false </name> + <fsummary>Filter and possible alter HTTP response headers.</fsummary> + <type> + <v>Header = {HeaderName :: string(), HeaderValue::string()}</v> + <d>The header name will be in lower case and should not be altered.</d> + </type> + <desc> + <p> Filter and possible alter HTTP response headers before they are sent to the client. + </p> + </desc> + </func> + + <func> + <name>request_header({HeaderName, HeaderValue}) -> {true, Header} | false </name> + <fsummary>Filter and possible alter HTTP request headers.</fsummary> + <type> + <v>Header = {HeaderName :: string(), HeaderValue::string()}</v> + <d>The header name will be in lower case and should not be altered.</d> + </type> + <desc> + <p> Filter and possible alter HTTP request headers before they are processed by the server. + </p> + </desc> + </func> + </funcs> +</erlref> + + diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml index bae8e327a3..f563a8c4b0 100644 --- a/lib/inets/doc/src/notes.xml +++ b/lib/inets/doc/src/notes.xml @@ -32,7 +32,23 @@ <file>notes.xml</file> </header> - <section><title>Inets 5.10.8</title> + <section><title>Inets 5.10.9</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Add behaviour with optional callbacks to customize the + inets HTTP server.</p> + <p> + Own Id: OTP-12776</p> + </item> + </list> + </section> + +</section> + +<section><title>Inets 5.10.8</title> <section><title>Fixed Bugs and Malfunctions</title> <list> diff --git a/lib/inets/doc/src/ref_man.xml b/lib/inets/doc/src/ref_man.xml index aaedf330b4..3afb020431 100644 --- a/lib/inets/doc/src/ref_man.xml +++ b/lib/inets/doc/src/ref_man.xml @@ -4,7 +4,7 @@ <application xmlns:xi="http://www.w3.org/2001/XInclude"> <header> <copyright> - <year>1997</year><year>2013</year> + <year>1997</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -39,6 +39,7 @@ <xi:include href="httpc.xml"/> <xi:include href="httpd.xml"/> <xi:include href="httpd_conf.xml"/> + <xi:include href="httpd_custom_api.xml"/> <xi:include href="httpd_socket.xml"/> <xi:include href="httpd_util.xml"/> <xi:include href="mod_alias.xml"/> diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl index f4f0c37570..9d832ef18b 100644 --- a/lib/inets/src/http_client/httpc_handler.erl +++ b/lib/inets/src/http_client/httpc_handler.erl @@ -1330,7 +1330,7 @@ handle_keep_alive_queue(#state{status = keep_alive, Session, <<>>, State#state{keep_alive = KeepAlive}); {error, Reason} -> - {stop, shutdown, {keepalive_failed, Reason}, State} + {stop, {shutdown, {keepalive_failed, Reason}}, State} end end end. diff --git a/lib/inets/src/http_server/Makefile b/lib/inets/src/http_server/Makefile index 51e3dd9212..00bad51ff9 100644 --- a/lib/inets/src/http_server/Makefile +++ b/lib/inets/src/http_server/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2005-2013. All Rights Reserved. +# Copyright Ericsson AB 2005-2015. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -46,6 +46,7 @@ MODULES = \ httpd_connection_sup\ httpd_cgi \ httpd_conf \ + httpd_custom \ httpd_example \ httpd_esi \ httpd_file\ diff --git a/lib/inets/src/http_server/httpd.erl b/lib/inets/src/http_server/httpd.erl index e8148ea362..71be6dde00 100644 --- a/lib/inets/src/http_server/httpd.erl +++ b/lib/inets/src/http_server/httpd.erl @@ -23,6 +23,7 @@ -behaviour(inets_service). -include("httpd.hrl"). +-include("httpd_internal.hrl"). %% Behavior callbacks -export([ @@ -61,18 +62,27 @@ info(Pid, Properties) when is_pid(Pid) andalso is_list(Properties) -> {ok, ServiceInfo} = service_info(Pid), Address = proplists:get_value(bind_address, ServiceInfo), Port = proplists:get_value(port, ServiceInfo), + Profile = proplists:get_value(profile, ServiceInfo, default), case Properties of [] -> - info(Address, Port); + info(Address, Port, Profile); _ -> - info(Address, Port, Properties) + info(Address, Port, Profile, Properties) end; + info(Address, Port) when is_integer(Port) -> - httpd_conf:get_config(Address, Port). + info(Address, Port, default). + +info(Address, Port, Profile) when is_integer(Port), is_atom(Profile) -> + httpd_conf:get_config(Address, Port, Profile); info(Address, Port, Properties) when is_integer(Port) andalso is_list(Properties) -> - httpd_conf:get_config(Address, Port, Properties). + httpd_conf:get_config(Address, Port, default, Properties). + +info(Address, Port, Profile, Properties) when is_integer(Port) andalso + is_atom(Profile) andalso is_list(Properties) -> + httpd_conf:get_config(Address, Port, Profile, Properties). %%%======================================================================== @@ -86,14 +96,16 @@ start_service(Conf) -> httpd_sup:start_child(Conf). stop_service({Address, Port}) -> - httpd_sup:stop_child(Address, Port); - + stop_service({Address, Port, ?DEFAULT_PROFILE}); +stop_service({Address, Port, Profile}) -> + httpd_sup:stop_child(Address, Port, Profile); stop_service(Pid) when is_pid(Pid) -> case service_info(Pid) of {ok, Info} -> Address = proplists:get_value(bind_address, Info), Port = proplists:get_value(port, Info), - stop_service({Address, Port}); + Profile = proplists:get_value(profile, Info, ?DEFAULT_PROFILE), + stop_service({Address, Port, Profile}); Error -> Error end. @@ -101,7 +113,6 @@ stop_service(Pid) when is_pid(Pid) -> services() -> [{httpd, ChildPid} || {_, ChildPid, _, _} <- supervisor:which_children(httpd_sup)]. - service_info(Pid) -> try [{ChildName, ChildPid} || @@ -114,7 +125,6 @@ service_info(Pid) -> {error, service_not_available} end. - %%%-------------------------------------------------------------- %%% Internal functions %%%-------------------------------------------------------------------- @@ -128,12 +138,12 @@ child_name(Pid, [_ | Children]) -> child_name2info(undefined) -> {error, no_such_service}; -child_name2info({httpd_instance_sup, any, Port}) -> +child_name2info({httpd_instance_sup, any, Port, Profile}) -> {ok, Host} = inet:gethostname(), - Info = info(any, Port, [server_name]), + Info = info(any, Port, Profile, [server_name]), {ok, [{bind_address, any}, {host, Host}, {port, Port} | Info]}; -child_name2info({httpd_instance_sup, Address, Port}) -> - Info = info(Address, Port, [server_name]), +child_name2info({httpd_instance_sup, Address, Port, Profile}) -> + Info = info(Address, Port, Profile, [server_name]), case inet:gethostbyaddr(Address) of {ok, {_, Host, _, _,_, _}} -> {ok, [{bind_address, Address}, @@ -143,8 +153,8 @@ child_name2info({httpd_instance_sup, Address, Port}) -> end. -reload(Config, Address, Port) -> - Name = make_name(Address,Port), +reload(Config, Address, Port, Profile) -> + Name = make_name(Address,Port, Profile), case whereis(Name) of Pid when is_pid(Pid) -> httpd_manager:reload(Pid, Config); @@ -191,51 +201,19 @@ reload(Config, Address, Port) -> %%% Timeout -> integer() %%% -block(Addr, Port, disturbing) when is_integer(Port) -> - do_block(Addr, Port, disturbing); -block(Addr, Port, non_disturbing) when is_integer(Port) -> - do_block(Addr, Port, non_disturbing); - -block(ConfigFile, Mode, Timeout) - when is_list(ConfigFile) andalso - is_atom(Mode) andalso - is_integer(Timeout) -> - case get_addr_and_port(ConfigFile) of - {ok, Addr, Port} -> - block(Addr, Port, Mode, Timeout); - Error -> - Error - end. - - -block(Addr, Port, non_disturbing, Timeout) - when is_integer(Port) andalso is_integer(Timeout) -> - do_block(Addr, Port, non_disturbing, Timeout); -block(Addr,Port,disturbing,Timeout) - when is_integer(Port) andalso is_integer(Timeout) -> - do_block(Addr, Port, disturbing, Timeout). - -do_block(Addr, Port, Mode) when is_integer(Port) andalso is_atom(Mode) -> - Name = make_name(Addr,Port), +block(Addr, Port, Profile, disturbing) when is_integer(Port) -> + do_block(Addr, Port, Profile, disturbing); +block(Addr, Port, Profile, non_disturbing) when is_integer(Port) -> + do_block(Addr, Port, Profile, non_disturbing). +do_block(Addr, Port, Profile, Mode) when is_integer(Port) andalso is_atom(Mode) -> + Name = make_name(Addr, Port, Profile), case whereis(Name) of Pid when is_pid(Pid) -> - httpd_manager:block(Pid,Mode); + httpd_manager:block(Pid, Mode); _ -> {error,not_started} end. - -do_block(Addr, Port, Mode, Timeout) - when is_integer(Port) andalso is_atom(Mode) -> - Name = make_name(Addr,Port), - case whereis(Name) of - Pid when is_pid(Pid) -> - httpd_manager:block(Pid,Mode,Timeout); - _ -> - {error,not_started} - end. - - %%% ========================================================= %%% Function: unblock/2 %%% unblock(Addr, Port) @@ -248,8 +226,8 @@ do_block(Addr, Port, Mode, Timeout) %%% ConfigFile -> string() %%% -unblock(Addr, Port) when is_integer(Port) -> - Name = make_name(Addr,Port), +unblock(Addr, Port, Profile) when is_integer(Port) -> + Name = make_name(Addr,Port, Profile), case whereis(Name) of Pid when is_pid(Pid) -> httpd_manager:unblock(Pid); @@ -269,24 +247,9 @@ foreach([KeyValue|Rest]) -> foreach(Rest) end. -get_addr_and_port(ConfigFile) -> - case httpd_conf:load(ConfigFile) of - {ok, ConfigList} -> - case (catch httpd_conf:validate_properties(ConfigList)) of - {ok, Config} -> - Address = proplists:get_value(bind_address, Config, any), - Port = proplists:get_value(port, Config, 80), - {ok, Address, Port}; - Error -> - Error - end; - Error -> - Error - end. - -make_name(Addr, Port) -> - httpd_util:make_name("httpd", Addr, Port). +make_name(Addr, Port, Profile) -> + httpd_util:make_name("httpd", Addr, Port, Profile). do_reload_config(ConfigList, Mode) -> @@ -294,10 +257,11 @@ do_reload_config(ConfigList, Mode) -> {ok, Config} -> Address = proplists:get_value(bind_address, Config, any), Port = proplists:get_value(port, Config, 80), - case block(Address, Port, Mode) of + Profile = proplists:get_value(profile, Config, default), + case block(Address, Port, Profile, Mode) of ok -> - reload(Config, Address, Port), - unblock(Address, Port); + reload(Config, Address, Port, Profile), + unblock(Address, Port, Profile); Error -> Error end; diff --git a/lib/inets/src/http_server/httpd_acceptor_sup.erl b/lib/inets/src/http_server/httpd_acceptor_sup.erl index cc2b582b52..a6a0fe2eea 100644 --- a/lib/inets/src/http_server/httpd_acceptor_sup.erl +++ b/lib/inets/src/http_server/httpd_acceptor_sup.erl @@ -26,6 +26,8 @@ -behaviour(supervisor). +-include("httpd_internal.hrl"). + %% API -export([start_link/1]). %%, start_acceptor/6, start_acceptor/7, stop_acceptor/2]). @@ -36,8 +38,9 @@ %%%========================================================================= %%% API %%%========================================================================= -start_link([Addr, Port| _] = Args) -> - SupName = make_name(Addr, Port), +start_link([Addr, Port, Config| _] = Args) -> + Profile = proplists:get_value(profile, Config, ?DEFAULT_PROFILE), + SupName = make_name(Addr, Port, Profile), supervisor:start_link({local, SupName}, ?MODULE, [Args]). %%%========================================================================= @@ -54,20 +57,23 @@ init([Args]) -> %%% Internal functions %%%========================================================================= child_spec([Address, Port, ConfigList, AcceptTimeout, ListenInfo]) -> - Name = id(Address, Port), - Manager = httpd_util:make_name("httpd", Address, Port), + Profile = proplists:get_value(profile, ConfigList, ?DEFAULT_PROFILE), + Name = id(Address, Port, Profile), + Manager = httpd_util:make_name("httpd", Address, Port, Profile), SockType = proplists:get_value(socket_type, ConfigList, ip_comm), IpFamily = proplists:get_value(ipfamily, ConfigList, inet), StartFunc = case ListenInfo of undefined -> - {httpd_acceptor, start_link, [Manager, SockType, Address, Port, IpFamily, - httpd_util:make_name("httpd_conf", Address, Port), - AcceptTimeout]}; + {httpd_acceptor, start_link, + [Manager, SockType, Address, Port, IpFamily, + httpd_util:make_name("httpd_conf", Address, Port, Profile), + AcceptTimeout]}; _ -> - {httpd_acceptor, start_link, [Manager, SockType, Address, Port, ListenInfo, - IpFamily, - httpd_util:make_name("httpd_conf", Address, Port), - AcceptTimeout]} + {httpd_acceptor, start_link, + [Manager, SockType, Address, Port, ListenInfo, + IpFamily, + httpd_util:make_name("httpd_conf", Address, Port, Profile), + AcceptTimeout]} end, Restart = transient, Shutdown = brutal_kill, @@ -75,9 +81,9 @@ child_spec([Address, Port, ConfigList, AcceptTimeout, ListenInfo]) -> Type = worker, {Name, StartFunc, Restart, Shutdown, Type, Modules}. -id(Address, Port) -> - {httpd_acceptor_sup, Address, Port}. +id(Address, Port, Profile) -> + {httpd_acceptor_sup, Address, Port, Profile}. -make_name(Addr,Port) -> - httpd_util:make_name("httpd_acceptor_sup", Addr, Port). +make_name(Addr, Port, Profile) -> + httpd_util:make_name("httpd_acceptor_sup", Addr, Port, Profile). diff --git a/lib/inets/src/http_server/httpd_conf.erl b/lib/inets/src/http_server/httpd_conf.erl index a21eb915d4..9c70f8d1b8 100644 --- a/lib/inets/src/http_server/httpd_conf.erl +++ b/lib/inets/src/http_server/httpd_conf.erl @@ -25,7 +25,7 @@ %% Application internal API -export([load/1, load/2, load_mime_types/1, store/1, store/2, - remove/1, remove_all/1, get_config/2, get_config/3, + remove/1, remove_all/1, get_config/3, get_config/4, lookup_socket_type/1, lookup/2, lookup/3, lookup/4, validate_properties/1]). @@ -757,8 +757,9 @@ store(ConfigList0) -> ?hdrt("store", [{modules, Modules}]), Port = proplists:get_value(port, ConfigList0), Addr = proplists:get_value(bind_address, ConfigList0, any), + Profile = proplists:get_value(profile, ConfigList0, default), ConfigList = fix_mime_types(ConfigList0), - Name = httpd_util:make_name("httpd_conf", Addr, Port), + Name = httpd_util:make_name("httpd_conf", Addr, Port, Profile), ConfigDB = ets:new(Name, [named_table, bag, protected]), store(ConfigDB, ConfigList, lists:append(Modules, [?MODULE]), @@ -909,15 +910,15 @@ remove(ConfigDB) -> %% end. -get_config(Address, Port) -> - Tab = httpd_util:make_name("httpd_conf", Address, Port), +get_config(Address, Port, Profile) -> + Tab = httpd_util:make_name("httpd_conf", Address, Port, Profile), Properties = ets:tab2list(Tab), MimeTab = proplists:get_value(mime_types, Properties), NewProperties = proplists:delete(mime_types, Properties), [{mime_types, ets:tab2list(MimeTab)} | NewProperties]. -get_config(Address, Port, Properties) -> - Tab = httpd_util:make_name("httpd_conf", Address, Port), +get_config(Address, Port, Profile, Properties) -> + Tab = httpd_util:make_name("httpd_conf", Address, Port, Profile), Config = lists:map(fun(Prop) -> {Prop, httpd_util:lookup(Tab, Prop)} end, Properties), diff --git a/lib/inets/src/http_server/httpd_custom.erl b/lib/inets/src/http_server/httpd_custom.erl new file mode 100644 index 0000000000..342469a579 --- /dev/null +++ b/lib/inets/src/http_server/httpd_custom.erl @@ -0,0 +1,69 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2015-2015. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(httpd_custom). + +-export([response_header/1, request_header/1]). +-export([customize_headers/3]). + +-include_lib("inets/src/inets_app/inets_internal.hrl"). + +response_header(Header) -> + {true, httpify(Header)}. +request_header(Header) -> + {true, Header}. + +customize_headers(?MODULE, Function, Arg) -> + ?MODULE:Function(Arg); +customize_headers(Module, Function, Arg) -> + try Module:Function(Arg) of + {true, Value} -> + ?MODULE:Function(Value); + false -> + false + catch + _:_ -> + ?MODULE:Function(Arg) + end. + +httpify({Key0, Value}) -> + %% make sure first letter is capital (defacto standard) + Words1 = string:tokens(Key0, "-"), + Words2 = upify(Words1, []), + Key = new_key(Words2), + Key ++ ": " ++ Value ++ ?CRLF . + +new_key([]) -> + ""; +new_key([W]) -> + W; +new_key([W1,W2]) -> + W1 ++ "-" ++ W2; +new_key([W|R]) -> + W ++ "-" ++ new_key(R). + +upify([], Acc) -> + lists:reverse(Acc); +upify([Key|Rest], Acc) -> + upify(Rest, [upify2(Key)|Acc]). + +upify2([C|Rest]) when (C >= $a) andalso (C =< $z) -> + [C-($a-$A)|Rest]; +upify2(Str) -> + Str. diff --git a/lib/inets/src/http_server/httpd_instance_sup.erl b/lib/inets/src/http_server/httpd_instance_sup.erl index b95be44b2a..90800f2724 100644 --- a/lib/inets/src/http_server/httpd_instance_sup.erl +++ b/lib/inets/src/http_server/httpd_instance_sup.erl @@ -27,6 +27,8 @@ -behaviour(supervisor). +-include("httpd_internal.hrl"). + %% Internal application API -export([start_link/3, start_link/4]). @@ -41,7 +43,8 @@ start_link([{_, _}| _] = Config, AcceptTimeout, Debug) -> {ok, Config2} -> Address = proplists:get_value(bind_address, Config2), Port = proplists:get_value(port, Config2), - Name = make_name(Address, Port), + Profile = proplists:get_value(profile, Config2, ?DEFAULT_PROFILE), + Name = make_name(Address, Port, Profile), SupName = {local, Name}, supervisor:start_link(SupName, ?MODULE, [undefined, Config2, AcceptTimeout, @@ -54,7 +57,8 @@ start_link([{_, _}| _] = Config, AcceptTimeout, Debug) -> start_link(ConfigFile, AcceptTimeout, Debug) -> case file_2_config(ConfigFile) of {ok, ConfigList, Address, Port} -> - Name = make_name(Address, Port), + Profile = proplists:get_value(profile, ConfigList, ?DEFAULT_PROFILE), + Name = make_name(Address, Port, Profile), SupName = {local, Name}, supervisor:start_link(SupName, ?MODULE, [ConfigFile, ConfigList, AcceptTimeout, @@ -70,7 +74,8 @@ start_link([{_, _}| _] = Config, AcceptTimeout, ListenInfo, Debug) -> {ok, Config2} -> Address = proplists:get_value(bind_address, Config2), Port = proplists:get_value(port, Config2), - Name = make_name(Address, Port), + Profile = proplists:get_value(profile, Config2, ?DEFAULT_PROFILE), + Name = make_name(Address, Port, Profile), SupName = {local, Name}, supervisor:start_link(SupName, ?MODULE, [undefined, Config2, AcceptTimeout, @@ -83,7 +88,8 @@ start_link([{_, _}| _] = Config, AcceptTimeout, ListenInfo, Debug) -> start_link(ConfigFile, AcceptTimeout, ListenInfo, Debug) -> case file_2_config(ConfigFile) of {ok, ConfigList, Address, Port} -> - Name = make_name(Address, Port), + Profile = proplists:get_value(profile, ConfigList, ?DEFAULT_PROFILE), + Name = make_name(Address, Port, Profile), SupName = {local, Name}, supervisor:start_link(SupName, ?MODULE, [ConfigFile, ConfigList, AcceptTimeout, @@ -99,22 +105,24 @@ start_link(ConfigFile, AcceptTimeout, ListenInfo, Debug) -> %%%========================================================================= init([ConfigFile, ConfigList, AcceptTimeout, Debug, Address, Port]) -> httpd_util:enable_debug(Debug), + Profile = proplists:get_value(profile, ConfigList, ?DEFAULT_PROFILE), Flags = {one_for_one, 0, 1}, - Children = [httpd_connection_sup_spec(Address, Port), - httpd_acceptor_sup_spec(Address, Port, ConfigList, AcceptTimeout, + Children = [httpd_connection_sup_spec(Address, Port, Profile), + httpd_acceptor_sup_spec(Address, Port, Profile, ConfigList, AcceptTimeout, undefined), - sup_spec(httpd_misc_sup, Address, Port), - worker_spec(httpd_manager, Address, Port, + sup_spec(httpd_misc_sup, Address, Port, Profile), + worker_spec(httpd_manager, Address, Port, Profile, ConfigFile, ConfigList,AcceptTimeout)], {ok, {Flags, Children}}; init([ConfigFile, ConfigList, AcceptTimeout, Debug, Address, Port, ListenInfo]) -> httpd_util:enable_debug(Debug), + Profile = proplists:get_value(profile, ConfigList, ?DEFAULT_PROFILE), Flags = {one_for_one, 0, 1}, - Children = [httpd_connection_sup_spec(Address, Port), - httpd_acceptor_sup_spec(Address, Port, ConfigList, AcceptTimeout, - ListenInfo), - sup_spec(httpd_misc_sup, Address, Port), - worker_spec(httpd_manager, Address, Port, ListenInfo, + Children = [httpd_connection_sup_spec(Address, Port, Profile), + httpd_acceptor_sup_spec(Address, Port, Profile, ConfigList, AcceptTimeout, + ListenInfo), + sup_spec(httpd_misc_sup, Address, Port, Profile), + worker_spec(httpd_manager, Address, Port, Profile, ListenInfo, ConfigFile, ConfigList, AcceptTimeout)], {ok, {Flags, Children}}. @@ -122,8 +130,8 @@ init([ConfigFile, ConfigList, AcceptTimeout, Debug, Address, Port, ListenInfo]) %%%========================================================================= %%% Internal functions %%%========================================================================= -httpd_connection_sup_spec(Address, Port) -> - Name = {httpd_connection_sup, Address, Port}, +httpd_connection_sup_spec(Address, Port, Profile) -> + Name = {httpd_connection_sup, Address, Port, Profile}, StartFunc = {httpd_connection_sup, start_link, [[Address, Port]]}, Restart = permanent, Shutdown = 5000, @@ -131,8 +139,8 @@ httpd_connection_sup_spec(Address, Port) -> Type = supervisor, {Name, StartFunc, Restart, Shutdown, Type, Modules}. -httpd_acceptor_sup_spec(Address, Port, ConfigList, AcceptTimeout, ListenInfo) -> - Name = {httpd_acceptor_sup, Address, Port}, +httpd_acceptor_sup_spec(Address, Port, Profile, ConfigList, AcceptTimeout, ListenInfo) -> + Name = {httpd_acceptor_sup, Address, Port, Profile}, StartFunc = {httpd_acceptor_sup, start_link, [[Address, Port, ConfigList, AcceptTimeout, ListenInfo]]}, Restart = permanent, Shutdown = infinity, @@ -140,18 +148,18 @@ httpd_acceptor_sup_spec(Address, Port, ConfigList, AcceptTimeout, ListenInfo) -> Type = supervisor, {Name, StartFunc, Restart, Shutdown, Type, Modules}. -sup_spec(SupModule, Address, Port) -> - Name = {SupModule, Address, Port}, - StartFunc = {SupModule, start_link, [Address, Port]}, +sup_spec(SupModule, Address, Port, Profile) -> + Name = {SupModule, Address, Port, Profile}, + StartFunc = {SupModule, start_link, [Address, Port, Profile]}, Restart = permanent, Shutdown = infinity, Modules = [SupModule], Type = supervisor, {Name, StartFunc, Restart, Shutdown, Type, Modules}. -worker_spec(WorkerModule, Address, Port, ConfigFile, +worker_spec(WorkerModule, Address, Port, Profile, ConfigFile, ConfigList, AcceptTimeout) -> - Name = {WorkerModule, Address, Port}, + Name = {WorkerModule, Address, Port, Profile}, StartFunc = {WorkerModule, start_link, [ConfigFile, ConfigList, AcceptTimeout]}, Restart = permanent, @@ -160,9 +168,9 @@ worker_spec(WorkerModule, Address, Port, ConfigFile, Type = worker, {Name, StartFunc, Restart, Shutdown, Type, Modules}. -worker_spec(WorkerModule, Address, Port, ListenInfo, ConfigFile, +worker_spec(WorkerModule, Address, Port, Profile, ListenInfo, ConfigFile, ConfigList, AcceptTimeout) -> - Name = {WorkerModule, Address, Port}, + Name = {WorkerModule, Address, Port, Profile}, StartFunc = {WorkerModule, start_link, [ConfigFile, ConfigList, AcceptTimeout, ListenInfo]}, Restart = permanent, @@ -171,8 +179,8 @@ worker_spec(WorkerModule, Address, Port, ListenInfo, ConfigFile, Type = worker, {Name, StartFunc, Restart, Shutdown, Type, Modules}. -make_name(Address,Port) -> - httpd_util:make_name("httpd_instance_sup", Address, Port). +make_name(Address, Port, Profile) -> + httpd_util:make_name("httpd_instance_sup", Address, Port, Profile). file_2_config(ConfigFile) -> diff --git a/lib/inets/src/http_server/httpd_internal.hrl b/lib/inets/src/http_server/httpd_internal.hrl index 108469ea0a..9829ca255c 100644 --- a/lib/inets/src/http_server/httpd_internal.hrl +++ b/lib/inets/src/http_server/httpd_internal.hrl @@ -31,6 +31,8 @@ -define(SOCKET_MAX_POLL,25). -define(FILE_CHUNK_SIZE,64*1024). -define(GATEWAY_INTERFACE,"CGI/1.1"). +-define(DEFAULT_PROFILE, default). + -define(NICE(Reason),lists:flatten(atom_to_list(?MODULE)++": "++Reason)). -define(DEFAULT_CONTEXT, [{errmsg,"[an error occurred while processing this directive]"}, diff --git a/lib/inets/src/http_server/httpd_manager.erl b/lib/inets/src/http_server/httpd_manager.erl index 3da0343401..995316d5e8 100644 --- a/lib/inets/src/http_server/httpd_manager.erl +++ b/lib/inets/src/http_server/httpd_manager.erl @@ -28,7 +28,7 @@ -export([start/2, start_link/2, start_link/3, start_link/4, stop/1, reload/2]). -export([new_connection/1]). --export([config_match/2, config_match/3]). +-export([config_match/3, config_match/4]). -export([block/2, block/3, unblock/1]). %% gen_server exports @@ -54,7 +54,8 @@ start(ConfigFile, ConfigList) -> Port = proplists:get_value(port,ConfigList,80), Addr = proplists:get_value(bind_address, ConfigList), - Name = make_name(Addr,Port), + Profile = proplists:get_value(profile, ConfigList, default), + Name = make_name(Addr, Port, Profile), gen_server:start({local,Name},?MODULE, [ConfigFile, ConfigList, 15000, Addr, Port],[]). @@ -65,7 +66,8 @@ start_link(ConfigFile, ConfigList) -> start_link(ConfigFile, ConfigList, AcceptTimeout) -> Port = proplists:get_value(port, ConfigList, 80), Addr = proplists:get_value(bind_address, ConfigList), - Name = make_name(Addr, Port), + Profile = proplists:get_value(profile, ConfigList, default), + Name = make_name(Addr, Port, Profile), gen_server:start_link({local, Name},?MODULE, [ConfigFile, ConfigList, @@ -74,7 +76,8 @@ start_link(ConfigFile, ConfigList, AcceptTimeout) -> start_link(ConfigFile, ConfigList, AcceptTimeout, ListenSocket) -> Port = proplists:get_value(port, ConfigList, 80), Addr = proplists:get_value(bind_address, ConfigList), - Name = make_name(Addr, Port), + Profile = proplists:get_value(profile, ConfigList, default), + Name = make_name(Addr, Port, Profile), gen_server:start_link({local, Name},?MODULE, [ConfigFile, ConfigList, AcceptTimeout, Addr, @@ -97,10 +100,10 @@ unblock(ServerRef) -> new_connection(Manager) -> call(Manager, {new_connection, self()}). -config_match(Port, Pattern) -> - config_match(undefined,Port,Pattern). -config_match(Addr, Port, Pattern) -> - Name = httpd_util:make_name("httpd",Addr,Port), +config_match(Port, Profile, Pattern) -> + config_match(undefined,Port, Profile, Pattern). +config_match(Addr, Port, Profile, Pattern) -> + Name = httpd_util:make_name("httpd",Addr,Port, Profile), call(whereis(Name), {config_match, Pattern}). %%%-------------------------------------------------------------------- @@ -446,8 +449,8 @@ get_ustate(ConnectionCnt,State) -> active end. -make_name(Addr,Port) -> - httpd_util:make_name("httpd",Addr,Port). +make_name(Addr, Port, Profile) -> + httpd_util:make_name("httpd", Addr, Port, Profile). report_error(State,String) -> diff --git a/lib/inets/src/http_server/httpd_misc_sup.erl b/lib/inets/src/http_server/httpd_misc_sup.erl index fd7c28bd7d..e5de66d773 100644 --- a/lib/inets/src/http_server/httpd_misc_sup.erl +++ b/lib/inets/src/http_server/httpd_misc_sup.erl @@ -27,8 +27,8 @@ -behaviour(supervisor). %% API --export([start_link/2, start_auth_server/2, stop_auth_server/2, - start_sec_server/2, stop_sec_server/2]). +-export([start_link/3, start_auth_server/3, stop_auth_server/3, + start_sec_server/3, stop_sec_server/3]). %% Supervisor callback -export([init/1]). @@ -37,26 +37,26 @@ %%% API %%%========================================================================= -start_link(Addr, Port) -> - SupName = make_name(Addr, Port), +start_link(Addr, Port, Profile) -> + SupName = make_name(Addr, Port, Profile), supervisor:start_link({local, SupName}, ?MODULE, []). %%---------------------------------------------------------------------- %% Function: [start|stop]_[auth|sec]_server/3 %% Description: Starts a [auth | security] worker (child) process %%---------------------------------------------------------------------- -start_auth_server(Addr, Port) -> - start_permanent_worker(mod_auth_server, Addr, Port, [gen_server]). +start_auth_server(Addr, Port, Profile) -> + start_permanent_worker(mod_auth_server, Addr, Port, Profile, [gen_server]). -stop_auth_server(Addr, Port) -> - stop_permanent_worker(mod_auth_server, Addr, Port). +stop_auth_server(Addr, Port, Profile) -> + stop_permanent_worker(mod_auth_server, Addr, Port, Profile). -start_sec_server(Addr, Port) -> - start_permanent_worker(mod_security_server, Addr, Port, [gen_server]). +start_sec_server(Addr, Port, Profile) -> + start_permanent_worker(mod_security_server, Addr, Port, Profile, [gen_server]). -stop_sec_server(Addr, Port) -> - stop_permanent_worker(mod_security_server, Addr, Port). +stop_sec_server(Addr, Port, Profile) -> + stop_permanent_worker(mod_security_server, Addr, Port, Profile). %%%========================================================================= @@ -70,15 +70,15 @@ init(_) -> %%%========================================================================= %%% Internal functions %%%========================================================================= -start_permanent_worker(Mod, Addr, Port, Modules) -> - SupName = make_name(Addr, Port), +start_permanent_worker(Mod, Addr, Port, Profile, Modules) -> + SupName = make_name(Addr, Port, Profile), Spec = {{Mod, Addr, Port}, - {Mod, start_link, [Addr, Port]}, + {Mod, start_link, [Addr, Port, Profile]}, permanent, timer:seconds(1), worker, [Mod] ++ Modules}, supervisor:start_child(SupName, Spec). -stop_permanent_worker(Mod, Addr, Port) -> - SupName = make_name(Addr, Port), +stop_permanent_worker(Mod, Addr, Port, Profile) -> + SupName = make_name(Addr, Port, Profile), Name = {Mod, Addr, Port}, case supervisor:terminate_child(SupName, Name) of ok -> @@ -87,5 +87,5 @@ stop_permanent_worker(Mod, Addr, Port) -> Error end. -make_name(Addr,Port) -> - httpd_util:make_name("httpd_misc_sup",Addr,Port). +make_name(Addr,Port, Profile) -> + httpd_util:make_name("httpd_misc_sup",Addr,Port, Profile). diff --git a/lib/inets/src/http_server/httpd_request.erl b/lib/inets/src/http_server/httpd_request.erl index 3ff07616f9..782120c284 100644 --- a/lib/inets/src/http_server/httpd_request.erl +++ b/lib/inets/src/http_server/httpd_request.erl @@ -42,28 +42,28 @@ %%%========================================================================= %%% Internal application API %%%========================================================================= -parse([Bin, MaxSizes]) -> - ?hdrt("parse", [{bin, Bin}, {max_sizes, MaxSizes}]), - parse_method(Bin, [], 0, proplists:get_value(max_method, MaxSizes), MaxSizes, []); +parse([Bin, Options]) -> + ?hdrt("parse", [{bin, Bin}, {max_sizes, Options}]), + parse_method(Bin, [], 0, proplists:get_value(max_method, Options), Options, []); parse(Unknown) -> ?hdrt("parse", [{unknown, Unknown}]), exit({bad_args, Unknown}). %% Functions that may be returned during the decoding process %% if the input data is incompleate. -parse_method([Bin, Method, Current, Max, MaxSizes, Result]) -> - parse_method(Bin, Method, Current, Max, MaxSizes, Result). +parse_method([Bin, Method, Current, Max, Options, Result]) -> + parse_method(Bin, Method, Current, Max, Options, Result). -parse_uri([Bin, URI, Current, Max, MaxSizes, Result]) -> - parse_uri(Bin, URI, Current, Max, MaxSizes, Result). +parse_uri([Bin, URI, Current, Max, Options, Result]) -> + parse_uri(Bin, URI, Current, Max, Options, Result). -parse_version([Bin, Rest, Version, Current, Max, MaxSizes, Result]) -> - parse_version(<<Rest/binary, Bin/binary>>, Version, Current, Max, MaxSizes, +parse_version([Bin, Rest, Version, Current, Max, Options, Result]) -> + parse_version(<<Rest/binary, Bin/binary>>, Version, Current, Max, Options, Result). -parse_headers([Bin, Rest, Header, Headers, Current, Max, MaxSizes, Result]) -> +parse_headers([Bin, Rest, Header, Headers, Current, Max, Options, Result]) -> parse_headers(<<Rest/binary, Bin/binary>>, - Header, Headers, Current, Max, MaxSizes, Result). + Header, Headers, Current, Max, Options, Result). whole_body([Bin, Body, Length]) -> whole_body(<<Body/binary, Bin/binary>>, Length). @@ -134,13 +134,13 @@ update_mod_data(ModData, Method, RequestURI, HTTPVersion, Headers)-> %%%======================================================================== %%% Internal functions %%%======================================================================== -parse_method(<<>>, Method, Current, Max, MaxSizes, Result) -> - {?MODULE, parse_method, [Method, Current, Max, MaxSizes, Result]}; -parse_method(<<?SP, Rest/binary>>, Method, _Current, _Max, MaxSizes, Result) -> - parse_uri(Rest, [], 0, proplists:get_value(max_uri, MaxSizes), MaxSizes, +parse_method(<<>>, Method, Current, Max, Options, Result) -> + {?MODULE, parse_method, [Method, Current, Max, Options, Result]}; +parse_method(<<?SP, Rest/binary>>, Method, _Current, _Max, Options, Result) -> + parse_uri(Rest, [], 0, proplists:get_value(max_uri, Options), Options, [string:strip(lists:reverse(Method)) | Result]); -parse_method(<<Octet, Rest/binary>>, Method, Current, Max, MaxSizes, Result) when Current =< Max -> - parse_method(Rest, [Octet | Method], Current + 1, Max, MaxSizes, Result); +parse_method(<<Octet, Rest/binary>>, Method, Current, Max, Options, Result) when Current =< Max -> + parse_method(Rest, [Octet | Method], Current + 1, Max, Options, Result); parse_method(_, _, _, Max, _, _) -> %% We do not know the version of the client as it comes after the %% method send the lowest version in the response so that the client @@ -153,30 +153,30 @@ parse_uri(_, _, Current, MaxURI, _, _) %% uri send the lowest version in the response so that the client %% will be able to handle it. {error, {size_error, MaxURI, 414, "URI unreasonably long"},lowest_version()}; -parse_uri(<<>>, URI, Current, Max, MaxSizes, Result) -> - {?MODULE, parse_uri, [URI, Current, Max, MaxSizes, Result]}; -parse_uri(<<?SP, Rest/binary>>, URI, _, _, MaxSizes, Result) -> - parse_version(Rest, [], 0, proplists:get_value(max_version, MaxSizes), MaxSizes, +parse_uri(<<>>, URI, Current, Max, Options, Result) -> + {?MODULE, parse_uri, [URI, Current, Max, Options, Result]}; +parse_uri(<<?SP, Rest/binary>>, URI, _, _, Options, Result) -> + parse_version(Rest, [], 0, proplists:get_value(max_version, Options), Options, [string:strip(lists:reverse(URI)) | Result]); %% Can happen if it is a simple HTTP/0.9 request e.i "GET /\r\n\r\n" -parse_uri(<<?CR, _Rest/binary>> = Data, URI, _, _, MaxSizes, Result) -> - parse_version(Data, [], 0, proplists:get_value(max_version, MaxSizes), MaxSizes, +parse_uri(<<?CR, _Rest/binary>> = Data, URI, _, _, Options, Result) -> + parse_version(Data, [], 0, proplists:get_value(max_version, Options), Options, [string:strip(lists:reverse(URI)) | Result]); -parse_uri(<<Octet, Rest/binary>>, URI, Current, Max, MaxSizes, Result) -> - parse_uri(Rest, [Octet | URI], Current + 1, Max, MaxSizes, Result). +parse_uri(<<Octet, Rest/binary>>, URI, Current, Max, Options, Result) -> + parse_uri(Rest, [Octet | URI], Current + 1, Max, Options, Result). -parse_version(<<>>, Version, Current, Max, MaxSizes, Result) -> - {?MODULE, parse_version, [<<>>, Version, Current, Max, MaxSizes, Result]}; -parse_version(<<?LF, Rest/binary>>, Version, Current, Max, MaxSizes, Result) -> +parse_version(<<>>, Version, Current, Max, Options, Result) -> + {?MODULE, parse_version, [<<>>, Version, Current, Max, Options, Result]}; +parse_version(<<?LF, Rest/binary>>, Version, Current, Max, Options, Result) -> %% If ?CR is is missing RFC2616 section-19.3 - parse_version(<<?CR, ?LF, Rest/binary>>, Version, Current, Max, MaxSizes, Result); -parse_version(<<?CR, ?LF, Rest/binary>>, Version, _, _, MaxSizes, Result) -> - parse_headers(Rest, [], [], 0, proplists:get_value(max_header, MaxSizes), MaxSizes, + parse_version(<<?CR, ?LF, Rest/binary>>, Version, Current, Max, Options, Result); +parse_version(<<?CR, ?LF, Rest/binary>>, Version, _, _, Options, Result) -> + parse_headers(Rest, [], [], 0, proplists:get_value(max_header, Options), Options, [string:strip(lists:reverse(Version)) | Result]); -parse_version(<<?CR>> = Data, Version, Current, Max, MaxSizes, Result) -> - {?MODULE, parse_version, [Data, Version, Current, Max, MaxSizes, Result]}; -parse_version(<<Octet, Rest/binary>>, Version, Current, Max, MaxSizes, Result) when Current =< Max -> - parse_version(Rest, [Octet | Version], Current + 1, Max, MaxSizes, Result); +parse_version(<<?CR>> = Data, Version, Current, Max, Options, Result) -> + {?MODULE, parse_version, [Data, Version, Current, Max, Options, Result]}; +parse_version(<<Octet, Rest/binary>>, Version, Current, Max, Options, Result) when Current =< Max -> + parse_version(Rest, [Octet | Version], Current + 1, Max, Options, Result); parse_version(_, _, _, Max,_,_) -> {error, {size_error, Max, 413, "Version string unreasonably long"}, lowest_version()}. @@ -185,34 +185,42 @@ parse_headers(_, _, _, Current, Max, _, Result) HttpVersion = lists:nth(3, lists:reverse(Result)), {error, {size_error, Max, 413, "Headers unreasonably long"}, HttpVersion}; -parse_headers(<<>>, Header, Headers, Current, Max, MaxSizes, Result) -> +parse_headers(<<>>, Header, Headers, Current, Max, Options, Result) -> {?MODULE, parse_headers, [<<>>, Header, Headers, Current, Max, - MaxSizes, Result]}; -parse_headers(<<?CR,?LF,?LF,Body/binary>>, [], [], Current, Max, MaxSizes, Result) -> + Options, Result]}; +parse_headers(<<?CR,?LF,?LF,Body/binary>>, [], [], Current, Max, Options, Result) -> %% If ?CR is is missing RFC2616 section-19.3 parse_headers(<<?CR,?LF,?CR,?LF,Body/binary>>, [], [], Current, Max, - MaxSizes, Result); + Options, Result); -parse_headers(<<?LF,?LF,Body/binary>>, [], [], Current, Max, MaxSizes, Result) -> +parse_headers(<<?LF,?LF,Body/binary>>, [], [], Current, Max, Options, Result) -> %% If ?CR is is missing RFC2616 section-19.3 parse_headers(<<?CR,?LF,?CR,?LF,Body/binary>>, [], [], Current, Max, - MaxSizes, Result); + Options, Result); parse_headers(<<?CR,?LF,?CR,?LF,Body/binary>>, [], [], _, _, _, Result) -> NewResult = list_to_tuple(lists:reverse([Body, {#http_request_h{}, []} | Result])), {ok, NewResult}; parse_headers(<<?CR,?LF,?CR,?LF,Body/binary>>, Header, Headers, _, _, - MaxSizes, Result) -> + Options, Result) -> + Customize = proplists:get_value(customize, Options), case http_request:key_value(lists:reverse(Header)) of undefined -> %% Skip headers with missing : - {ok, list_to_tuple(lists:reverse([Body, {http_request:headers(Headers, #http_request_h{}), Headers} | Result]))}; + FinalHeaders = lists:filtermap(fun(H) -> + httpd_custom:customize_headers(Customize, request_header, H) + end, + Headers), + {ok, list_to_tuple(lists:reverse([Body, {http_request:headers(FinalHeaders, #http_request_h{}), FinalHeaders} | Result]))}; NewHeader -> - case check_header(NewHeader, MaxSizes) of + case check_header(NewHeader, Options) of ok -> - {ok, list_to_tuple(lists:reverse([Body, {http_request:headers([NewHeader | Headers], + FinalHeaders = lists:filtermap(fun(H) -> + httpd_custom:customize_headers(Customize, request_header, H) + end, [NewHeader | Headers]), + {ok, list_to_tuple(lists:reverse([Body, {http_request:headers(FinalHeaders, #http_request_h{}), - [NewHeader | Headers]} | Result]))}; + FinalHeaders} | Result]))}; {error, Reason} -> HttpVersion = lists:nth(3, lists:reverse(Result)), @@ -221,12 +229,12 @@ parse_headers(<<?CR,?LF,?CR,?LF,Body/binary>>, Header, Headers, _, _, end; parse_headers(<<?CR,?LF,?CR>> = Data, Header, Headers, Current, Max, - MaxSizes, Result) -> + Options, Result) -> {?MODULE, parse_headers, [Data, Header, Headers, Current, Max, - MaxSizes, Result]}; -parse_headers(<<?LF>>, [], [], Current, Max, MaxSizes, Result) -> + Options, Result]}; +parse_headers(<<?LF>>, [], [], Current, Max, Options, Result) -> %% If ?CR is is missing RFC2616 section-19.3 - parse_headers(<<?CR,?LF>>, [], [], Current, Max, MaxSizes, Result); + parse_headers(<<?CR,?LF>>, [], [], Current, Max, Options, Result); %% There where no headers, which is unlikely to happen. parse_headers(<<?CR,?LF>>, [], [], _, _, _, Result) -> @@ -235,30 +243,30 @@ parse_headers(<<?CR,?LF>>, [], [], _, _, _, Result) -> {ok, NewResult}; parse_headers(<<?LF>>, Header, Headers, Current, Max, - MaxSizes, Result) -> + Options, Result) -> %% If ?CR is is missing RFC2616 section-19.3 - parse_headers(<<?CR,?LF>>, Header, Headers, Current, Max, MaxSizes, Result); + parse_headers(<<?CR,?LF>>, Header, Headers, Current, Max, Options, Result); parse_headers(<<?CR,?LF>> = Data, Header, Headers, Current, Max, - MaxSizes, Result) -> + Options, Result) -> {?MODULE, parse_headers, [Data, Header, Headers, Current, Max, - MaxSizes, Result]}; + Options, Result]}; parse_headers(<<?LF, Octet, Rest/binary>>, Header, Headers, Current, Max, - MaxSizes, Result) -> + Options, Result) -> %% If ?CR is is missing RFC2616 section-19.3 parse_headers(<<?CR,?LF, Octet, Rest/binary>>, Header, Headers, Current, Max, - MaxSizes, Result); + Options, Result); parse_headers(<<?CR,?LF, Octet, Rest/binary>>, Header, Headers, _, Max, - MaxSizes, Result) -> + Options, Result) -> case http_request:key_value(lists:reverse(Header)) of undefined -> %% Skip headers with missing : parse_headers(Rest, [Octet], Headers, - 0, Max, MaxSizes, Result); + 0, Max, Options, Result); NewHeader -> - case check_header(NewHeader, MaxSizes) of + case check_header(NewHeader, Options) of ok -> parse_headers(Rest, [Octet], [NewHeader | Headers], - 0, Max, MaxSizes, Result); + 0, Max, Options, Result); {error, Reason} -> HttpVersion = lists:nth(3, lists:reverse(Result)), {error, Reason, HttpVersion} @@ -266,19 +274,19 @@ parse_headers(<<?CR,?LF, Octet, Rest/binary>>, Header, Headers, _, Max, end; parse_headers(<<?CR>> = Data, Header, Headers, Current, Max, - MaxSizes, Result) -> + Options, Result) -> {?MODULE, parse_headers, [Data, Header, Headers, Current, Max, - MaxSizes, Result]}; + Options, Result]}; parse_headers(<<?LF>>, Header, Headers, Current, Max, - MaxSizes, Result) -> + Options, Result) -> %% If ?CR is is missing RFC2616 section-19.3 parse_headers(<<?CR, ?LF>>, Header, Headers, Current, Max, - MaxSizes, Result); + Options, Result); parse_headers(<<Octet, Rest/binary>>, Header, Headers, Current, - Max, MaxSizes, Result) -> + Max, Options, Result) -> parse_headers(Rest, [Octet | Header], Headers, Current + 1, Max, - MaxSizes, Result). + Options, Result). whole_body(Body, Length) -> case size(Body) of diff --git a/lib/inets/src/http_server/httpd_request_handler.erl b/lib/inets/src/http_server/httpd_request_handler.erl index f7a9fe5d49..9947e17b47 100644 --- a/lib/inets/src/http_server/httpd_request_handler.erl +++ b/lib/inets/src/http_server/httpd_request_handler.erl @@ -121,13 +121,15 @@ continue_init(Manager, ConfigDB, SocketType, Socket, TimeOut) -> MaxURISize = max_uri_size(ConfigDB), NrOfRequest = max_keep_alive_request(ConfigDB), MaxContentLen = max_content_length(ConfigDB), + Customize = customize(ConfigDB), {_, Status} = httpd_manager:new_connection(Manager), MFA = {httpd_request, parse, [[{max_uri, MaxURISize}, {max_header, MaxHeaderSize}, {max_version, ?HTTP_MAX_VERSION_STRING}, {max_method, ?HTTP_MAX_METHOD_STRING}, - {max_content_length, MaxContentLen} + {max_content_length, MaxContentLen}, + {customize, Customize} ]]}, State = #state{mod = Mod, @@ -550,11 +552,13 @@ handle_next_request(#state{mod = #mod{connection = true} = ModData, MaxHeaderSize = max_header_size(ModData#mod.config_db), MaxURISize = max_uri_size(ModData#mod.config_db), MaxContentLen = max_content_length(ModData#mod.config_db), + Customize = customize(ModData#mod.config_db), MFA = {httpd_request, parse, [[{max_uri, MaxURISize}, {max_header, MaxHeaderSize}, {max_version, ?HTTP_MAX_VERSION_STRING}, {max_method, ?HTTP_MAX_METHOD_STRING}, - {max_content_length, MaxContentLen} + {max_content_length, MaxContentLen}, + {customize, Customize} ]]}, TmpState = State#state{mod = NewModData, mfa = MFA, @@ -640,3 +644,6 @@ max_keep_alive_request(ConfigDB) -> max_content_length(ConfigDB) -> httpd_util:lookup(ConfigDB, max_content_length, ?HTTP_MAX_CONTENT_LENGTH). + +customize(ConfigDB) -> + httpd_util:lookup(ConfigDB, customize, httpd_custom). diff --git a/lib/inets/src/http_server/httpd_response.erl b/lib/inets/src/http_server/httpd_response.erl index 2fa91d47a0..71dc05e46d 100644 --- a/lib/inets/src/http_server/httpd_response.erl +++ b/lib/inets/src/http_server/httpd_response.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2013. All Rights Reserved. +%% Copyright Ericsson AB 1997-2015. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -176,7 +176,7 @@ send_header(#mod{socket_type = Type, StatusLine = [NewVer, " ", io_lib:write(NewStatusCode), " ", httpd_util:reason_phrase(NewStatusCode), ?CRLF], ConnectionHeader = get_connection(Conn, NewVer), - Head = list_to_binary([StatusLine, Headers, ConnectionHeader , ?CRLF]), + Head = [StatusLine, Headers, ConnectionHeader , ?CRLF], httpd_socket:deliver(Type, Sock, Head). map_status_code("HTTP/1.0", Code) @@ -286,45 +286,21 @@ create_header(ConfigDb, KeyValueTupleHeaders) -> Date = httpd_util:rfc1123_date(), ContentType = "text/html", Server = server(ConfigDb), - NewHeaders = add_default_headers([{"date", Date}, - {"content-type", ContentType} - | if Server=="" -> []; - true -> [{"server", Server}] - end - ], - KeyValueTupleHeaders), - lists:map(fun fix_header/1, NewHeaders). - - + Headers0 = add_default_headers([{"date", Date}, + {"content-type", ContentType} + | if Server=="" -> []; + true -> [{"server", Server}] + end + ], + KeyValueTupleHeaders), + CustomizeCB = httpd_util:lookup(ConfigDb, customize, httpd_custom), + lists:filtermap(fun(H) -> + httpd_custom:customize_headers(CustomizeCB, response_header, H) + end, + [Header || Header <- Headers0]). server(ConfigDb) -> httpd_util:lookup(ConfigDb, server, ?SERVER_SOFTWARE). -fix_header({Key0, Value}) -> - %% make sure first letter is capital - Words1 = string:tokens(Key0, "-"), - Words2 = upify(Words1, []), - Key = new_key(Words2), - Key ++ ": " ++ Value ++ ?CRLF . - -new_key([]) -> - ""; -new_key([W]) -> - W; -new_key([W1,W2]) -> - W1 ++ "-" ++ W2; -new_key([W|R]) -> - W ++ "-" ++ new_key(R). - -upify([], Acc) -> - lists:reverse(Acc); -upify([Key|Rest], Acc) -> - upify(Rest, [upify2(Key)|Acc]). - -upify2([C|Rest]) when (C >= $a) andalso (C =< $z) -> - [C-($a-$A)|Rest]; -upify2(Str) -> - Str. - add_default_headers([], Headers) -> Headers; diff --git a/lib/inets/src/http_server/httpd_sup.erl b/lib/inets/src/http_server/httpd_sup.erl index 3b1e16cf78..b45742136a 100644 --- a/lib/inets/src/http_server/httpd_sup.erl +++ b/lib/inets/src/http_server/httpd_sup.erl @@ -28,7 +28,7 @@ %% Internal application API -export([start_link/1, start_link/2]). --export([start_child/1, restart_child/2, stop_child/2]). +-export([start_child/1, restart_child/3, stop_child/3]). %% Supervisor callback -export([init/1]). @@ -37,7 +37,6 @@ -define(TIMEOUT, 15000). -include("httpd_internal.hrl"). --include("inets_internal.hrl"). %%%========================================================================= %%% API @@ -64,33 +63,32 @@ start_child(Config) -> end. -restart_child(Address, Port) -> - Name = id(Address, Port), +restart_child(Address, Port, Profile) -> + Name = id(Address, Port, Profile), case supervisor:terminate_child(?MODULE, Name) of - ok -> - supervisor:restart_child(?MODULE, Name); - Error -> - Error - end. - -stop_child(Address, Port) -> - Name = id(Address, Port), + ok -> + supervisor:restart_child(?MODULE, Name); + Error -> + Error + end. + +stop_child(Address, Port, Profile) -> + Name = id(Address, Port, Profile), case supervisor:terminate_child(?MODULE, Name) of - ok -> - supervisor:delete_child(?MODULE, Name); - Error -> + ok -> + supervisor:delete_child(?MODULE, Name); + Error -> Error end. - -id(Address, Port) -> - {httpd_instance_sup, Address, Port}. + +id(Address, Port, Profile) -> + {httpd_instance_sup, Address, Port, Profile}. %%%========================================================================= %%% Supervisor callback %%%========================================================================= init([HttpdServices]) -> - ?hdrd("starting", [{httpd_service, HttpdServices}]), RestartStrategy = one_for_one, MaxR = 10, MaxT = 3600, @@ -118,23 +116,18 @@ init([HttpdServices]) -> child_specs([], Acc) -> Acc; child_specs([{httpd, HttpdService} | Rest], Acc) -> - ?hdrd("child specs", [{httpd, HttpdService}]), NewHttpdService = (catch mk_tuple_list(HttpdService)), - ?hdrd("child specs", [{new_httpd, NewHttpdService}]), case catch child_spec(NewHttpdService) of {error, Reason} -> - ?hdri("failed generating child spec", [{reason, Reason}]), error_msg("Failed to start service: ~n~p ~n due to: ~p~n", [HttpdService, Reason]), child_specs(Rest, Acc); Spec -> - ?hdrt("child spec", [{child_spec, Spec}]), child_specs(Rest, [Spec | Acc]) end. child_spec(HttpdService) -> {ok, Config} = httpd_config(HttpdService), - ?hdrt("child spec", [{config, Config}]), Debug = proplists:get_value(debug, Config, []), AcceptTimeout = proplists:get_value(accept_timeout, Config, 15000), httpd_util:valid_options(Debug, AcceptTimeout, Config), @@ -162,32 +155,27 @@ httpd_config([Value| _] = Config) when is_tuple(Value) -> httpd_child_spec([Value| _] = Config, AcceptTimeout, Debug) when is_tuple(Value) -> - ?hdrt("httpd_child_spec - entry", [{accept_timeout, AcceptTimeout}, - {debug, Debug}]), Address = proplists:get_value(bind_address, Config, any), Port = proplists:get_value(port, Config, 80), - httpd_child_spec(Config, AcceptTimeout, Debug, Address, Port); + Profile = proplists:get_value(profile, Config, ?DEFAULT_PROFILE), + httpd_child_spec(Config, AcceptTimeout, Debug, Address, Port, Profile); %% In this case the AcceptTimeout and Debug will only have default values... httpd_child_spec(ConfigFile, AcceptTimeoutDef, DebugDef) -> - ?hdrt("httpd_child_spec - entry", [{config_file, ConfigFile}, - {accept_timeout_def, AcceptTimeoutDef}, - {debug_def, DebugDef}]), case httpd_conf:load(ConfigFile) of {ok, ConfigList} -> - ?hdrt("httpd_child_spec - loaded", [{config_list, ConfigList}]), case (catch httpd_conf:validate_properties(ConfigList)) of {ok, Config} -> - ?hdrt("httpd_child_spec - validated", [{config, Config}]), Address = proplists:get_value(bind_address, Config, any), Port = proplists:get_value(port, Config, 80), + Profile = proplists:get_value(profile, Config, ?DEFAULT_PROFILE), AcceptTimeout = proplists:get_value(accept_timeout, Config, AcceptTimeoutDef), Debug = proplists:get_value(debug, Config, DebugDef), httpd_child_spec([{file, ConfigFile} | Config], - AcceptTimeout, Debug, Address, Port); + AcceptTimeout, Debug, Address, Port, Profile); Error -> Error end; @@ -195,19 +183,19 @@ httpd_child_spec(ConfigFile, AcceptTimeoutDef, DebugDef) -> Error end. -httpd_child_spec(Config, AcceptTimeout, Debug, Addr, Port) -> +httpd_child_spec(Config, AcceptTimeout, Debug, Addr, Port, Profile) -> Fd = proplists:get_value(fd, Config, undefined), case Port == 0 orelse Fd =/= undefined of true -> - httpd_child_spec_listen(Config, AcceptTimeout, Debug, Addr, Port); + httpd_child_spec_listen(Config, AcceptTimeout, Debug, Addr, Port, Profile); false -> - httpd_child_spec_nolisten(Config, AcceptTimeout, Debug, Addr, Port) + httpd_child_spec_nolisten(Config, AcceptTimeout, Debug, Addr, Port, Profile) end. -httpd_child_spec_listen(Config, AcceptTimeout, Debug, Addr, Port) -> +httpd_child_spec_listen(Config, AcceptTimeout, Debug, Addr, Port, Profile) -> case start_listen(Addr, Port, Config) of {Pid, {NewPort, NewConfig, ListenSocket}} -> - Name = {httpd_instance_sup, Addr, NewPort}, + Name = {httpd_instance_sup, Addr, NewPort, Profile}, StartFunc = {httpd_instance_sup, start_link, [NewConfig, AcceptTimeout, {Pid, ListenSocket}, Debug]}, @@ -221,8 +209,8 @@ httpd_child_spec_listen(Config, AcceptTimeout, Debug, Addr, Port) -> {error, Reason} end. -httpd_child_spec_nolisten(Config, AcceptTimeout, Debug, Addr, Port) -> - Name = {httpd_instance_sup, Addr, Port}, +httpd_child_spec_nolisten(Config, AcceptTimeout, Debug, Addr, Port, Profile) -> + Name = {httpd_instance_sup, Addr, Port, Profile}, StartFunc = {httpd_instance_sup, start_link, [Config, AcceptTimeout, Debug]}, Restart = permanent, diff --git a/lib/inets/src/http_server/httpd_util.erl b/lib/inets/src/http_server/httpd_util.erl index 0d04a75205..b1ddc1abbb 100644 --- a/lib/inets/src/http_server/httpd_util.erl +++ b/lib/inets/src/http_server/httpd_util.erl @@ -572,7 +572,10 @@ make_name(Prefix,Port) -> make_name(Prefix,Addr,Port) -> make_name(Prefix,Addr,Port,""). - + +make_name(Prefix, Addr,Port,Postfix) when is_atom(Postfix)-> + make_name(Prefix, Addr,Port, atom_to_list(Postfix)); + make_name(Prefix,"*",Port,Postfix) -> make_name(Prefix,undefined,Port,Postfix); @@ -595,15 +598,7 @@ make_name2({A,B,C,D}) -> io_lib:format("~w_~w_~w_~w", [A,B,C,D]); make_name2({A, B, C, D, E, F, G, H}) -> - io_lib:format("~s_~s_~s_~s_~s_~s_~s_~s", [integer_to_hexlist(A), - integer_to_hexlist(B), - integer_to_hexlist(C), - integer_to_hexlist(D), - integer_to_hexlist(E), - integer_to_hexlist(F), - integer_to_hexlist(G), - integer_to_hexlist(H) - ]); + io_lib:format("~w_~w_~w_~w_~w_~w_~w_~w", [A,B,C,D,E,F,G,H]); make_name2(Addr) -> search_and_replace(Addr,$.,$_). diff --git a/lib/inets/src/http_server/mod_auth.erl b/lib/inets/src/http_server/mod_auth.erl index 85a87ab884..1f4470622d 100644 --- a/lib/inets/src/http_server/mod_auth.erl +++ b/lib/inets/src/http_server/mod_auth.erl @@ -38,15 +38,16 @@ -include("httpd.hrl"). -include("mod_auth.hrl"). -include("httpd_internal.hrl"). --include("inets_internal.hrl"). -define(VMODULE,"AUTH"). -define(NOPASSWORD,"NoPassword"). -%% do +%%==================================================================== +%% Internal application API +%%==================================================================== + do(Info) -> - ?hdrt("do", [{info, Info}]), case proplists:get_value(status,Info#mod.data) of %% A status code has been generated! {_StatusCode, _PhraseArgs, _Reason} -> @@ -61,22 +62,15 @@ do(Info) -> %% Is it a secret area? case secretp(Path,Info#mod.config_db) of {yes, {Directory, DirectoryData}} -> - ?hdrt("secret area", - [{directory, Directory}, - {directory_data, DirectoryData}]), - - %% Authenticate (allow) case allow((Info#mod.init_data)#init_data.peername, Info#mod.socket_type,Info#mod.socket, DirectoryData) of allowed -> - ?hdrt("allowed", []), case deny((Info#mod.init_data)#init_data.peername, Info#mod.socket_type, Info#mod.socket, DirectoryData) of not_denied -> - ?hdrt("not denied", []), case proplists:get_value(auth_type, DirectoryData) of undefined -> @@ -90,15 +84,13 @@ do(Info) -> AuthType) end; {denied, Reason} -> - ?hdrt("denied", [{reason, Reason}]), {proceed, [{status, {403, - Info#mod.request_uri, - Reason}}| + Info#mod.request_uri, + Reason}}| Info#mod.data]} end; {not_allowed, Reason} -> - ?hdrt("not allowed", [{reason, Reason}]), {proceed,[{status,{403, Info#mod.request_uri, Reason}} | @@ -114,18 +106,299 @@ do(Info) -> end. -do_auth(Info, Directory, DirectoryData, AuthType) -> +%% mod_auth recognizes the following Configuration Directives: +%% <Directory /path/to/directory> +%% AuthDBType +%% AuthName +%% AuthUserFile +%% AuthGroupFile +%% AuthAccessPassword +%% require +%% allow +%% </Directory> + +%% When a <Directory> directive is found, a new context is set to +%% [{directory, Directory, DirData}|OtherContext] +%% DirData in this case is a key-value list of data belonging to the +%% directory in question. +%% +%% When the </Directory> statement is found, the Context created earlier +%% will be returned as a ConfigList and the context will return to the +%% state it was previously. + +load("<Directory " ++ Directory,[]) -> + Dir = httpd_conf:custom_clean(Directory,"",">"), + {ok,[{directory, {Dir, [{path, Dir}]}}]}; +load(eof,[{directory, {Directory, _DirData}}|_]) -> + {error, ?NICE("Premature end-of-file in "++ Directory)}; + +load("AuthName " ++ AuthName, [{directory, {Directory, DirData}}|Rest]) -> + {ok, [{directory, {Directory, + [{auth_name, httpd_conf:clean(AuthName)} | DirData]}} + | Rest ]}; +load("AuthUserFile " ++ AuthUserFile0, + [{directory, {Directory, DirData}}|Rest]) -> + AuthUserFile = httpd_conf:clean(AuthUserFile0), + {ok, [{directory, {Directory, + [{auth_user_file, AuthUserFile}|DirData]}} | Rest ]}; +load("AuthGroupFile " ++ AuthGroupFile0, + [{directory, {Directory, DirData}}|Rest]) -> + AuthGroupFile = httpd_conf:clean(AuthGroupFile0), + {ok,[{directory, {Directory, + [{auth_group_file, AuthGroupFile}|DirData]}} | Rest]}; + +load("AuthAccessPassword " ++ AuthAccessPassword0, + [{directory, {Directory, DirData}}|Rest]) -> + AuthAccessPassword = httpd_conf:clean(AuthAccessPassword0), + {ok,[{directory, {Directory, + [{auth_access_password, AuthAccessPassword}|DirData]}} | Rest]}; + +load("AuthDBType " ++ Type, + [{directory, {Dir, DirData}}|Rest]) -> + case httpd_conf:clean(Type) of + "plain" -> + {ok, [{directory, {Dir, [{auth_type, plain}|DirData]}} | Rest ]}; + "mnesia" -> + {ok, [{directory, {Dir, [{auth_type, mnesia}|DirData]}} | Rest ]}; + "dets" -> + {ok, [{directory, {Dir, [{auth_type, dets}|DirData]}} | Rest ]}; + _ -> + {error, ?NICE(httpd_conf:clean(Type)++" is an invalid AuthDBType")} + end; + +load("require " ++ Require,[{directory, {Directory, DirData}}|Rest]) -> + case inets_regexp:split(Require," ") of + {ok,["user"|Users]} -> + {ok,[{directory, {Directory, + [{require_user,Users}|DirData]}} | Rest]}; + {ok,["group"|Groups]} -> + {ok,[{directory, {Directory, + [{require_group,Groups}|DirData]}} | Rest]}; + {ok,_} -> + {error,?NICE(httpd_conf:clean(Require) ++" is an invalid require")} + end; + +load("allow " ++ Allow,[{directory, {Directory, DirData}}|Rest]) -> + case inets_regexp:split(Allow," ") of + {ok,["from","all"]} -> + {ok,[{directory, {Directory, + [{allow_from,all}|DirData]}} | Rest]}; + {ok,["from"|Hosts]} -> + {ok,[{directory, {Directory, + [{allow_from,Hosts}|DirData]}} | Rest]}; + {ok,_} -> + {error,?NICE(httpd_conf:clean(Allow) ++" is an invalid allow")} + end; + +load("deny " ++ Deny,[{directory, {Directory, DirData}}|Rest]) -> + case inets_regexp:split(Deny," ") of + {ok, ["from", "all"]} -> + {ok,[{{directory, Directory, + [{deny_from, all}|DirData]}} | Rest]}; + {ok, ["from"|Hosts]} -> + {ok,[{{directory, Directory, + [{deny_from, Hosts}|DirData]}} | Rest]}; + {ok, _} -> + {error,?NICE(httpd_conf:clean(Deny) ++" is an invalid deny")} + end; + +load("</Directory>",[{directory, {Directory, DirData}}|Rest]) -> + {ok, Rest, {directory, {Directory, DirData}}}; + +load("AuthMnesiaDB " ++ AuthMnesiaDB, + [{directory, {Dir, DirData}}|Rest]) -> + case httpd_conf:clean(AuthMnesiaDB) of + "On" -> + {ok,[{directory, {Dir,[{auth_type,mnesia}|DirData]}}|Rest]}; + "Off" -> + {ok,[{directory, {Dir,[{auth_type,plain}|DirData]}}|Rest]}; + _ -> + {error, ?NICE(httpd_conf:clean(AuthMnesiaDB) ++ + " is an invalid AuthMnesiaDB")} + end. + +store({directory, {Directory, DirData}}, ConfigList) + when is_list(Directory) andalso is_list(DirData) -> + try directory_config_check(Directory, DirData) of + ok -> + store_directory(Directory, DirData, ConfigList) + catch + throw:Error -> + {error, Error, {directory, Directory, DirData}} + end; +store({directory, {Directory, DirData}}, _) -> + {error, {wrong_type, {directory, {Directory, DirData}}}}. + +remove(ConfigDB) -> + lists:foreach(fun({directory, {_Dir, DirData}}) -> + AuthMod = auth_mod_name(DirData), + (catch apply(AuthMod, remove, [DirData])) + end, + ets:match_object(ConfigDB,{directory,{'_','_'}})), + + Addr = httpd_util:lookup(ConfigDB, bind_address, undefined), + Port = httpd_util:lookup(ConfigDB, port), + Profile = httpd_util:lookup(ConfigDB, profile, ?DEFAULT_PROFILE), + mod_auth_server:stop(Addr, Port, Profile), + ok. + +add_user(UserName, Opt) -> + case get_options(Opt, mandatory) of + {Addr, Port, Dir, AuthPwd}-> + case get_options(Opt, userData) of + {error, Reason}-> + {error, Reason}; + {UserData, Password}-> + User = [#httpd_user{username = UserName, + password = Password, + user_data = UserData}], + mod_auth_server:add_user(Addr, Port, Dir, User, AuthPwd) + end + end. + + +add_user(UserName, Password, UserData, Port, Dir) -> + add_user(UserName, Password, UserData, undefined, Port, Dir). +add_user(UserName, Password, UserData, Addr, Port, Dir) -> + User = [#httpd_user{username = UserName, + password = Password, + user_data = UserData}], + mod_auth_server:add_user(Addr, Port, Dir, User, ?NOPASSWORD). + +get_user(UserName, Opt) -> + case get_options(Opt, mandatory) of + {Addr, Port, Dir, AuthPwd} -> + mod_auth_server:get_user(Addr, Port, Dir, UserName, AuthPwd); + {error, Reason} -> + {error, Reason} + end. + +get_user(UserName, Port, Dir) -> + get_user(UserName, undefined, Port, Dir). +get_user(UserName, Addr, Port, Dir) -> + mod_auth_server:get_user(Addr, Port, Dir, UserName, ?NOPASSWORD). + +add_group_member(GroupName, UserName, Opt)-> + case get_options(Opt, mandatory) of + {Addr, Port, Dir, AuthPwd}-> + mod_auth_server:add_group_member(Addr, Port, Dir, + GroupName, UserName, AuthPwd); + {error, Reason} -> + {error, Reason} + end. + +add_group_member(GroupName, UserName, Port, Dir) -> + add_group_member(GroupName, UserName, undefined, Port, Dir). + +add_group_member(GroupName, UserName, Addr, Port, Dir) -> + mod_auth_server:add_group_member(Addr, Port, Dir, + GroupName, UserName, ?NOPASSWORD). + +delete_group_member(GroupName, UserName, Opt) -> + case get_options(Opt, mandatory) of + {Addr, Port, Dir, AuthPwd} -> + mod_auth_server:delete_group_member(Addr, Port, Dir, + GroupName, UserName, AuthPwd); + {error, Reason} -> + {error, Reason} + end. + +delete_group_member(GroupName, UserName, Port, Dir) -> + delete_group_member(GroupName, UserName, undefined, Port, Dir). +delete_group_member(GroupName, UserName, Addr, Port, Dir) -> + mod_auth_server:delete_group_member(Addr, Port, Dir, + GroupName, UserName, ?NOPASSWORD). + +list_users(Opt) -> + case get_options(Opt, mandatory) of + {Addr, Port, Dir, AuthPwd} -> + mod_auth_server:list_users(Addr, Port, Dir, AuthPwd); + {error, Reason} -> + {error, Reason} + end. + +list_users(Port, Dir) -> + list_users(undefined, Port, Dir). +list_users(Addr, Port, Dir) -> + mod_auth_server:list_users(Addr, Port, Dir, ?NOPASSWORD). + +delete_user(UserName, Opt) -> + case get_options(Opt, mandatory) of + {Addr, Port, Dir, AuthPwd} -> + mod_auth_server:delete_user(Addr, Port, Dir, UserName, AuthPwd); + {error, Reason} -> + {error, Reason} + end. + +delete_user(UserName, Port, Dir) -> + delete_user(UserName, undefined, Port, Dir). +delete_user(UserName, Addr, Port, Dir) -> + mod_auth_server:delete_user(Addr, Port, Dir, UserName, ?NOPASSWORD). + +delete_group(GroupName, Opt) -> + case get_options(Opt, mandatory) of + {Addr, Port, Dir, AuthPwd} -> + mod_auth_server:delete_group(Addr, Port, Dir, GroupName, AuthPwd); + {error, Reason} -> + {error, Reason} + end. + +delete_group(GroupName, Port, Dir) -> + delete_group(GroupName, undefined, Port, Dir). +delete_group(GroupName, Addr, Port, Dir) -> + mod_auth_server:delete_group(Addr, Port, Dir, GroupName, ?NOPASSWORD). + +list_groups(Opt) -> + case get_options(Opt, mandatory) of + {Addr, Port, Dir, AuthPwd} -> + mod_auth_server:list_groups(Addr, Port, Dir, AuthPwd); + {error, Reason} -> + {error, Reason} + end. + +list_groups(Port, Dir) -> + list_groups(undefined, Port, Dir). +list_groups(Addr, Port, Dir) -> + mod_auth_server:list_groups(Addr, Port, Dir, ?NOPASSWORD). + +list_group_members(GroupName, Opt) -> + case get_options(Opt, mandatory) of + {Addr, Port, Dir, AuthPwd} -> + mod_auth_server:list_group_members(Addr, Port, Dir, GroupName, + AuthPwd); + {error, Reason} -> + {error, Reason} + end. + +list_group_members(GroupName, Port, Dir) -> + list_group_members(GroupName, undefined, Port, Dir). +list_group_members(GroupName, Addr, Port, Dir) -> + mod_auth_server:list_group_members(Addr, Port, Dir, + GroupName, ?NOPASSWORD). + +update_password(Port, Dir, Old, New, New)-> + update_password(undefined, Port, Dir, Old, New, New). + +update_password(Addr, Port, Dir, Old, New, New) when is_list(New) -> + mod_auth_server:update_password(Addr, Port, Dir, Old, New); + +update_password(_Addr, _Port, _Dir, _Old, _New, _New) -> + {error, badtype}; +update_password(_Addr, _Port, _Dir, _Old, _New, _New1) -> + {error, notqeual}. + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- + +do_auth(Info, Directory, DirectoryData, _AuthType) -> %% Authenticate (require) - ?hdrt("authenticate", [{auth_type, AuthType}]), case require(Info, Directory, DirectoryData) of authorized -> - ?hdrt("authorized", []), {proceed,Info#mod.data}; {authorized, User} -> - ?hdrt("authorized", [{user, User}]), {proceed, [{remote_user,User}|Info#mod.data]}; {authorization_required, Realm} -> - ?hdrt("authorization required", [{realm, Realm}]), ReasonPhrase = httpd_util:reason_phrase(401), Message = httpd_util:message(401,none,Info#mod.config_db), {proceed, @@ -142,8 +415,6 @@ do_auth(Info, Directory, DirectoryData, AuthType) -> Info#mod.data]} end. -%% require - require(Info, Directory, DirectoryData) -> ParsedHeader = Info#mod.parsed_header, ValidUsers = proplists:get_value(require_user, DirectoryData), @@ -270,13 +541,6 @@ auth_mod_name(DirData) -> dets -> mod_auth_dets end. - -%% -%% Is it a secret area? -%% - -%% secretp - secretp(Path,ConfigDB) -> Directories = ets:match(ConfigDB,{directory, {'$1','_'}}), case secret_path(Path, Directories) of @@ -307,12 +571,6 @@ secret_path(Path, [[NewDirectory] | Rest], Directory) -> secret_path(Path, Rest, Directory) end. -%% -%% Authenticate -%% - -%% allow - allow({_,RemoteAddr}, _SocketType, _Socket, DirectoryData) -> Hosts = proplists:get_value(allow_from, DirectoryData, all), case validate_addr(RemoteAddr, Hosts) of @@ -336,8 +594,6 @@ validate_addr(RemoteAddr, [HostRegExp | Rest]) -> validate_addr(RemoteAddr,Rest) end. -%% deny - deny({_,RemoteAddr}, _SocketType, _Socket,DirectoryData) -> Hosts = proplists:get_value(deny_from, DirectoryData, none), case validate_addr(RemoteAddr,Hosts) of @@ -347,124 +603,6 @@ deny({_,RemoteAddr}, _SocketType, _Socket,DirectoryData) -> not_denied end. -%% -%% Configuration -%% - -%% load/2 -%% - -%% mod_auth recognizes the following Configuration Directives: -%% <Directory /path/to/directory> -%% AuthDBType -%% AuthName -%% AuthUserFile -%% AuthGroupFile -%% AuthAccessPassword -%% require -%% allow -%% </Directory> - -%% When a <Directory> directive is found, a new context is set to -%% [{directory, Directory, DirData}|OtherContext] -%% DirData in this case is a key-value list of data belonging to the -%% directory in question. -%% -%% When the </Directory> statement is found, the Context created earlier -%% will be returned as a ConfigList and the context will return to the -%% state it was previously. - -load("<Directory " ++ Directory,[]) -> - Dir = httpd_conf:custom_clean(Directory,"",">"), - {ok,[{directory, {Dir, [{path, Dir}]}}]}; -load(eof,[{directory, {Directory, _DirData}}|_]) -> - {error, ?NICE("Premature end-of-file in "++ Directory)}; - -load("AuthName " ++ AuthName, [{directory, {Directory, DirData}}|Rest]) -> - {ok, [{directory, {Directory, - [{auth_name, httpd_conf:clean(AuthName)} | DirData]}} - | Rest ]}; -load("AuthUserFile " ++ AuthUserFile0, - [{directory, {Directory, DirData}}|Rest]) -> - AuthUserFile = httpd_conf:clean(AuthUserFile0), - {ok, [{directory, {Directory, - [{auth_user_file, AuthUserFile}|DirData]}} | Rest ]}; -load("AuthGroupFile " ++ AuthGroupFile0, - [{directory, {Directory, DirData}}|Rest]) -> - AuthGroupFile = httpd_conf:clean(AuthGroupFile0), - {ok,[{directory, {Directory, - [{auth_group_file, AuthGroupFile}|DirData]}} | Rest]}; - -%AuthAccessPassword -load("AuthAccessPassword " ++ AuthAccessPassword0, - [{directory, {Directory, DirData}}|Rest]) -> - AuthAccessPassword = httpd_conf:clean(AuthAccessPassword0), - {ok,[{directory, {Directory, - [{auth_access_password, AuthAccessPassword}|DirData]}} | Rest]}; - -load("AuthDBType " ++ Type, - [{directory, {Dir, DirData}}|Rest]) -> - case httpd_conf:clean(Type) of - "plain" -> - {ok, [{directory, {Dir, [{auth_type, plain}|DirData]}} | Rest ]}; - "mnesia" -> - {ok, [{directory, {Dir, [{auth_type, mnesia}|DirData]}} | Rest ]}; - "dets" -> - {ok, [{directory, {Dir, [{auth_type, dets}|DirData]}} | Rest ]}; - _ -> - {error, ?NICE(httpd_conf:clean(Type)++" is an invalid AuthDBType")} - end; - -load("require " ++ Require,[{directory, {Directory, DirData}}|Rest]) -> - case inets_regexp:split(Require," ") of - {ok,["user"|Users]} -> - {ok,[{directory, {Directory, - [{require_user,Users}|DirData]}} | Rest]}; - {ok,["group"|Groups]} -> - {ok,[{directory, {Directory, - [{require_group,Groups}|DirData]}} | Rest]}; - {ok,_} -> - {error,?NICE(httpd_conf:clean(Require) ++" is an invalid require")} - end; - -load("allow " ++ Allow,[{directory, {Directory, DirData}}|Rest]) -> - case inets_regexp:split(Allow," ") of - {ok,["from","all"]} -> - {ok,[{directory, {Directory, - [{allow_from,all}|DirData]}} | Rest]}; - {ok,["from"|Hosts]} -> - {ok,[{directory, {Directory, - [{allow_from,Hosts}|DirData]}} | Rest]}; - {ok,_} -> - {error,?NICE(httpd_conf:clean(Allow) ++" is an invalid allow")} - end; - -load("deny " ++ Deny,[{directory, {Directory, DirData}}|Rest]) -> - case inets_regexp:split(Deny," ") of - {ok, ["from", "all"]} -> - {ok,[{{directory, Directory, - [{deny_from, all}|DirData]}} | Rest]}; - {ok, ["from"|Hosts]} -> - {ok,[{{directory, Directory, - [{deny_from, Hosts}|DirData]}} | Rest]}; - {ok, _} -> - {error,?NICE(httpd_conf:clean(Deny) ++" is an invalid deny")} - end; - -load("</Directory>",[{directory, {Directory, DirData}}|Rest]) -> - {ok, Rest, {directory, {Directory, DirData}}}; - -load("AuthMnesiaDB " ++ AuthMnesiaDB, - [{directory, {Dir, DirData}}|Rest]) -> - case httpd_conf:clean(AuthMnesiaDB) of - "On" -> - {ok,[{directory, {Dir,[{auth_type,mnesia}|DirData]}}|Rest]}; - "Off" -> - {ok,[{directory, {Dir,[{auth_type,plain}|DirData]}}|Rest]}; - _ -> - {error, ?NICE(httpd_conf:clean(AuthMnesiaDB) ++ - " is an invalid AuthMnesiaDB")} - end. directory_config_check(Directory, DirData) -> case proplists:get_value(auth_type, DirData) of @@ -482,25 +620,7 @@ check_filename_present(Dir,AuthFile,DirData) -> throw({missing_auth_file, AuthFile, {directory, {Dir, DirData}}}) end. -%% store - -store({directory, {Directory, DirData}}, ConfigList) - when is_list(Directory) andalso is_list(DirData) -> - ?hdrt("store", - [{directory, Directory}, {dir_data, DirData}]), - try directory_config_check(Directory, DirData) of - ok -> - store_directory(Directory, DirData, ConfigList) - catch - throw:Error -> - {error, Error, {directory, Directory, DirData}} - end; -store({directory, {Directory, DirData}}, _) -> - {error, {wrong_type, {directory, {Directory, DirData}}}}. - store_directory(Directory0, DirData0, ConfigList) -> - ?hdrt("store directory - entry", - [{directory, Directory0}, {dir_data, DirData0}]), Port = proplists:get_value(port, ConfigList), DirData = case proplists:get_value(bind_address, ConfigList) of undefined -> @@ -522,9 +642,7 @@ store_directory(Directory0, DirData0, ConfigList) -> dets -> mod_auth_dets; plain -> mod_auth_plain; _ -> no_module_at_all - end, - ?hdrt("store directory", - [{directory, Directory}, {dir_data, DirData}, {auth_mod, AuthMod}]), + end, case AuthMod of no_module_at_all -> {ok, {directory, {Directory, DirData}}}; @@ -560,204 +678,10 @@ store_directory(Directory0, DirData0, ConfigList) -> add_auth_password(Dir, Pwd0, ConfigList) -> Addr = proplists:get_value(bind_address, ConfigList), Port = proplists:get_value(port, ConfigList), - mod_auth_server:start(Addr, Port), + Profile = proplists:get_value(profile, ConfigList, ?DEFAULT_PROFILE), + mod_auth_server:start(Addr, Port, Profile), mod_auth_server:add_password(Addr, Port, Dir, Pwd0). -%% remove - - -remove(ConfigDB) -> - lists:foreach(fun({directory, {_Dir, DirData}}) -> - AuthMod = auth_mod_name(DirData), - (catch apply(AuthMod, remove, [DirData])) - end, - ets:match_object(ConfigDB,{directory,{'_','_'}})), - Addr = case lookup(ConfigDB, bind_address) of - [] -> - undefined; - [{bind_address, Address}] -> - Address - end, - [{port, Port}] = lookup(ConfigDB, port), - mod_auth_server:stop(Addr, Port), - ok. - -%% -------------------------------------------------------------------- - -%% update_password - -update_password(Port, Dir, Old, New, New)-> - update_password(undefined, Port, Dir, Old, New, New). - -update_password(Addr, Port, Dir, Old, New, New) when is_list(New) -> - mod_auth_server:update_password(Addr, Port, Dir, Old, New); - -update_password(_Addr, _Port, _Dir, _Old, _New, _New) -> - {error, badtype}; -update_password(_Addr, _Port, _Dir, _Old, _New, _New1) -> - {error, notqeual}. - - -%% add_user - -add_user(UserName, Opt) -> - case get_options(Opt, mandatory) of - {Addr, Port, Dir, AuthPwd}-> - case get_options(Opt, userData) of - {error, Reason}-> - {error, Reason}; - {UserData, Password}-> - User = [#httpd_user{username = UserName, - password = Password, - user_data = UserData}], - mod_auth_server:add_user(Addr, Port, Dir, User, AuthPwd) - end - end. - - -add_user(UserName, Password, UserData, Port, Dir) -> - add_user(UserName, Password, UserData, undefined, Port, Dir). -add_user(UserName, Password, UserData, Addr, Port, Dir) -> - User = [#httpd_user{username = UserName, - password = Password, - user_data = UserData}], - mod_auth_server:add_user(Addr, Port, Dir, User, ?NOPASSWORD). - - -%% get_user - -get_user(UserName, Opt) -> - case get_options(Opt, mandatory) of - {Addr, Port, Dir, AuthPwd} -> - mod_auth_server:get_user(Addr, Port, Dir, UserName, AuthPwd); - {error, Reason} -> - {error, Reason} - end. - -get_user(UserName, Port, Dir) -> - get_user(UserName, undefined, Port, Dir). -get_user(UserName, Addr, Port, Dir) -> - mod_auth_server:get_user(Addr, Port, Dir, UserName, ?NOPASSWORD). - - -%% add_group_member - -add_group_member(GroupName, UserName, Opt)-> - case get_options(Opt, mandatory) of - {Addr, Port, Dir, AuthPwd}-> - mod_auth_server:add_group_member(Addr, Port, Dir, - GroupName, UserName, AuthPwd); - {error, Reason} -> - {error, Reason} - end. - -add_group_member(GroupName, UserName, Port, Dir) -> - add_group_member(GroupName, UserName, undefined, Port, Dir). - -add_group_member(GroupName, UserName, Addr, Port, Dir) -> - mod_auth_server:add_group_member(Addr, Port, Dir, - GroupName, UserName, ?NOPASSWORD). - - -%% delete_group_member - -delete_group_member(GroupName, UserName, Opt) -> - case get_options(Opt, mandatory) of - {Addr, Port, Dir, AuthPwd} -> - mod_auth_server:delete_group_member(Addr, Port, Dir, - GroupName, UserName, AuthPwd); - {error, Reason} -> - {error, Reason} - end. - -delete_group_member(GroupName, UserName, Port, Dir) -> - delete_group_member(GroupName, UserName, undefined, Port, Dir). -delete_group_member(GroupName, UserName, Addr, Port, Dir) -> - mod_auth_server:delete_group_member(Addr, Port, Dir, - GroupName, UserName, ?NOPASSWORD). - - -%% list_users - -list_users(Opt) -> - case get_options(Opt, mandatory) of - {Addr, Port, Dir, AuthPwd} -> - mod_auth_server:list_users(Addr, Port, Dir, AuthPwd); - {error, Reason} -> - {error, Reason} - end. - -list_users(Port, Dir) -> - list_users(undefined, Port, Dir). -list_users(Addr, Port, Dir) -> - mod_auth_server:list_users(Addr, Port, Dir, ?NOPASSWORD). - - -%% delete_user - -delete_user(UserName, Opt) -> - case get_options(Opt, mandatory) of - {Addr, Port, Dir, AuthPwd} -> - mod_auth_server:delete_user(Addr, Port, Dir, UserName, AuthPwd); - {error, Reason} -> - {error, Reason} - end. - -delete_user(UserName, Port, Dir) -> - delete_user(UserName, undefined, Port, Dir). -delete_user(UserName, Addr, Port, Dir) -> - mod_auth_server:delete_user(Addr, Port, Dir, UserName, ?NOPASSWORD). - - -%% delete_group - -delete_group(GroupName, Opt) -> - case get_options(Opt, mandatory) of - {Addr, Port, Dir, AuthPwd} -> - mod_auth_server:delete_group(Addr, Port, Dir, GroupName, AuthPwd); - {error, Reason} -> - {error, Reason} - end. - -delete_group(GroupName, Port, Dir) -> - delete_group(GroupName, undefined, Port, Dir). -delete_group(GroupName, Addr, Port, Dir) -> - mod_auth_server:delete_group(Addr, Port, Dir, GroupName, ?NOPASSWORD). - - -%% list_groups - -list_groups(Opt) -> - case get_options(Opt, mandatory) of - {Addr, Port, Dir, AuthPwd} -> - mod_auth_server:list_groups(Addr, Port, Dir, AuthPwd); - {error, Reason} -> - {error, Reason} - end. - -list_groups(Port, Dir) -> - list_groups(undefined, Port, Dir). -list_groups(Addr, Port, Dir) -> - mod_auth_server:list_groups(Addr, Port, Dir, ?NOPASSWORD). - - -%% list_group_members - -list_group_members(GroupName, Opt) -> - case get_options(Opt, mandatory) of - {Addr, Port, Dir, AuthPwd} -> - mod_auth_server:list_group_members(Addr, Port, Dir, GroupName, - AuthPwd); - {error, Reason} -> - {error, Reason} - end. - -list_group_members(GroupName, Port, Dir) -> - list_group_members(GroupName, undefined, Port, Dir). -list_group_members(GroupName, Addr, Port, Dir) -> - mod_auth_server:list_group_members(Addr, Port, Dir, - GroupName, ?NOPASSWORD). - %% Opt = [{port, Port}, %% {addr, Addr}, %% {dir, Dir}, @@ -792,7 +716,3 @@ get_options(Opt, userData)-> {UserData, Pwd} end end. - - -lookup(Db, Key) -> - ets:lookup(Db, Key). diff --git a/lib/inets/src/http_server/mod_auth_dets.erl b/lib/inets/src/http_server/mod_auth_dets.erl index a48725d5d9..4220f46166 100644 --- a/lib/inets/src/http_server/mod_auth_dets.erl +++ b/lib/inets/src/http_server/mod_auth_dets.erl @@ -38,23 +38,23 @@ -include("httpd_internal.hrl"). -include("mod_auth.hrl"). -store_directory_data(_Directory, DirData, Server_root) -> - ?CDEBUG("store_directory_data -> ~n" - " Directory: ~p~n" - " DirData: ~p", - [_Directory, DirData]), +%%==================================================================== +%% Internal application API +%%==================================================================== +store_directory_data(_Directory, DirData, Server_root) -> {PWFile, Absolute_pwdfile} = absolute_file_name(auth_user_file, DirData, Server_root), {GroupFile, Absolute_groupfile} = absolute_file_name(auth_group_file, DirData, Server_root), Addr = proplists:get_value(bind_address, DirData), Port = proplists:get_value(port, DirData), + Profile = proplists:get_value(profile, DirData, ?DEFAULT_PROFILE), - PWName = httpd_util:make_name("httpd_dets_pwdb",Addr,Port), + PWName = httpd_util:make_name("httpd_dets_pwdb", Addr, Port, Profile), case dets:open_file(PWName,[{type,set},{file,Absolute_pwdfile},{repair,true}]) of {ok, PWDB} -> - GDBName = httpd_util:make_name("httpd_dets_groupdb",Addr,Port), + GDBName = httpd_util:make_name("httpd_dets_groupdb", Addr, Port, Profile), case dets:open_file(GDBName,[{type,set},{file,Absolute_groupfile},{repair,true}]) of {ok, GDB} -> NDD1 = lists:keyreplace(auth_user_file, 1, DirData, @@ -69,11 +69,8 @@ store_directory_data(_Directory, DirData, Server_root) -> {error, {{file, PWFile},Err2}} end. -%% %% Storage format of users in the dets table: %% {{UserName, Addr, Port, Dir}, Password, UserData} -%% - add_user(DirData, UStruct) -> {Addr, Port, Dir} = lookup_common(DirData), PWDB = proplists:get_value(auth_user_file, DirData), @@ -99,21 +96,15 @@ get_user(DirData, UserName) -> end. list_users(DirData) -> - ?DEBUG("list_users -> ~n" - " DirData: ~p", [DirData]), {Addr, Port, Dir} = lookup_common(DirData), PWDB = proplists:get_value(auth_user_file, DirData), - case dets:traverse(PWDB, fun(X) -> {continue, X} end) of %% SOOOO Ugly ! + case dets:traverse(PWDB, fun(X) -> {continue, X} end) of Records when is_list(Records) -> - ?DEBUG("list_users -> ~n" - " Records: ~p", [Records]), {ok, [UserName || {{UserName, AnyAddr, AnyPort, AnyDir}, _Password, _Data} <- Records, AnyAddr == Addr, AnyPort == Port, AnyDir == Dir]}; _O -> - ?DEBUG("list_users -> ~n" - " O: ~p", [_O]), {ok, []} end. @@ -134,10 +125,8 @@ delete_user(DirData, UserName) -> {error, no_such_user} end. -%% %% Storage of groups in the dets table: %% {Group, UserList} where UserList is a list of strings. -%% add_group_member(DirData, GroupName, UserName) -> {Addr, Port, Dir} = lookup_common(DirData), GDB = proplists:get_value(auth_group_file, DirData), @@ -215,16 +204,7 @@ delete_group(DirData, GroupName) -> {error, no_such_group} end. -lookup_common(DirData) -> - Dir = proplists:get_value(path, DirData), - Port = proplists:get_value(port, DirData), - Addr = proplists:get_value(bind_address, DirData), - {Addr, Port, Dir}. - -%% remove/1 -%% %% Closes dets tables used by this auth mod. -%% remove(DirData) -> PWDB = proplists:get_value(auth_user_file, DirData), GDB = proplists:get_value(auth_group_file, DirData), @@ -232,8 +212,9 @@ remove(DirData) -> dets:close(PWDB), ok. -%% absolute_file_name/2 -%% +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- %% Return the absolute path name of File_type. absolute_file_name(File_type, DirData, Server_root) -> Path = proplists:get_value(File_type, DirData), @@ -253,3 +234,8 @@ absolute_file_name(File_type, DirData, Server_root) -> end, {Path, Absolute_path}. +lookup_common(DirData) -> + Dir = proplists:get_value(path, DirData), + Port = proplists:get_value(port, DirData), + Addr = proplists:get_value(bind_address, DirData), + {Addr, Port, Dir}. diff --git a/lib/inets/src/http_server/mod_auth_plain.erl b/lib/inets/src/http_server/mod_auth_plain.erl index c0a83711ba..7bb86fc812 100644 --- a/lib/inets/src/http_server/mod_auth_plain.erl +++ b/lib/inets/src/http_server/mod_auth_plain.erl @@ -22,15 +22,11 @@ -include("httpd.hrl"). -include("mod_auth.hrl"). -include("httpd_internal.hrl"). --include("inets_internal.hrl"). - -define(VMODULE,"AUTH_PLAIN"). %% Internal API -export([store_directory_data/3]). - - -export([get_user/2, list_group_members/2, add_user/2, @@ -42,17 +38,13 @@ delete_group/2, remove/1]). -%% -%% API -%% +%%==================================================================== +%% Internal application API +%%==================================================================== -%% %% Storage format of users in the ets table: %% {UserName, Password, UserData} -%% - add_user(DirData, #httpd_user{username = User} = UStruct) -> - ?hdrt("add user", [{user, UStruct}]), PWDB = proplists:get_value(auth_user_file, DirData), Record = {User, UStruct#httpd_user.password, @@ -66,7 +58,6 @@ add_user(DirData, #httpd_user{username = User} = UStruct) -> end. get_user(DirData, User) -> - ?hdrt("get user", [{dir_data, DirData}, {user, User}]), PWDB = proplists:get_value(auth_user_file, DirData), case ets:lookup(PWDB, User) of [{User, PassWd, Data}] -> @@ -84,7 +75,6 @@ list_users(DirData) -> [], lists:flatten(Records))}. delete_user(DirData, UserName) -> - ?hdrt("delete user", [{dir_data, DirData}, {user, UserName}]), PWDB = proplists:get_value(auth_user_file, DirData), case ets:lookup(PWDB, UserName) of [{UserName, _SomePassword, _SomeData}] -> @@ -98,11 +88,8 @@ delete_user(DirData, UserName) -> {error, no_such_user} end. -%% %% Storage of groups in the ets table: %% {Group, UserList} where UserList is a list of strings. -%% - add_group_member(DirData, Group, UserName) -> GDB = proplists:get_value(auth_group_file, DirData), case ets:lookup(GDB, Group) of @@ -163,17 +150,12 @@ delete_group(DirData, Group) -> end. store_directory_data(_Directory, DirData, Server_root) -> - ?hdrt("store directory data", - [{dir_data, DirData}, {server_root, Server_root}]), PWFile = absolute_file_name(auth_user_file, DirData, Server_root), GroupFile = absolute_file_name(auth_group_file, DirData, Server_root), case load_passwd(PWFile) of {ok, PWDB} -> - ?hdrt("password file loaded", [{file, PWFile}, {pwdb, PWDB}]), case load_group(GroupFile) of {ok, GRDB} -> - ?hdrt("group file loaded", - [{file, GroupFile}, {grdb, GRDB}]), %% Address and port is included in the file names... Addr = proplists:get_value(bind_address, DirData), Port = proplists:get_value(port, DirData), @@ -191,9 +173,83 @@ store_directory_data(_Directory, DirData, Server_root) -> {error, Err2} end. +%% Deletes ets tables used by this auth mod. +remove(DirData) -> + PWDB = proplists:get_value(auth_user_file, DirData), + GDB = proplists:get_value(auth_group_file, DirData), + ets:delete(PWDB), + ets:delete(GDB). +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- +%% Return the absolute path name of File_type. +absolute_file_name(File_type, DirData, Server_root) -> + Path = proplists:get_value(File_type, DirData), + case filename:pathtype(Path) of + relative -> + case Server_root of + undefined -> + {error, + ?NICE(Path++ + " is an invalid file name because " + "ServerRoot is not defined")}; + _ -> + filename:join(Server_root,Path) + end; + _ -> + Path + end. -%% load_passwd +store_group(Addr,Port,GroupList) -> + %% Not a named table so not importante to add Profile to name + Name = httpd_util:make_name("httpd_group",Addr,Port), + GroupDB = ets:new(Name, [set, public]), + store_group(GroupDB, GroupList). + +store_group(GroupDB,[]) -> + {ok, GroupDB}; +store_group(GroupDB, [User|Rest]) -> + ets:insert(GroupDB, User), + store_group(GroupDB, Rest). + +store_passwd(Addr,Port,PasswdList) -> + %% Not a named table so not importante to add Profile to name + Name = httpd_util:make_name("httpd_passwd",Addr,Port), + PasswdDB = ets:new(Name, [set, public]), + store_passwd(PasswdDB, PasswdList). + +store_passwd(PasswdDB, []) -> + {ok, PasswdDB}; +store_passwd(PasswdDB, [User|Rest]) -> + ets:insert(PasswdDB, User), + store_passwd(PasswdDB, Rest). + +parse_group(Stream, GroupList) -> + Line = + case io:get_line(Stream,'') of + eof -> + eof; + String -> + httpd_conf:clean(String) + end, + parse_group(Stream, GroupList, Line). + +parse_group(Stream, GroupList, eof) -> + file:close(Stream), + {ok, GroupList}; +parse_group(Stream, GroupList, "") -> + parse_group(Stream, GroupList); +parse_group(Stream, GroupList, [$#|_]) -> + parse_group(Stream, GroupList); +parse_group(Stream, GroupList, Line) -> + case inets_regexp:split(Line, ":") of + {ok, [Group,Users]} -> + {ok, UserList} = inets_regexp:split(Users," "), + parse_group(Stream, [{Group,UserList}|GroupList]); + {ok, _} -> + {error, ?NICE(Line)} + end. load_passwd(AuthUserFile) -> case file:open(AuthUserFile, [read]) of @@ -228,8 +284,6 @@ parse_passwd(Stream, PasswdList, Line) -> {error, ?NICE(Line)} end. -%% load_group - load_group(AuthGroupFile) -> case file:open(AuthGroupFile, [read]) of {ok, Stream} -> @@ -237,91 +291,3 @@ load_group(AuthGroupFile) -> {error, _} -> {error, ?NICE("Can't open " ++ AuthGroupFile)} end. - -parse_group(Stream, GroupList) -> - Line = - case io:get_line(Stream,'') of - eof -> - eof; - String -> - httpd_conf:clean(String) - end, - parse_group(Stream, GroupList, Line). - -parse_group(Stream, GroupList, eof) -> - file:close(Stream), - {ok, GroupList}; -parse_group(Stream, GroupList, "") -> - parse_group(Stream, GroupList); -parse_group(Stream, GroupList, [$#|_]) -> - parse_group(Stream, GroupList); -parse_group(Stream, GroupList, Line) -> - case inets_regexp:split(Line, ":") of - {ok, [Group,Users]} -> - {ok, UserList} = inets_regexp:split(Users," "), - parse_group(Stream, [{Group,UserList}|GroupList]); - {ok, _} -> - {error, ?NICE(Line)} - end. - - -%% store_passwd - -store_passwd(Addr,Port,PasswdList) -> - Name = httpd_util:make_name("httpd_passwd",Addr,Port), - PasswdDB = ets:new(Name, [set, public]), - store_passwd(PasswdDB, PasswdList). - -store_passwd(PasswdDB, []) -> - {ok, PasswdDB}; -store_passwd(PasswdDB, [User|Rest]) -> - ets:insert(PasswdDB, User), - store_passwd(PasswdDB, Rest). - -%% store_group - -store_group(Addr,Port,GroupList) -> - Name = httpd_util:make_name("httpd_group",Addr,Port), - GroupDB = ets:new(Name, [set, public]), - store_group(GroupDB, GroupList). - - -store_group(GroupDB,[]) -> - {ok, GroupDB}; -store_group(GroupDB, [User|Rest]) -> - ets:insert(GroupDB, User), - store_group(GroupDB, Rest). - - -%% remove/1 -%% -%% Deletes ets tables used by this auth mod. -%% -remove(DirData) -> - PWDB = proplists:get_value(auth_user_file, DirData), - GDB = proplists:get_value(auth_group_file, DirData), - ets:delete(PWDB), - ets:delete(GDB). - - - -%% absolute_file_name/2 -%% -%% Return the absolute path name of File_type. -absolute_file_name(File_type, DirData, Server_root) -> - Path = proplists:get_value(File_type, DirData), - case filename:pathtype(Path) of - relative -> - case Server_root of - undefined -> - {error, - ?NICE(Path++ - " is an invalid file name because " - "ServerRoot is not defined")}; - _ -> - filename:join(Server_root,Path) - end; - _ -> - Path - end. - diff --git a/lib/inets/src/http_server/mod_auth_server.erl b/lib/inets/src/http_server/mod_auth_server.erl index 947273bd9e..2a45f402d7 100644 --- a/lib/inets/src/http_server/mod_auth_server.erl +++ b/lib/inets/src/http_server/mod_auth_server.erl @@ -22,246 +22,184 @@ -include("httpd.hrl"). -include("httpd_internal.hrl"). --include("inets_internal.hrl"). -behaviour(gen_server). - %% mod_auth exports --export([start/2, stop/2, +-export([start/3, stop/3, add_password/4, update_password/5, add_user/5, delete_user/5, get_user/5, list_users/4, add_group_member/6, delete_group_member/6, list_group_members/5, delete_group/5, list_groups/4]). %% gen_server exports --export([start_link/2, init/1, +-export([start_link/3, init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -record(state, {tab}). +%%==================================================================== +%% Internal application API +%%==================================================================== -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% %% -%% External API %% -%% %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% start_link/3 -%% %% NOTE: This is called by httpd_misc_sup when the process is started %% -start_link(Addr, Port) -> - ?hdrt("start_link", [{address, Addr}, {port, Port}]), - Name = make_name(Addr, Port), +start_link(Addr, Port, Profile) -> + Name = make_name(Addr, Port, Profile), gen_server:start_link({local, Name}, ?MODULE, [], [{timeout, infinity}]). - -%% start/2 - -start(Addr, Port) -> - ?hdrd("start", [{address, Addr}, {port, Port}]), - Name = make_name(Addr, Port), +start(Addr, Port, Profile) -> + Name = make_name(Addr, Port, Profile), case whereis(Name) of undefined -> - httpd_misc_sup:start_auth_server(Addr, Port); + httpd_misc_sup:start_auth_server(Addr, Port, Profile); _ -> %% Already started... ok end. - -%% stop/2 - -stop(Addr, Port) -> - ?hdrd("stop", [{address, Addr}, {port, Port}]), - Name = make_name(Addr, Port), +stop(Addr, Port, Profile) -> + Name = make_name(Addr, Port, Profile), case whereis(Name) of undefined -> %% Already stopped ok; _ -> - (catch httpd_misc_sup:stop_auth_server(Addr, Port)) + (catch httpd_misc_sup:stop_auth_server(Addr, Port, Profile)) end. -%% add_password/4 - add_password(Addr, Port, Dir, Password) -> - ?hdrt("add password", [{address, Addr}, {port, Port}]), - Name = make_name(Addr, Port), + add_password(Addr, Port, ?DEFAULT_PROFILE, Dir, Password). +add_password(Addr, Port, Profile, Dir, Password) -> + Name = make_name(Addr, Port, Profile), Req = {add_password, Dir, Password}, call(Name, Req). - -%% update_password/6 - -update_password(Addr, Port, Dir, Old, New) when is_list(New) -> - ?hdrt("update password", - [{address, Addr}, {port, Port}, {dir, Dir}, {old, Old}, {new, New}]), - Name = make_name(Addr, Port), +update_password(Addr, Port, Dir, Old, New) -> + update_password(Addr, Port, ?DEFAULT_PROFILE, Dir, Old, New). +update_password(Addr, Port, Profile, Dir, Old, New) when is_list(New) -> + Name = make_name(Addr, Port, Profile), Req = {update_password, Dir, Old, New}, call(Name, Req). - - -%% add_user/5 add_user(Addr, Port, Dir, User, Password) -> - ?hdrt("add user", - [{address, Addr}, {port, Port}, - {dir, Dir}, {user, User}, {passwd, Password}]), - Name = make_name(Addr, Port), - Req = {add_user, Addr, Port, Dir, User, Password}, + add_user(Addr, Port, ?DEFAULT_PROFILE, Dir, User, Password). +add_user(Addr, Port, Profile, Dir, User, Password) -> + Name = make_name(Addr, Port, Profile), + Req = {add_user, Addr, Port, Profile, Dir, User, Password}, call(Name, Req). - -%% delete_user/5 - delete_user(Addr, Port, Dir, UserName, Password) -> - ?hdrt("delete user", - [{address, Addr}, {port, Port}, - {dir, Dir}, {user, UserName}, {passwd, Password}]), - Name = make_name(Addr, Port), - Req = {delete_user, Addr, Port, Dir, UserName, Password}, + delete_user(Addr, Port, ?DEFAULT_PROFILE, Dir, UserName, Password). +delete_user(Addr, Port, Profile, Dir, UserName, Password) -> + Name = make_name(Addr, Port, Profile), + Req = {delete_user, Addr, Port, Profile, Dir, UserName, Password}, call(Name, Req). - -%% get_user/5 - get_user(Addr, Port, Dir, UserName, Password) -> - ?hdrt("get user", - [{address, Addr}, {port, Port}, - {dir, Dir}, {user, UserName}, {passwd, Password}]), - Name = make_name(Addr, Port), - Req = {get_user, Addr, Port, Dir, UserName, Password}, + get_user(Addr, Port, ?DEFAULT_PROFILE, Dir, UserName, Password). +get_user(Addr, Port, Profile,Dir, UserName, Password) -> + Name = make_name(Addr, Port, Profile), + Req = {get_user, Addr, Port, Profile, Dir, UserName, Password}, call(Name, Req). - -%% list_users/4 - list_users(Addr, Port, Dir, Password) -> - ?hdrt("list users", - [{address, Addr}, {port, Port}, {dir, Dir}, {passwd, Password}]), - Name = make_name(Addr,Port), - Req = {list_users, Addr, Port, Dir, Password}, + list_users(Addr, Port, ?DEFAULT_PROFILE, Dir, Password). +list_users(Addr, Port, Profile, Dir, Password) -> + Name = make_name(Addr,Port, Profile), + Req = {list_users, Addr, Port, Profile, Dir, Password}, call(Name, Req). - -%% add_group_member/6 - add_group_member(Addr, Port, Dir, GroupName, UserName, Password) -> - ?hdrt("add group member", - [{address, Addr}, {port, Port}, {dir, Dir}, - {group, GroupName}, {user, UserName}, {passwd, Password}]), - Name = make_name(Addr,Port), - Req = {add_group_member, Addr, Port, Dir, GroupName, UserName, Password}, + add_group_member(Addr, Port, ?DEFAULT_PROFILE, Dir, GroupName, UserName, Password). +add_group_member(Addr, Port, Profile, Dir, GroupName, UserName, Password) -> + Name = make_name(Addr,Port, Profile), + Req = {add_group_member, Addr, Port, Profile, Dir, GroupName, UserName, Password}, call(Name, Req). - -%% delete_group_member/6 - delete_group_member(Addr, Port, Dir, GroupName, UserName, Password) -> - ?hdrt("delete group member", - [{address, Addr}, {port, Port}, {dir, Dir}, - {group, GroupName}, {user, UserName}, {passwd, Password}]), - Name = make_name(Addr,Port), - Req = {delete_group_member, Addr, Port, Dir, GroupName, UserName, Password}, + delete_group_member(Addr, Port, ?DEFAULT_PROFILE, Dir, GroupName, UserName, Password). +delete_group_member(Addr, Port, Profile, Dir, GroupName, UserName, Password) -> + Name = make_name(Addr,Port,Profile), + Req = {delete_group_member, Addr, Port, Profile, Dir, GroupName, UserName, Password}, call(Name, Req). - -%% list_group_members/4 - list_group_members(Addr, Port, Dir, Group, Password) -> - ?hdrt("list group members", - [{address, Addr}, {port, Port}, {dir, Dir}, - {group, Group}, {passwd, Password}]), - Name = make_name(Addr, Port), + list_group_members(Addr, Port, ?DEFAULT_PROFILE, Dir, Group, Password). +list_group_members(Addr, Port, Profile, Dir, Group, Password) -> + Name = make_name(Addr, Port, Profile), Req = {list_group_members, Addr, Port, Dir, Group, Password}, call(Name, Req). - -%% delete_group/5 - delete_group(Addr, Port, Dir, GroupName, Password) -> - ?hdrt("delete group", - [{address, Addr}, {port, Port}, {dir, Dir}, - {group, GroupName}, {passwd, Password}]), - Name = make_name(Addr, Port), - Req = {delete_group, Addr, Port, Dir, GroupName, Password}, + delete_group(Addr, Port, ?DEFAULT_PROFILE, Dir, GroupName, Password). +delete_group(Addr, Port, Profile, Dir, GroupName, Password) -> + Name = make_name(Addr, Port, Profile), + Req = {delete_group, Addr, Port, Profile, Dir, GroupName, Password}, call(Name, Req). - -%% list_groups/4 - list_groups(Addr, Port, Dir, Password) -> - ?hdrt("list groups", - [{address, Addr}, {port, Port}, {dir, Dir}, {passwd, Password}]), - Name = make_name(Addr, Port), - Req = {list_groups, Addr, Port, Dir, Password}, + list_groups(Addr, Port, ?DEFAULT_PROFILE, Dir, Password). +list_groups(Addr, Port, Profile, Dir, Password) -> + Name = make_name(Addr, Port, Profile), + Req = {list_groups, Addr, Port,Profile, Dir, Password}, call(Name, Req). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% %% -%% Server call-back functions %% -%% %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% init - +%%==================================================================== +%% Behavior call backs +%%==================================================================== init(_) -> - ?hdrv("initiating", []), {ok,#state{tab = ets:new(auth_pwd,[set,protected])}}. %% handle_call %% Add a user -handle_call({add_user, Addr, Port, Dir, User, AuthPwd}, _From, State) -> - Reply = api_call(Addr, Port, Dir, add_user, User, AuthPwd, State), - ?hdrt("add user", [{reply, Reply}]), +handle_call({add_user, Addr, Port, Profile, Dir, User, AuthPwd}, _From, State) -> + Reply = api_call(Addr, Port, Profile, Dir, add_user, User, AuthPwd, State), {reply, Reply, State}; %% Get data about a user -handle_call({get_user, Addr, Port, Dir, User, AuthPwd}, _From, State) -> - Reply = api_call(Addr, Port, Dir, get_user, [User], AuthPwd, State), +handle_call({get_user, Addr, Port, Profile, Dir, User, AuthPwd}, _From, State) -> + Reply = api_call(Addr, Port, Profile, Dir, get_user, [User], AuthPwd, State), {reply, Reply, State}; %% Add a group member -handle_call({add_group_member, Addr, Port, Dir, Group, User, AuthPwd}, +handle_call({add_group_member, Addr, Port, Profile, Dir, Group, User, AuthPwd}, _From, State) -> - Reply = api_call(Addr, Port, Dir, add_group_member, [Group, User], + Reply = api_call(Addr, Port, Profile, Dir, add_group_member, [Group, User], AuthPwd, State), {reply, Reply, State}; %% delete a group -handle_call({delete_group_member, Addr, Port, Dir, Group, User, AuthPwd}, +handle_call({delete_group_member, Addr, Port, Profile, Dir, Group, User, AuthPwd}, _From, State) -> - Reply = api_call(Addr, Port, Dir, delete_group_member, [Group, User], + Reply = api_call(Addr, Port, Profile, Dir, delete_group_member, [Group, User], AuthPwd, State), {reply, Reply, State}; %% List all users thats standalone users -handle_call({list_users, Addr, Port, Dir, AuthPwd}, _From, State) -> - Reply = api_call(Addr, Port, Dir, list_users, [], AuthPwd, State), +handle_call({list_users, Addr, Port, Profile, Dir, AuthPwd}, _From, State) -> + Reply = api_call(Addr, Port, Profile, Dir, list_users, [], AuthPwd, State), {reply, Reply, State}; %% Delete a user -handle_call({delete_user, Addr, Port, Dir, User, AuthPwd}, _From, State) -> - Reply = api_call(Addr, Port, Dir, delete_user, [User], AuthPwd, State), +handle_call({delete_user, Addr, Port, Profile, Dir, User, AuthPwd}, _From, State) -> + Reply = api_call(Addr, Port, Profile, Dir, delete_user, [User], AuthPwd, State), {reply, Reply, State}; %% Delete a group -handle_call({delete_group, Addr, Port, Dir, Group, AuthPwd}, _From, State) -> - Reply = api_call(Addr, Port, Dir, delete_group, [Group], AuthPwd, State), +handle_call({delete_group, Addr, Port, Profile, Dir, Group, AuthPwd}, _From, State) -> + Reply = api_call(Addr, Port, Profile, Dir, delete_group, [Group], AuthPwd, State), {reply, Reply, State}; %% List the current groups -handle_call({list_groups, Addr, Port, Dir, AuthPwd}, _From, State) -> - Reply = api_call(Addr, Port, Dir, list_groups, [], AuthPwd, State), +handle_call({list_groups, Addr, Port, Profile, Dir, AuthPwd}, _From, State) -> + Reply = api_call(Addr, Port, Profile, Dir, list_groups, [], AuthPwd, State), {reply, Reply, State}; %% List the members of the given group -handle_call({list_group_members, Addr, Port, Dir, Group, AuthPwd}, +handle_call({list_group_members, Addr, Port, Profile, Dir, Group, AuthPwd}, _From, State) -> - Reply = api_call(Addr, Port, Dir, list_group_members, [Group], + Reply = api_call(Addr, Port, Profile, Dir, list_group_members, [Group], AuthPwd, State), {reply, Reply, State}; @@ -306,26 +244,16 @@ terminate(_Reason,State) -> ets:delete(State#state.tab), ok. - -%% code_change(Vsn, State, Extra) -%% code_change(_Vsn, State, _Extra) -> {ok, State}. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% %% -%% The functions that really changes the data in the database %% -%% of users to different directories %% -%% %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% API gateway - -api_call(Addr, Port, Dir, Func, Args,Password,State) -> +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- +api_call(Addr, Port, Profile, Dir, Func, Args,Password,State) -> case controlPassword(Password, State, Dir) of ok-> - ConfigName = httpd_util:make_name("httpd_conf", Addr, Port), + ConfigName = httpd_util:make_name("httpd_conf", Addr, Port, Profile), case ets:match_object(ConfigName, {directory, {Dir, '$1'}}) of [{directory, {Dir, DirData}}] -> AuthMod = auth_mod_name(DirData), @@ -386,8 +314,8 @@ lookup(Db, Key) -> ets:lookup(Db, Key). -make_name(Addr,Port) -> - httpd_util:make_name("httpd_auth",Addr,Port). +make_name(Addr, Port, Profile) -> + httpd_util:make_name(?MODULE, Addr, Port, Profile). call(Name, Req) -> @@ -397,5 +325,3 @@ call(Name, Req) -> Reply -> Reply end. - - diff --git a/lib/inets/src/http_server/mod_security.erl b/lib/inets/src/http_server/mod_security.erl index 41988732ad..a85383a921 100644 --- a/lib/inets/src/http_server/mod_security.erl +++ b/lib/inets/src/http_server/mod_security.erl @@ -32,14 +32,13 @@ -include("httpd.hrl"). -include("httpd_internal.hrl"). --include("inets_internal.hrl"). -define(VMODULE,"SEC"). - -%% do/1 +%%==================================================================== +%% Internal application API +%%==================================================================== do(Info) -> - ?hdrt("do", [{info, Info}]), %% Check and see if any user has been authorized. case proplists:get_value(remote_user, Info#mod.data,not_defined_user) of not_defined_user -> @@ -84,151 +83,66 @@ do(Info) -> {_Dir, SDirData} = secretp(Path, Info#mod.config_db), Addr = httpd_util:lookup(Info#mod.config_db, bind_address), Port = httpd_util:lookup(Info#mod.config_db, port), + Profile = httpd_util:lookup(Info#mod.config_db, profile, ?DEFAULT_PROFILE), case mod_security_server:check_blocked_user(Info, User, SDirData, - Addr, Port) of + Addr, Port, Profile) of true -> report_failed(Info, User ,"User Blocked"), {proceed, [{status, {403, Info#mod.request_uri, ""}} | Info#mod.data]}; false -> report_failed(Info, User,"Authentication Succedded"), - mod_security_server:store_successful_auth(Addr, Port, + mod_security_server:store_successful_auth(Addr, Port, Profile, User, SDirData), {proceed, Info#mod.data} end end. -report_failed(Info, Auth, Event) -> - Request = Info#mod.request_line, - {_PortNumber,RemoteHost}=(Info#mod.init_data)#init_data.peername, - String = RemoteHost ++ " : " ++ Event ++ " : " ++ Request ++ - " : " ++ Auth, - mod_disk_log:security_log(Info,String), - mod_log:security_log(Info, String). - -take_failed_action(Info, Auth) -> - ?hdrd("take failed action", [{auth, Auth}]), - Path = mod_alias:path(Info#mod.data, Info#mod.config_db, - Info#mod.request_uri), - {_Dir, SDirData} = secretp(Path, Info#mod.config_db), - Addr = httpd_util:lookup(Info#mod.config_db, bind_address), - Port = httpd_util:lookup(Info#mod.config_db, port), - mod_security_server:store_failed_auth(Info, Addr, Port, - Auth, SDirData). - -secretp(Path, ConfigDB) -> - Directories = ets:match(ConfigDB,{directory,{'$1','_'}}), - case secret_path(Path, Directories) of - {yes, Directory} -> - ?hdrd("secretp - yes", [{dir, Directory}]), - SDirs0 = httpd_util:multi_lookup(ConfigDB, security_directory), - [SDir] = lists:filter(fun({Directory0, _}) - when Directory0 == Directory -> - true; - (_) -> - false - end, SDirs0), - SDir; - no -> - {[], []} - end. - -secret_path(Path,Directories) -> - secret_path(Path, httpd_util:uniq(lists:sort(Directories)), to_be_found). - -secret_path(_Path, [], to_be_found) -> - no; -secret_path(_Path, [], Dir) -> - {yes, Dir}; -secret_path(Path, [[NewDir]|Rest], Dir) -> - case inets_regexp:match(Path, NewDir) of - {match, _, _} when Dir =:= to_be_found -> - secret_path(Path, Rest, NewDir); - {match, _, Length} when Length > length(Dir) -> - secret_path(Path, Rest, NewDir); - {match, _, _} -> - secret_path(Path, Rest, Dir); - nomatch -> - secret_path(Path, Rest, Dir) - end. - - load("<Directory " ++ Directory, []) -> - ?hdrt("load security directory - begin", [{directory, Directory}]), Dir = httpd_conf:custom_clean(Directory,"",">"), {ok, [{security_directory, {Dir, [{path, Dir}]}}]}; load(eof,[{security_directory, {Directory, _DirData}}|_]) -> {error, ?NICE("Premature end-of-file in "++Directory)}; load("SecurityDataFile " ++ FileName, [{security_directory, {Dir, DirData}}]) -> - ?hdrt("load security directory", - [{file, FileName}, {dir, Dir}, {dir_data, DirData}]), File = httpd_conf:clean(FileName), {ok, [{security_directory, {Dir, [{data_file, File}|DirData]}}]}; load("SecurityCallbackModule " ++ ModuleName, [{security_directory, {Dir, DirData}}]) -> - ?hdrt("load security directory", - [{module, ModuleName}, {dir, Dir}, {dir_data, DirData}]), Mod = list_to_atom(httpd_conf:clean(ModuleName)), {ok, [{security_directory, {Dir, [{callback_module, Mod}|DirData]}}]}; load("SecurityMaxRetries " ++ Retries, [{security_directory, {Dir, DirData}}]) -> - ?hdrt("load security directory", - [{max_retries, Retries}, {dir, Dir}, {dir_data, DirData}]), load_return_int_tag("SecurityMaxRetries", max_retries, httpd_conf:clean(Retries), Dir, DirData); load("SecurityBlockTime " ++ Time, [{security_directory, {Dir, DirData}}]) -> - ?hdrt("load security directory", - [{block_time, Time}, {dir, Dir}, {dir_data, DirData}]), load_return_int_tag("SecurityBlockTime", block_time, httpd_conf:clean(Time), Dir, DirData); load("SecurityFailExpireTime " ++ Time, [{security_directory, {Dir, DirData}}]) -> - ?hdrt("load security directory", - [{expire_time, Time}, {dir, Dir}, {dir_data, DirData}]), load_return_int_tag("SecurityFailExpireTime", fail_expire_time, httpd_conf:clean(Time), Dir, DirData); load("SecurityAuthTimeout " ++ Time0, [{security_directory, {Dir, DirData}}]) -> - ?hdrt("load security directory", - [{auth_timeout, Time0}, {dir, Dir}, {dir_data, DirData}]), Time = httpd_conf:clean(Time0), load_return_int_tag("SecurityAuthTimeout", auth_timeout, httpd_conf:clean(Time), Dir, DirData); load("AuthName " ++ Name0, [{security_directory, {Dir, DirData}}]) -> - ?hdrt("load security directory", - [{name, Name0}, {dir, Dir}, {dir_data, DirData}]), Name = httpd_conf:clean(Name0), {ok, [{security_directory, {Dir, [{auth_name, Name}|DirData]}}]}; load("</Directory>",[{security_directory, {Dir, DirData}}]) -> - ?hdrt("load security directory - end", - [{dir, Dir}, {dir_data, DirData}]), {ok, [], {security_directory, {Dir, DirData}}}. -load_return_int_tag(Name, Atom, Time, Dir, DirData) -> - case Time of - "infinity" -> - {ok, [{security_directory, {Dir, - [{Atom, 99999999999999999999999999999} | DirData]}}]}; - _Int -> - case catch list_to_integer(Time) of - {'EXIT', _} -> - {error, Time++" is an invalid "++Name}; - Val -> - {ok, [{security_directory, {Dir, [{Atom, Val}|DirData]}}]} - end - end. - store({security_directory, {Dir, DirData}}, ConfigList) when is_list(Dir) andalso is_list(DirData) -> - ?hdrt("store security directory", [{dir, Dir}, {dir_data, DirData}]), Addr = proplists:get_value(bind_address, ConfigList), Port = proplists:get_value(port, ConfigList), - mod_security_server:start(Addr, Port), + Profile = proplists:get_value(profile, ConfigList, ?DEFAULT_PROFILE), + mod_security_server:start(Addr, Port, Profile), SR = proplists:get_value(server_root, ConfigList), case proplists:get_value(data_file, DirData, no_data_file) of no_data_file -> @@ -241,7 +155,7 @@ store({security_directory, {Dir, DirData}}, ConfigList) _ -> DataFile0 end, - case mod_security_server:new_table(Addr, Port, DataFile) of + case mod_security_server:new_table(Addr, Port, Profile, DataFile) of {ok, TwoTables} -> NewDirData0 = lists:keyreplace(data_file, 1, DirData, {data_file, TwoTables}), @@ -261,45 +175,35 @@ store({directory, {Directory, DirData}}, _) -> {error, {wrong_type, {security_directory, {Directory, DirData}}}}. remove(ConfigDB) -> - Addr = case ets:lookup(ConfigDB, bind_address) of - [] -> - undefined; - [{bind_address, Address}] -> - Address - end, - [{port, Port}] = ets:lookup(ConfigDB, port), - mod_security_server:delete_tables(Addr, Port), - mod_security_server:stop(Addr, Port). + Addr = httpd_util:lookup(ConfigDB, bind_address, undefined), + Port = httpd_util:lookup(ConfigDB, port), + Profile = httpd_util:lookup(ConfigDB, profile, ?DEFAULT_PROFILE), + mod_security_server:delete_tables(Addr, Port, Profile), + mod_security_server:stop(Addr, Port, Profile). -%% -%% User API -%% - -%% list_blocked_users - list_blocked_users(Port) -> list_blocked_users(undefined, Port). list_blocked_users(Port, Dir) when is_integer(Port) -> list_blocked_users(undefined,Port,Dir); list_blocked_users(Addr, Port) when is_integer(Port) -> - mod_security_server:list_blocked_users(Addr, Port). + lists:map(fun({User, Addr0, Port0, ?DEFAULT_PROFILE, Dir0, Time}) -> + {User, Addr0, Port0, Dir0,Time} + end, + mod_security_server:list_blocked_users(Addr, Port)). list_blocked_users(Addr, Port, Dir) -> - mod_security_server:list_blocked_users(Addr, Port, Dir). - - -%% block_user + lists:map(fun({User, Addr0, Port0, ?DEFAULT_PROFILE, Dir0, Time}) -> + {User, Addr0, Port0, Dir0,Time} + end, + mod_security_server:list_blocked_users(Addr, Port, Dir)). block_user(User, Port, Dir, Time) -> block_user(User, undefined, Port, Dir, Time). block_user(User, Addr, Port, Dir, Time) -> mod_security_server:block_user(User, Addr, Port, Dir, Time). - -%% unblock_user - unblock_user(User, Port) -> unblock_user(User, undefined, Port). @@ -311,9 +215,6 @@ unblock_user(User, Addr, Port) when is_integer(Port) -> unblock_user(User, Addr, Port, Dir) -> mod_security_server:unblock_user(User, Addr, Port, Dir). - -%% list_auth_users - list_auth_users(Port) -> list_auth_users(undefined,Port). @@ -324,3 +225,76 @@ list_auth_users(Addr, Port) when is_integer(Port) -> list_auth_users(Addr, Port, Dir) -> mod_security_server:list_auth_users(Addr, Port, Dir). + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- + +report_failed(Info, Auth, Event) -> + Request = Info#mod.request_line, + {_PortNumber,RemoteHost}=(Info#mod.init_data)#init_data.peername, + String = RemoteHost ++ " : " ++ Event ++ " : " ++ Request ++ + " : " ++ Auth, + mod_disk_log:security_log(Info,String), + mod_log:security_log(Info, String). + +take_failed_action(Info, Auth) -> + Path = mod_alias:path(Info#mod.data, Info#mod.config_db, + Info#mod.request_uri), + {_Dir, SDirData} = secretp(Path, Info#mod.config_db), + Addr = httpd_util:lookup(Info#mod.config_db, bind_address), + Port = httpd_util:lookup(Info#mod.config_db, port), + Profile = httpd_util:lookup(Info#mod.config_db, profile, ?DEFAULT_PROFILE), + mod_security_server:store_failed_auth(Info, Addr, Port, Profile, + Auth, SDirData). + +secretp(Path, ConfigDB) -> + Directories = ets:match(ConfigDB,{directory,{'$1','_'}}), + case secret_path(Path, Directories) of + {yes, Directory} -> + SDirs0 = httpd_util:multi_lookup(ConfigDB, security_directory), + [SDir] = lists:filter(fun({Directory0, _}) + when Directory0 == Directory -> + true; + (_) -> + false + end, SDirs0), + SDir; + no -> + {[], []} + end. + +secret_path(Path,Directories) -> + secret_path(Path, httpd_util:uniq(lists:sort(Directories)), to_be_found). + +secret_path(_Path, [], to_be_found) -> + no; +secret_path(_Path, [], Dir) -> + {yes, Dir}; +secret_path(Path, [[NewDir]|Rest], Dir) -> + case inets_regexp:match(Path, NewDir) of + {match, _, _} when Dir =:= to_be_found -> + secret_path(Path, Rest, NewDir); + {match, _, Length} when Length > length(Dir) -> + secret_path(Path, Rest, NewDir); + {match, _, _} -> + secret_path(Path, Rest, Dir); + nomatch -> + secret_path(Path, Rest, Dir) + end. + + + +load_return_int_tag(Name, Atom, Time, Dir, DirData) -> + case Time of + "infinity" -> + {ok, [{security_directory, {Dir, + [{Atom, 99999999999999999999999999999} | DirData]}}]}; + _Int -> + case catch list_to_integer(Time) of + {'EXIT', _} -> + {error, Time++" is an invalid "++Name}; + Val -> + {ok, [{security_directory, {Dir, [{Atom, Val}|DirData]}}]} + end + end. diff --git a/lib/inets/src/http_server/mod_security_server.erl b/lib/inets/src/http_server/mod_security_server.erl index 784b3eba70..4f37dff18c 100644 --- a/lib/inets/src/http_server/mod_security_server.erl +++ b/lib/inets/src/http_server/mod_security_server.erl @@ -45,7 +45,6 @@ -include("httpd.hrl"). -include("httpd_internal.hrl"). --include("inets_internal.hrl"). -behaviour(gen_server). @@ -57,129 +56,105 @@ list_auth_users/2, list_auth_users/3]). %% Internal exports (for mod_security only) --export([start/2, stop/1, stop/2, - new_table/3, delete_tables/2, - store_failed_auth/5, store_successful_auth/4, - check_blocked_user/5]). +-export([start/3, stop/2, stop/3, + new_table/4, delete_tables/3, + store_failed_auth/6, store_successful_auth/5, + check_blocked_user/6]). %% gen_server exports --export([start_link/2, init/1, +-export([start_link/3, init/1, handle_info/2, handle_call/3, handle_cast/2, terminate/2, code_change/3]). +%%==================================================================== +%% Internal application API +%%==================================================================== -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% %% -%% External API %% -%% %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% start_link/3 -%% %% NOTE: This is called by httpd_misc_sup when the process is started -%% - -start_link(Addr, Port) -> - ?hdrt("start_link", [{address, Addr}, {port, Port}]), - Name = make_name(Addr, Port), +start_link(Addr, Port, Profile) -> + Name = make_name(Addr, Port, Profile), gen_server:start_link({local, Name}, ?MODULE, [], [{timeout, infinity}]). - -%% start/2 %% Called by the mod_security module. - -start(Addr, Port) -> - ?hdrt("start", [{address, Addr}, {port, Port}]), - Name = make_name(Addr, Port), +start(Addr, Port, Profile) -> + Name = make_name(Addr, Port, Profile), case whereis(Name) of undefined -> - httpd_misc_sup:start_sec_server(Addr, Port); + httpd_misc_sup:start_sec_server(Addr, Port, Profile); _ -> %% Already started... ok end. - -%% stop - -stop(Port) -> - stop(undefined, Port). -stop(Addr, Port) -> - ?hdrt("stop", [{address, Addr}, {port, Port}]), - Name = make_name(Addr, Port), +stop(Port, Profile) -> + stop(undefined, Port, Profile). +stop(Addr, Port, Profile) -> + Name = make_name(Addr, Port, Profile), case whereis(Name) of undefined -> ok; _ -> - httpd_misc_sup:stop_sec_server(Addr, Port) + httpd_misc_sup:stop_sec_server(Addr, Port, Profile) end. - addr(undefined) -> any; addr(Addr) -> Addr. - -%% list_blocked_users - list_blocked_users(Addr, Port) -> - Name = make_name(Addr, Port), - Req = {list_blocked_users, addr(Addr), Port, '_'}, - call(Name, Req). - + list_blocked_users(Addr, Port, ?DEFAULT_PROFILE). +list_blocked_users(Addr, Port, Profile) when is_atom(Profile)-> + Name = make_name(Addr, Port, Profile), + Req = {list_blocked_users, addr(Addr), Port, Profile,'_'}, + call(Name, Req); list_blocked_users(Addr, Port, Dir) -> - Name = make_name(Addr, Port), - Req = {list_blocked_users, addr(Addr), Port, Dir}, + list_blocked_users(Addr, Port, ?DEFAULT_PROFILE, Dir). +list_blocked_users(Addr, Port, Profile, Dir) -> + Name = make_name(Addr, Port, Profile), + Req = {list_blocked_users, addr(Addr), Port, Profile, Dir}, call(Name, Req). - -%% block_user - block_user(User, Addr, Port, Dir, Time) -> - Name = make_name(Addr, Port), - Req = {block_user, User, addr(Addr), Port, Dir, Time}, + block_user(User, Addr, Port, ?DEFAULT_PROFILE, Dir, Time). +block_user(User, Addr, Port, Profile, Dir, Time) -> + Name = make_name(Addr, Port, Profile), + Req = {block_user, User, addr(Addr), Port, Profile, Dir, Time}, call(Name, Req). - -%% unblock_user - unblock_user(User, Addr, Port) -> - Name = make_name(Addr, Port), - Req = {unblock_user, User, addr(Addr), Port, '_'}, - call(Name, Req). - + unblock_user(User, Addr, Port, ?DEFAULT_PROFILE). +unblock_user(User, Addr, Port, Profile) when is_atom(Profile)-> + Name = make_name(Addr, Port, Profile), + Req = {unblock_user, User, addr(Addr), Port, Profile, '_'}, + call(Name, Req); unblock_user(User, Addr, Port, Dir) -> - Name = make_name(Addr, Port), - Req = {unblock_user, User, addr(Addr), Port, Dir}, + unblock_user(User, Addr, Port, ?DEFAULT_PROFILE, Dir). +unblock_user(User, Addr, Port, Profile, Dir) -> + Name = make_name(Addr, Port, Profile), + Req = {unblock_user, User, addr(Addr), Port, Profile, Dir}, call(Name, Req). - -%% list_auth_users - list_auth_users(Addr, Port) -> - Name = make_name(Addr, Port), - Req = {list_auth_users, addr(Addr), Port, '_'}, - call(Name, Req). - + list_auth_users(Addr, Port, ?DEFAULT_PROFILE). +list_auth_users(Addr, Port, Profile) when is_atom(Profile) -> + Name = make_name(Addr, Port, Profile), + Req = {list_auth_users, addr(Addr), Port, Profile, '_'}, + call(Name, Req); list_auth_users(Addr, Port, Dir) -> - Name = make_name(Addr,Port), - Req = {list_auth_users, addr(Addr), Port, Dir}, + list_auth_users(Addr, Port, ?DEFAULT_PROFILE, Dir). +list_auth_users(Addr, Port, Profile, Dir) -> + Name = make_name(Addr,Port, Profile), + Req = {list_auth_users, addr(Addr), Port, Profile, Dir}, call(Name, Req). - -%% new_table - -new_table(Addr, Port, TabName) -> - Name = make_name(Addr,Port), - Req = {new_table, addr(Addr), Port, TabName}, +new_table(Addr, Port, Profile, TabName) -> + Name = make_name(Addr,Port, Profile), + Req = {new_table, addr(Addr), Port, Profile, TabName}, call(Name, Req). - -%% delete_tables - -delete_tables(Addr, Port) -> - Name = make_name(Addr, Port), +delete_tables(Addr, Port, Profile) -> + Name = make_name(Addr, Port, Profile), case whereis(Name) of undefined -> ok; @@ -187,79 +162,53 @@ delete_tables(Addr, Port) -> call(Name, delete_tables) end. - -%% store_failed_auth - -store_failed_auth(Info, Addr, Port, DecodedString, SDirData) -> - ?hdrv("store failed auth", - [{addr, Addr}, {port, Port}, - {decoded_string, DecodedString}, {sdir_data, SDirData}]), - Name = make_name(Addr,Port), - Msg = {store_failed_auth,[Info,DecodedString,SDirData]}, +store_failed_auth(Info, Addr, Port, Profile, DecodedString, SDirData) -> + Name = make_name(Addr, Port, Profile), + Msg = {store_failed_auth, Profile, [Info,DecodedString,SDirData]}, cast(Name, Msg). - -%% store_successful_auth - -store_successful_auth(Addr, Port, User, SDirData) -> - Name = make_name(Addr,Port), - Msg = {store_successful_auth, [User,Addr,Port,SDirData]}, +store_successful_auth(Addr, Port, Profile, User, SDirData) -> + Name = make_name(Addr,Port, Profile), + Msg = {store_successful_auth, [User,Addr,Port, Profile, SDirData]}, cast(Name, Msg). - - -%% check_blocked_user - -check_blocked_user(Info, User, SDirData, Addr, Port) -> - Name = make_name(Addr, Port), - Req = {check_blocked_user, [Info, User, SDirData]}, + +check_blocked_user(Info, User, SDirData, Addr, Port, Profile) -> + Name = make_name(Addr, Port, Profile), + Req = {check_blocked_user, Profile, [Info, User, SDirData]}, call(Name, Req). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% %% -%% Server call-back functions %% -%% %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - +%%==================================================================== +%% Behavior call backs +%%==================================================================== init(_) -> - ?hdrv("initiating", []), process_flag(trap_exit, true), {ok, []}. handle_call(stop, _From, _Tables) -> {stop, normal, ok, []}; -handle_call({block_user, User, Addr, Port, Dir, Time}, _From, Tables) -> - ?hdrv("block user", - [{user, User}, {addr, Addr}, {port, Port}, {dir, Dir}, - {time, Time}]), - Ret = block_user_int(User, Addr, Port, Dir, Time), +handle_call({block_user, User, Addr, Port, Profile, Dir, Time}, _From, Tables) -> + Ret = block_user_int(User, Addr, Port, Profile, Dir, Time), {reply, Ret, Tables}; -handle_call({list_blocked_users, Addr, Port, Dir}, _From, Tables) -> - ?hdrv("list blocked users", - [{addr, Addr}, {port, Port}, {dir, Dir}]), - Blocked = list_blocked(Tables, Addr, Port, Dir, []), +handle_call({list_blocked_users, Addr, Port, Profile, Dir}, _From, Tables) -> + Blocked = list_blocked(Tables, Addr, Port, Profile, Dir, []), {reply, Blocked, Tables}; -handle_call({unblock_user, User, Addr, Port, Dir}, _From, Tables) -> - ?hdrv("block user", - [{user, User}, {addr, Addr}, {port, Port}, {dir, Dir}]), - Ret = unblock_user_int(User, Addr, Port, Dir), +handle_call({unblock_user, User, Addr, Port, Profile, Dir}, _From, Tables) -> + Ret = unblock_user_int(User, Addr, Port, Profile,Dir), {reply, Ret, Tables}; -handle_call({list_auth_users, Addr, Port, Dir}, _From, Tables) -> - ?hdrv("list auth users", - [{addr, Addr}, {port, Port}, {dir, Dir}]), - Auth = list_auth(Tables, Addr, Port, Dir, []), +handle_call({list_auth_users, Addr, Port, Profile, Dir}, _From, Tables) -> + Auth = list_auth(Tables, Addr, Port, Profile, Dir, []), {reply, Auth, Tables}; -handle_call({new_table, Addr, Port, Name}, _From, Tables) -> +handle_call({new_table, Addr, Port, Profile, Name}, _From, Tables) -> case lists:keysearch(Name, 1, Tables) of {value, {Name, {Ets, Dets}}} -> {reply, {ok, {Ets, Dets}}, Tables}; false -> - TName = make_name(Addr,Port,length(Tables)), + TName = make_name(Addr,Port, Profile, length(Tables)), case dets:open_file(TName, [{type, bag}, {file, Name}, {repair, true}, {access, read_write}]) of @@ -280,7 +229,7 @@ handle_call(delete_tables, _From, Tables) -> end, Tables), {reply, ok, []}; -handle_call({check_blocked_user, [Info, User, SDirData]}, _From, Tables) -> +handle_call({check_blocked_user, Profile, [Info, User, SDirData]}, _From, Tables) -> {ETS, DETS} = proplists:get_value(data_file, SDirData), Dir = proplists:get_value(path, SDirData), Addr = proplists:get_value(bind_address, SDirData), @@ -288,27 +237,24 @@ handle_call({check_blocked_user, [Info, User, SDirData]}, _From, Tables) -> CBModule = proplists:get_value(callback_module, SDirData, no_module_at_all), Ret = - check_blocked_user(Info, User, Dir, Addr, Port, ETS, DETS, CBModule), + check_blocked_user(Info, User, Dir, Addr, Port, Profile, ETS, DETS, CBModule), {reply, Ret, Tables}; handle_call(_Request,_From,Tables) -> {reply,ok,Tables}. - -%% handle_cast - -handle_cast({store_failed_auth, [_, _, []]}, Tables) -> +handle_cast({store_failed_auth, _,[_, _, []]}, Tables) -> %% Some other authentication scheme than mod_auth (example mod_htacess) %% was the source for the authentication failure so we should ignor it! {noreply, Tables}; -handle_cast({store_failed_auth, [Info, DecodedString, SDirData]}, Tables) -> +handle_cast({store_failed_auth, Profile, [Info, DecodedString, SDirData]}, Tables) -> {ETS, DETS} = proplists:get_value(data_file, SDirData), Dir = proplists:get_value(path, SDirData), Addr = proplists:get_value(bind_address, SDirData), Port = proplists:get_value(port, SDirData), {ok, [User,Password]} = httpd_util:split(DecodedString,":",2), Seconds = universal_time(), - Key = {User, Dir, Addr, Port}, + Key = {User, Dir, Addr, Port, Profile}, %% Event CBModule = proplists:get_value(callback_module, SDirData, no_module_at_all), @@ -363,7 +309,7 @@ handle_cast({store_failed_auth, [Info, DecodedString, SDirData]}, Tables) -> dets:match_delete(DETS, {blocked_user, {User, Addr, Port, Dir, '$1'}}), BlockRecord = {blocked_user, - {User, Addr, Port, Dir, Future}}, + {User, Addr, Port, Profile, Dir, Future}}, ets:insert(ETS, BlockRecord), dets:insert(DETS, BlockRecord), %% Remove previous failed requests. @@ -374,11 +320,11 @@ handle_cast({store_failed_auth, [Info, DecodedString, SDirData]}, Tables) -> end, {noreply, Tables}; -handle_cast({store_successful_auth, [User, Addr, Port, SDirData]}, Tables) -> +handle_cast({store_successful_auth, [User, Addr, Port, Profile, SDirData]}, Tables) -> {ETS, DETS} = proplists:get_value(data_file, SDirData), AuthTimeOut = proplists:get_value(auth_timeout, SDirData, 30), Dir = proplists:get_value(path, SDirData), - Key = {User, Dir, Addr, Port}, + Key = {User, Dir, Addr, Port, Profile}, %% Remove failed entries for this Key dets:match_delete(DETS, {failed, {Key, '_', '_'}}), @@ -396,33 +342,22 @@ handle_cast(Req, Tables) -> error_msg("security server got unknown cast: ~p",[Req]), {noreply, Tables}. - -%% handle_info - handle_info(_Info, State) -> {noreply, State}. - -%% terminate - terminate(_Reason, _Tables) -> ok. - -%% code_change({down, ToVsn}, State, Extra) -%% -code_change({down, _}, State, _Extra) -> - {ok, State}; - - -%% code_change(FromVsn, State, Extra) -%% code_change(_, State, _Extra) -> {ok, State}. +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- + %% block_user_int/5 -block_user_int(User, Addr, Port, Dir, Time) -> - Dirs = httpd_manager:config_match(Addr, Port, +block_user_int(User, Addr, Port, Profile, Dir, Time) -> + Dirs = httpd_manager:config_match(Addr, Port, Profile, {security_directory, {'_', '_'}}), case find_dirdata(Dirs, Dir) of {ok, DirData, {ETS, DETS}} -> @@ -434,11 +369,11 @@ block_user_int(User, Addr, Port, Dir, Time) -> Time end, Future = universal_time()+Time1, - ets:match_delete(ETS, {blocked_user, {User,Addr,Port,Dir,'_'}}), + ets:match_delete(ETS, {blocked_user, {User,Addr,Port,Profile, Dir,'_'}}), dets:match_delete(DETS, {blocked_user, - {User,Addr,Port,Dir,'_'}}), - ets:insert(ETS, {blocked_user, {User,Addr,Port,Dir,Future}}), - dets:insert(DETS, {blocked_user, {User,Addr,Port,Dir,Future}}), + {User,Addr,Port,Profile, Dir,'_'}}), + ets:insert(ETS, {blocked_user, {User,Addr,Port, Profile, Dir,Future}}), + dets:insert(DETS, {blocked_user, {User,Addr,Port,Profile, Dir,Future}}), CBModule = proplists:get_value(callback_module, DirData, no_module_at_all), user_block_event(CBModule,Addr,Port,Dir,User), @@ -447,7 +382,6 @@ block_user_int(User, Addr, Port, Dir, Time) -> {error, no_such_directory} end. - find_dirdata([], _Dir) -> false; find_dirdata([{security_directory, {_, DirData}}|SDirs], Dir) -> @@ -460,21 +394,20 @@ find_dirdata([{security_directory, {_, DirData}}|SDirs], Dir) -> find_dirdata(SDirs, Dir) end. -%% unblock_user_int/4 -unblock_user_int(User, Addr, Port, Dir) -> - Dirs = httpd_manager:config_match(Addr, Port, +unblock_user_int(User, Addr, Port, Profile, Dir) -> + Dirs = httpd_manager:config_match(Addr, Port, Profile, {security_directory, {'_', '_'}}), case find_dirdata(Dirs, Dir) of {ok, DirData, {ETS, DETS}} -> case ets:match_object(ETS, - {blocked_user,{User,Addr,Port,Dir,'_'}}) of + {blocked_user,{User,Addr,Port,Profile,Dir,'_'}}) of [] -> {error, not_blocked}; _Objects -> ets:match_delete(ETS, {blocked_user, - {User, Addr, Port, Dir, '_'}}), + {User, Addr, Port, Profile, Dir, '_'}}), dets:match_delete(DETS, {blocked_user, - {User, Addr, Port, Dir, '_'}}), + {User, Addr, Port, Profile, Dir, '_'}}), CBModule = proplists:get_value(callback_module, DirData, no_module_at_all), @@ -485,63 +418,51 @@ unblock_user_int(User, Addr, Port, Dir) -> {error, no_such_directory} end. - - -%% list_auth/2 - -list_auth([], _Addr, _Port, _Dir, Acc) -> +list_auth([], _, _, _, _, Acc) -> Acc; -list_auth([{_Name, {ETS, DETS}}|Tables], Addr, Port, Dir, Acc) -> - case ets:match_object(ETS, {success, {{'_', Dir, Addr, Port}, '_'}}) of +list_auth([{_Name, {ETS, DETS}}|Tables], Addr, Port, Profile, Dir, Acc) -> + case ets:match_object(ETS, {success, {{'_', Dir, Addr, Port, Profile}, '_'}}) of [] -> - list_auth(Tables, Addr, Port, Dir, Acc); + list_auth(Tables, Addr, Port, Profile, Dir, Acc); List -> TN = universal_time(), - NewAcc = lists:foldr(fun({success,{{U,Ad,P,D},T}},Ac) -> + NewAcc = lists:foldr(fun({success,{{U,Ad,P, Pr,D},T}},Ac) -> if T-TN > 0 -> [U|Ac]; true -> Rec = {success, - {{U,Ad,P,D},T}}, + {{U,Ad,P,Pr,D},T}}, ets:match_delete(ETS,Rec), dets:match_delete(DETS,Rec), Ac end end, Acc, List), - list_auth(Tables, Addr, Port, Dir, NewAcc) + list_auth(Tables, Addr, Port, Profile, Dir, NewAcc) end. - -%% list_blocked/2 - -list_blocked([], _Addr, _Port, _Dir, Acc) -> - ?hdrv("list blocked", [{acc, Acc}]), +list_blocked([], _, _, _, _, Acc) -> TN = universal_time(), - lists:foldl(fun({U,Ad,P,D,T}, Ac) -> + lists:foldl(fun({U,Ad,P,Pr,D,T}, Ac) -> if T-TN > 0 -> - [{U,Ad,P,D,local_time(T)}|Ac]; + [{U,Ad,P, Pr,D,local_time(T)}|Ac]; true -> Ac end end, [], Acc); -list_blocked([{_Name, {ETS, _DETS}}|Tables], Addr, Port, Dir, Acc) -> - ?hdrv("list blocked", [{ets, ETS}, {tab2list, ets:tab2list(ETS)}]), +list_blocked([{_Name, {ETS, _DETS}}|Tables], Addr, Port, Profile, Dir, Acc) -> List = ets:match_object(ETS, {blocked_user, - {'_',Addr,Port,Dir,'_'}}), + {'_',Addr,Port,Profile, Dir,'_'}}), NewBlocked = lists:foldl(fun({blocked_user, X}, A) -> [X|A] end, Acc, List), - list_blocked(Tables, Addr, Port, Dir, NewBlocked). + list_blocked(Tables, Addr, Port, Profile, Dir, NewBlocked). -%% -%% sync_dets_to_ets/2 -%% %% Reads dets-table DETS and syncronizes it with the ets-table ETS. %% sync_dets_to_ets(DETS, ETS) -> @@ -550,68 +471,62 @@ sync_dets_to_ets(DETS, ETS) -> continue end). -%% -%% check_blocked_user/7 -> true | false -%% %% Check if a specific user is blocked from access. %% %% The sideeffect of this routine is that it unblocks also other users %% whos blocking time has expired. This to keep the tables as small %% as possible. %% -check_blocked_user(Info, User, Dir, Addr, Port, ETS, DETS, CBModule) -> +check_blocked_user(Info, User, Dir, Addr, Port, Profile, ETS, DETS, CBModule) -> TN = universal_time(), - BlockList = ets:match_object(ETS, {blocked_user, {User, '_', '_', '_', '_'}}), + BlockList = ets:match_object(ETS, {blocked_user, {User, '_', '_', '_', '_', '_'}}), Blocked = lists:foldl(fun({blocked_user, X}, A) -> [X|A] end, [], BlockList), check_blocked_user(Info,User,Dir, - Addr,Port,ETS,DETS,TN,Blocked,CBModule). + Addr,Port, Profile, ETS,DETS,TN,Blocked,CBModule). -check_blocked_user(_Info, _User, _Dir, _Addr, _Port, _ETS, _DETS, _TN, - [], _CBModule) -> +check_blocked_user(_Info, _, _, _, _, _, _, _, _,[], _CBModule) -> false; -check_blocked_user(Info, User, Dir, Addr, Port, ETS, DETS, TN, - [{User,Addr,Port,Dir,T}| _], CBModule) -> +check_blocked_user(Info, User, Dir, Addr, Port, Profile, ETS, DETS, TN, + [{User,Addr,Port,Profile, Dir,T}| _], CBModule) -> TD = T-TN, if TD =< 0 -> %% Blocking has expired, remove and grant access. - unblock_user(Info, User, Dir, Addr, Port, ETS, DETS, CBModule), + unblock_user(Info, User, Dir, Addr, Port, Profile, ETS, DETS, CBModule), false; true -> true end; -check_blocked_user(Info, User, Dir, Addr, Port, ETS, DETS, TN, - [{OUser,ODir,OAddr,OPort,T}|Ls], CBModule) -> +check_blocked_user(Info, User, Dir, Addr, Port, Profile, ETS, DETS, TN, + [{OUser,ODir,OAddr,OPort, OProfile, T}|Ls], CBModule) -> TD = T-TN, if TD =< 0 -> %% Blocking has expired, remove. - unblock_user(Info, OUser, ODir, OAddr, OPort, + unblock_user(Info, OUser, ODir, OAddr, OPort, OProfile, ETS, DETS, CBModule); true -> true end, - check_blocked_user(Info, User, Dir, Addr, Port, ETS, DETS, + check_blocked_user(Info, User, Dir, Addr, Port, Profile, ETS, DETS, TN, Ls, CBModule). -unblock_user(Info, User, Dir, Addr, Port, ETS, DETS, CBModule) -> +unblock_user(Info, User, Dir, Addr, Port, Profile, ETS, DETS, CBModule) -> Reason = io_lib:format("User ~s was removed from the block list for dir ~s", [User, Dir]), mod_log:security_log(Info, lists:flatten(Reason)), user_unblock_event(CBModule,Addr,Port,Dir,User), - dets:match_delete(DETS, {blocked_user, {User, Addr, Port, Dir, '_'}}), - ets:match_delete(ETS, {blocked_user, {User, Addr, Port, Dir, '_'}}). + dets:match_delete(DETS, {blocked_user, {User, Addr, Port, Profile, Dir, '_'}}), + ets:match_delete(ETS, {blocked_user, {User, Addr, Port, Profile, Dir, '_'}}). +make_name(Addr,Port, Profile) -> + httpd_util:make_name(?MODULE,Addr,Port, Profile). -make_name(Addr,Port) -> - httpd_util:make_name("httpd_security",Addr,Port). - -make_name(Addr,Port,Num) -> - httpd_util:make_name("httpd_security",Addr,Port, - "__" ++ integer_to_list(Num)). - +make_name(Addr,Port, Profile, Num) -> + httpd_util:make_name(?MODULE,Addr,Port, + atom_to_list(Profile) ++ "__" ++ integer_to_list(Num)). auth_fail_event(Mod,Addr,Port,Dir,User,Passwd) -> event(auth_fail,Mod,Addr,Port,Dir,[{user,User},{password,Passwd}]). @@ -623,17 +538,10 @@ user_unblock_event(Mod,Addr,Port,Dir,User) -> event(user_unblock,Mod,Addr,Port,Dir,[{user,User}]). event(Event, Mod, undefined, Port, Dir, Info) -> - ?hdrt("event", - [{event, Event}, {mod, Mod}, {port, Port}, {dir, Dir}]), (catch Mod:event(Event,Port,Dir,Info)); event(Event, Mod, any, Port, Dir, Info) -> - ?hdrt("event", - [{event, Event}, {mod, Mod}, {port, Port}, {dir, Dir}]), (catch Mod:event(Event,Port,Dir,Info)); event(Event, Mod, Addr, Port, Dir, Info) -> - ?hdrt("event", - [{event, Event}, {mod, Mod}, - {addr, Addr}, {port, Port}, {dir, Dir}]), (catch Mod:event(Event,Addr,Port,Dir,Info)). universal_time() -> @@ -643,11 +551,9 @@ local_time(T) -> calendar:universal_time_to_local_time( calendar:gregorian_seconds_to_datetime(T)). - error_msg(F, A) -> error_logger:error_msg(F, A). - call(Name, Req) -> case (catch gen_server:call(Name, Req)) of {'EXIT', Reason} -> @@ -656,7 +562,6 @@ call(Name, Req) -> Reply end. - cast(Name, Msg) -> case (catch gen_server:cast(Name, Msg)) of {'EXIT', Reason} -> diff --git a/lib/inets/src/inets_app/inets.app.src b/lib/inets/src/inets_app/inets.app.src index b7c3e341e8..6ba9795d9e 100644 --- a/lib/inets/src/inets_app/inets.app.src +++ b/lib/inets/src/inets_app/inets.app.src @@ -63,6 +63,7 @@ httpd_cgi, httpd_connection_sup, httpd_conf, + httpd_custom, httpd_esi, httpd_example, httpd_file, diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 0dfc65e8f7..ab7ffadf75 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -1289,7 +1289,9 @@ dummy_server_init(Caller, ip_comm, Inet, _) -> {max_header, ?HTTP_MAX_HEADER_SIZE}, {max_version,?HTTP_MAX_VERSION_STRING}, {max_method, ?HTTP_MAX_METHOD_STRING}, - {max_content_length, ?HTTP_MAX_CONTENT_LENGTH}]]}, + {max_content_length, ?HTTP_MAX_CONTENT_LENGTH}, + {customize, httpd_custom} + ]]}, [], ListenSocket); dummy_server_init(Caller, ssl, Inet, SSLOptions) -> @@ -1305,7 +1307,8 @@ dummy_ssl_server_init(Caller, BaseOpts, Inet) -> {max_method, ?HTTP_MAX_METHOD_STRING}, {max_version,?HTTP_MAX_VERSION_STRING}, {max_method, ?HTTP_MAX_METHOD_STRING}, - {max_content_length, ?HTTP_MAX_CONTENT_LENGTH} + {max_content_length, ?HTTP_MAX_CONTENT_LENGTH}, + {customize, httpd_custom} ]]}, [], ListenSocket). @@ -1384,18 +1387,20 @@ handle_request(Module, Function, Args, Socket) -> stop; <<>> -> {httpd_request, parse, [[{max_uri,?HTTP_MAX_URI_SIZE}, - {max_header, ?HTTP_MAX_HEADER_SIZE}, - {max_version,?HTTP_MAX_VERSION_STRING}, - {max_method, ?HTTP_MAX_METHOD_STRING}, - {max_content_length, ?HTTP_MAX_CONTENT_LENGTH} - ]]}; + {max_header, ?HTTP_MAX_HEADER_SIZE}, + {max_version,?HTTP_MAX_VERSION_STRING}, + {max_method, ?HTTP_MAX_METHOD_STRING}, + {max_content_length, ?HTTP_MAX_CONTENT_LENGTH}, + {customize, httpd_custom} + ]]}; Data -> handle_request(httpd_request, parse, [Data, [{max_uri, ?HTTP_MAX_URI_SIZE}, - {max_header, ?HTTP_MAX_HEADER_SIZE}, + {max_header, ?HTTP_MAX_HEADER_SIZE}, {max_version,?HTTP_MAX_VERSION_STRING}, {max_method, ?HTTP_MAX_METHOD_STRING}, - {max_content_length, ?HTTP_MAX_CONTENT_LENGTH} + {max_content_length, ?HTTP_MAX_CONTENT_LENGTH}, + {customize, httpd_custom} ]], Socket) end; NewMFA -> diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl index 7670c2cc60..c90887bcf3 100644 --- a/lib/inets/test/httpd_SUITE.erl +++ b/lib/inets/test/httpd_SUITE.erl @@ -53,6 +53,8 @@ all() -> {group, https_basic}, {group, http_limit}, {group, https_limit}, + {group, http_custom}, + {group, https_custom}, {group, http_basic_auth}, {group, https_basic_auth}, {group, http_auth_api}, @@ -76,6 +78,8 @@ groups() -> {https_basic, [], basic_groups()}, {http_limit, [], [{group, limit}]}, {https_limit, [], [{group, limit}]}, + {http_custom, [], [{group, custom}]}, + {https_custom, [], [{group, custom}]}, {http_basic_auth, [], [{group, basic_auth}]}, {https_basic_auth, [], [{group, basic_auth}]}, {http_auth_api, [], [{group, auth_api}]}, @@ -92,6 +96,7 @@ groups() -> {https_reload, [], [{group, reload}]}, {http_mime_types, [], [alias_1_1, alias_1_0, alias_0_9]}, {limit, [], [max_clients_1_1, max_clients_1_0, max_clients_0_9]}, + {custom, [], [customize]}, {reload, [], [non_disturbing_reconfiger_dies, disturbing_reconfiger_dies, non_disturbing_1_1, @@ -178,6 +183,7 @@ end_per_suite(_Config) -> %%-------------------------------------------------------------------- init_per_group(Group, Config0) when Group == https_basic; Group == https_limit; + Group == https_custom; Group == https_basic_auth; Group == https_auth_api; Group == https_auth_api_dets; @@ -188,6 +194,7 @@ init_per_group(Group, Config0) when Group == https_basic; init_ssl(Group, Config0); init_per_group(Group, Config0) when Group == http_basic; Group == http_limit; + Group == http_custom; Group == http_basic_auth; Group == http_auth_api; Group == http_auth_api_dets; @@ -977,6 +984,30 @@ missing_CR(Config) -> {version, Version}]). %%------------------------------------------------------------------------- +customize() -> + [{doc, "Test filtering of headers with custom callback"}]. + +customize(Config) when is_list(Config) -> + Version = "HTTP/1.1", + Host = ?config(host, Config), + Type = ?config(type, Config), + ok = httpd_test_lib:verify_request(?config(type, Config), Host, + ?config(port, Config), + transport_opts(Type, Config), + ?config(node, Config), + http_request("GET /index.html ", Version, Host), + [{statuscode, 200}, + {header, "Content-Type", "text/html"}, + {header, "Date"}, + {no_header, "Server"}, + {version, Version}]). + +response_header({"server", _}) -> + false; +response_header(Header) -> + {true, Header}. + +%%------------------------------------------------------------------------- max_header() -> ["Denial Of Service (DOS) attack, prevented by max_header"]. max_header(Config) when is_list(Config) -> @@ -1320,24 +1351,26 @@ setup_server_dirs(ServerRoot, DocRoot, DataDir) -> start_apps(Group) when Group == https_basic; Group == https_limit; + Group == https_custom; Group == https_basic_auth; Group == https_auth_api; Group == https_auth_api_dets; Group == https_auth_api_mnesia; - Group == http_htaccess; - Group == http_security; - Group == http_reload + Group == https_htaccess; + Group == https_security; + Group == https_reload -> inets_test_lib:start_apps([inets, asn1, crypto, public_key, ssl]); start_apps(Group) when Group == http_basic; Group == http_limit; + Group == http_custom; Group == http_basic_auth; Group == http_auth_api; Group == http_auth_api_dets; Group == http_auth_api_mnesia; - Group == https_htaccess; - Group == https_security; - Group == https_reload; + Group == http_htaccess; + Group == http_security; + Group == http_reload; Group == http_mime_types-> inets_test_lib:start_apps([inets]). @@ -1390,6 +1423,10 @@ server_config(http_limit, Config) -> [{max_clients, 1}, %% Make sure option checking code is run {max_content_length, 100000002}] ++ server_config(http, Config); +server_config(http_custom, Config) -> + [{custom, ?MODULE}] ++ server_config(http, Config); +server_config(https_custom, Config) -> + [{custom, ?MODULE}] ++ server_config(https, Config); server_config(https_limit, Config) -> [{max_clients, 1}] ++ server_config(https, Config); server_config(http_basic_auth, Config) -> diff --git a/lib/inets/test/httpd_block.erl b/lib/inets/test/httpd_block.erl index 9790623b6f..a95a5ee62d 100644 --- a/lib/inets/test/httpd_block.erl +++ b/lib/inets/test/httpd_block.erl @@ -292,7 +292,7 @@ httpd_restart(Addr, Port) -> end. make_name(Addr, Port) -> - httpd_util:make_name("httpd", Addr, Port). + httpd_util:make_name("httpd", Addr, Port, default). get_admin_state(_, _Host, Port) -> Name = make_name(undefined, Port), diff --git a/lib/inets/test/inets_sup_SUITE.erl b/lib/inets/test/inets_sup_SUITE.erl index 60979278fc..1479681e30 100644 --- a/lib/inets/test/inets_sup_SUITE.erl +++ b/lib/inets/test/inets_sup_SUITE.erl @@ -22,14 +22,14 @@ -include_lib("common_test/include/ct.hrl"). - %% Note: This directive should only be used in test suites. -compile(export_all). suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [default_tree, ftpc_worker, tftpd_worker, httpd_subtree, + [default_tree, ftpc_worker, tftpd_worker, + httpd_subtree, httpd_subtree_profile, httpc_subtree]. groups() -> @@ -41,54 +41,29 @@ init_per_group(_GroupName, Config) -> end_per_group(_GroupName, Config) -> Config. - -%%-------------------------------------------------------------------- -%% Function: init_per_suite(Config) -> Config -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Description: Initiation before the whole suite -%% -%% Note: This function is free to add any key/value pairs to the Config -%% variable, but should NOT alter/remove any existing entries. -%%-------------------------------------------------------------------- init_per_suite(Config) -> Config. -%%-------------------------------------------------------------------- -%% Function: end_per_suite(Config) -> _ -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Description: Cleanup after the whole suite -%%-------------------------------------------------------------------- end_per_suite(_) -> inets:stop(), ok. -%%-------------------------------------------------------------------- -%% Function: init_per_testcase(Case, Config) -> Config -%% Case - atom() -%% Name of the test case that is about to be run. -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% -%% Description: Initiation before each test case -%% -%% Note: This function is free to add any key/value pairs to the Config -%% variable, but should NOT alter/remove any existing entries. -%%-------------------------------------------------------------------- init_per_testcase(httpd_subtree, Config) -> Dog = test_server:timetrap(?t:minutes(1)), NewConfig = lists:keydelete(watchdog, 1, Config), PrivDir = ?config(priv_dir, Config), - + Dir = filename:join(PrivDir, "root"), + ok = file:make_dir(Dir), + SimpleConfig = [{port, 0}, {server_name,"www.test"}, {modules, [mod_get]}, - {server_root, PrivDir}, - {document_root, PrivDir}, + {server_root, Dir}, + {document_root, Dir}, {bind_address, any}, {ipfamily, inet}], try + inets:stop(), inets:start(), inets:start(httpd, SimpleConfig), [{watchdog, Dog} | NewConfig] @@ -97,7 +72,33 @@ init_per_testcase(httpd_subtree, Config) -> inets:stop(), exit({failed_starting_inets, Reason}) end; - + +init_per_testcase(httpd_subtree_profile, Config) -> + Dog = test_server:timetrap(?t:minutes(1)), + NewConfig = lists:keydelete(watchdog, 1, Config), + PrivDir = ?config(priv_dir, Config), + Dir = filename:join(PrivDir, "root"), + ok = file:make_dir(Dir), + + SimpleConfig = [{port, 0}, + {server_name,"www.test"}, + {modules, [mod_get]}, + {server_root, Dir}, + {document_root, Dir}, + {bind_address, any}, + {profile, test_profile}, + {ipfamily, inet}], + try + inets:stop(), + inets:start(), + {ok, _} = inets:start(httpd, SimpleConfig), + [{watchdog, Dog} | NewConfig] + catch + _:Reason -> + inets:stop(), + exit({failed_starting_inets, Reason}) + end; + init_per_testcase(_Case, Config) -> Dog = test_server:timetrap(?t:minutes(5)), @@ -106,20 +107,13 @@ init_per_testcase(_Case, Config) -> ok = inets:start(), [{watchdog, Dog} | NewConfig]. - -%%-------------------------------------------------------------------- -%% Function: end_per_testcase(Case, Config) -> _ -%% Case - atom() -%% Name of the test case that is about to be run. -%% Config - [tuple()] -%% A list of key/value pairs, holding the test case configuration. -%% Description: Cleanup after each test case -%%-------------------------------------------------------------------- -end_per_testcase(httpd_subtree, Config) -> +end_per_testcase(Case, Config) when Case == httpd_subtree; + Case == httpd_subtree_profile -> Dog = ?config(watchdog, Config), test_server:timetrap_cancel(Dog), - PrivDir = ?config(priv_dir, Config), - inets_test_lib:del_dirs(PrivDir), + PrivDir = ?config(priv_dir, Config), + Dir = filename:join(PrivDir, "root"), + inets_test_lib:del_dirs(Dir), ok; end_per_testcase(_, Config) -> @@ -131,16 +125,9 @@ end_per_testcase(_, Config) -> %%------------------------------------------------------------------------- %% Test cases starts here. %%------------------------------------------------------------------------- - - -%%------------------------------------------------------------------------- -%% default_tree -%%------------------------------------------------------------------------- -default_tree(doc) -> - ["Makes sure the correct processes are started and linked," - "in the default case."]; -default_tree(suite) -> - []; +default_tree() -> + [{doc, "Makes sure the correct processes are started and linked," + "in the default case."}]. default_tree(Config) when is_list(Config) -> TopSupChildren = supervisor:which_children(inets_sup), 4 = length(TopSupChildren), @@ -173,15 +160,9 @@ default_tree(Config) when is_list(Config) -> ok. - -%%------------------------------------------------------------------------- -%% ftpc_worker -%%------------------------------------------------------------------------- -ftpc_worker(doc) -> - ["Makes sure the ftp worker processes are added and removed " - "appropriatly to/from the supervison tree."]; -ftpc_worker(suite) -> - []; +ftpc_worker() -> + [{doc, "Makes sure the ftp worker processes are added and removed " + "appropriatly to/from the supervison tree."}]. ftpc_worker(Config) when is_list(Config) -> [] = supervisor:which_children(ftp_sup), try @@ -207,14 +188,8 @@ ftpc_worker(Config) when is_list(Config) -> {skip, "No available FTP servers"} end. - -%%------------------------------------------------------------------------- -%% tftpd_worker -%%------------------------------------------------------------------------- -tftpd_worker(doc) -> - ["Makes sure the tftp sub tree is correct."]; -tftpd_worker(suite) -> - []; +tftpd_worker() -> + [{doc, "Makes sure the tftp sub tree is correct."}]. tftpd_worker(Config) when is_list(Config) -> [] = supervisor:which_children(tftp_sup), {ok, Pid0} = inets:start(tftpd, [{host, inets_test_lib:hostname()}, @@ -228,22 +203,63 @@ tftpd_worker(Config) when is_list(Config) -> [] = supervisor:which_children(tftp_sup), ok. +httpd_subtree() -> + [{doc, "Makes sure the httpd sub tree is correct."}]. +httpd_subtree(Config) when is_list(Config) -> + do_httpd_subtree(Config, default). + +httpd_subtree_profile(doc) -> + ["Makes sure the httpd sub tree is correct when using a profile"]; +httpd_subtree_profile(Config) when is_list(Config) -> + do_httpd_subtree(Config, test_profile). + +httpc_subtree() -> + [{doc, "Makes sure the httpd sub tree is correct."}]. +httpc_subtree(Config) when is_list(Config) -> + {ok, Foo} = inets:start(httpc, [{profile, foo}]), + + {ok, Bar} = inets:start(httpc, [{profile, bar}], stand_alone), + + HttpcChildren = supervisor:which_children(httpc_profile_sup), + + {value, {httpc_manager, _, worker, [httpc_manager]}} = + lists:keysearch(httpc_manager, 1, HttpcChildren), + + {value,{{httpc,foo}, _Pid, worker, [httpc_manager]}} = + lists:keysearch({httpc, foo}, 1, HttpcChildren), + false = lists:keysearch({httpc, bar}, 1, HttpcChildren), + + inets:stop(httpc, Foo), + exit(Bar, normal). %%------------------------------------------------------------------------- -%% httpd_subtree +%% Internal functions %%------------------------------------------------------------------------- -httpd_subtree(doc) -> - ["Makes sure the httpd sub tree is correct."]; -httpd_subtree(suite) -> - []; -httpd_subtree(Config) when is_list(Config) -> - %% Check that we have the httpd top supervisor + +verify_child(Parent, Child, Type) -> + Children = supervisor:which_children(Parent), + verify_child(Children, Parent, Child, Type). + +verify_child([], Parent, Child, _Type) -> + {error, {child_not_found, Child, Parent}}; +verify_child([{Id, _Pid, Type2, Mods}|Children], Parent, Child, Type) -> + case lists:member(Child, Mods) of + true when (Type2 =:= Type) -> + {ok, Id}; + true when (Type2 =/= Type) -> + {error, {wrong_type, Type2, Child, Parent}}; + false -> + verify_child(Children, Parent, Child, Type) + end. + +do_httpd_subtree(_Config, Profile) -> + %% Check that we have the httpd top supervisor {ok, _} = verify_child(inets_sup, httpd_sup, supervisor), %% Check that we have the httpd instance supervisor {ok, Id} = verify_child(httpd_sup, httpd_instance_sup, supervisor), - {httpd_instance_sup, Addr, Port} = Id, - Instance = httpd_util:make_name("httpd_instance_sup", Addr, Port), + {httpd_instance_sup, Addr, Port, Profile} = Id, + Instance = httpd_util:make_name("httpd_instance_sup", Addr, Port, Profile), %% Check that we have the expected httpd instance children {ok, _} = verify_child(Instance, httpd_connection_sup, supervisor), @@ -252,7 +268,7 @@ httpd_subtree(Config) when is_list(Config) -> {ok, _} = verify_child(Instance, httpd_manager, worker), %% Check that the httpd instance acc supervisor has children - InstanceAcc = httpd_util:make_name("httpd_acceptor_sup", Addr, Port), + InstanceAcc = httpd_util:make_name("httpd_acceptor_sup", Addr, Port, Profile), case supervisor:which_children(InstanceAcc) of [_ | _] -> ok; @@ -263,7 +279,7 @@ httpd_subtree(Config) when is_list(Config) -> %% Check that the httpd instance misc supervisor has no children io:format("httpd_subtree -> verify misc~n", []), - InstanceMisc = httpd_util:make_name("httpd_misc_sup", Addr, Port), + InstanceMisc = httpd_util:make_name("httpd_misc_sup", Addr, Port, Profile), case supervisor:which_children(InstanceMisc) of [] -> ok; @@ -273,45 +289,3 @@ httpd_subtree(Config) when is_list(Config) -> end, io:format("httpd_subtree -> done~n", []), ok. - - -verify_child(Parent, Child, Type) -> - Children = supervisor:which_children(Parent), - verify_child(Children, Parent, Child, Type). - -verify_child([], Parent, Child, _Type) -> - {error, {child_not_found, Child, Parent}}; -verify_child([{Id, _Pid, Type2, Mods}|Children], Parent, Child, Type) -> - case lists:member(Child, Mods) of - true when (Type2 =:= Type) -> - {ok, Id}; - true when (Type2 =/= Type) -> - {error, {wrong_type, Type2, Child, Parent}}; - false -> - verify_child(Children, Parent, Child, Type) - end. - -%%------------------------------------------------------------------------- -%% httpc_subtree -%%------------------------------------------------------------------------- -httpc_subtree(doc) -> - ["Makes sure the httpc sub tree is correct."]; -httpc_subtree(suite) -> - []; -httpc_subtree(Config) when is_list(Config) -> - {ok, Foo} = inets:start(httpc, [{profile, foo}]), - - {ok, Bar} = inets:start(httpc, [{profile, bar}], stand_alone), - - HttpcChildren = supervisor:which_children(httpc_profile_sup), - - {value, {httpc_manager, _, worker, [httpc_manager]}} = - lists:keysearch(httpc_manager, 1, HttpcChildren), - - {value,{{httpc,foo}, _Pid, worker, [httpc_manager]}} = - lists:keysearch({httpc, foo}, 1, HttpcChildren), - false = lists:keysearch({httpc, bar}, 1, HttpcChildren), - - inets:stop(httpc, Foo), - exit(Bar, normal). - |