aboutsummaryrefslogtreecommitdiffstats
path: root/lib/inets/src/http_server/httpd.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/inets/src/http_server/httpd.erl')
-rw-r--r--lib/inets/src/http_server/httpd.erl600
1 files changed, 600 insertions, 0 deletions
diff --git a/lib/inets/src/http_server/httpd.erl b/lib/inets/src/http_server/httpd.erl
new file mode 100644
index 0000000000..554f162fc5
--- /dev/null
+++ b/lib/inets/src/http_server/httpd.erl
@@ -0,0 +1,600 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-2009. 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).
+
+-behaviour(inets_service).
+
+-include("httpd.hrl").
+
+-deprecated({start, 0, next_major_release}).
+-deprecated({start, 1, next_major_release}).
+-deprecated({start_link, 1, next_major_release}).
+-deprecated({start_child, 0, next_major_release}).
+-deprecated({start_child, 1, next_major_release}).
+-deprecated({stop, 0, next_major_release}).
+-deprecated({stop, 1, next_major_release}).
+-deprecated({stop, 2, next_major_release}).
+-deprecated({stop_child, 0, next_major_release}).
+-deprecated({stop_child, 1, next_major_release}).
+-deprecated({stop_child, 2, next_major_release}).
+-deprecated({restart, 0, next_major_release}).
+-deprecated({restart, 1, next_major_release}).
+-deprecated({restart, 2, next_major_release}).
+-deprecated({block, 0, next_major_release}).
+-deprecated({block, 1, next_major_release}).
+-deprecated({block, 2, next_major_release}).
+-deprecated({block, 3, next_major_release}).
+-deprecated({block, 4, next_major_release}).
+-deprecated({unblock, 0, next_major_release}).
+-deprecated({unblock, 1, next_major_release}).
+-deprecated({unblock, 2, next_major_release}).
+
+%% Behavior callbacks
+-export([start_standalone/1, start_service/1, stop_service/1, services/0,
+ service_info/1]).
+
+%% API
+-export([parse_query/1, reload_config/2, info/1, info/2, info/3]).
+
+%% Deprecated
+-export([start/0, start/1,
+ start_link/0, start_link/1,
+ start_child/0,start_child/1,
+ stop/0,stop/1,stop/2,
+ stop_child/0,stop_child/1,stop_child/2,
+ restart/0,restart/1,restart/2]).
+
+%% Management stuff should be internal functions
+%% Will be from r13
+-export([block/0,block/1,block/2,block/3,block/4,
+ unblock/0,unblock/1,unblock/2]).
+
+%% Internal Debugging and status info stuff...
+%% Keep for now should probably be moved to test catalog
+-export([get_status/1,get_status/2,get_status/3,
+ get_admin_state/0,get_admin_state/1,get_admin_state/2,
+ get_usage_state/0,get_usage_state/1,get_usage_state/2]).
+
+%%%========================================================================
+%%% API
+%%%========================================================================
+
+parse_query(String) ->
+ {ok, SplitString} = inets_regexp:split(String,"[&;]"),
+ foreach(SplitString).
+
+reload_config(Config = [Value| _], Mode) when is_tuple(Value) ->
+ do_reload_config(Config, Mode);
+reload_config(ConfigFile, Mode) ->
+ case httpd_conf:load(ConfigFile) of
+ {ok, ConfigList} ->
+ do_reload_config(ConfigList, Mode);
+ Error ->
+ Error
+ end.
+
+info(Pid) when is_pid(Pid) ->
+ info(Pid, []).
+
+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),
+ case Properties of
+ [] ->
+ info(Address, Port);
+ _ ->
+ info(Address, Port, Properties)
+ end;
+info(Address, Port) when is_integer(Port) ->
+ httpd_conf:get_config(Address, Port).
+
+info(Address, Port, Properties) when is_integer(Port) andalso
+ is_list(Properties) ->
+ httpd_conf:get_config(Address, Port, Properties).
+
+%%%========================================================================
+%%% Behavior callbacks
+%%%========================================================================
+
+start_standalone(Config) ->
+ httpd_sup:start_link([{httpd, Config}], stand_alone).
+
+start_service(Conf) ->
+ httpd_sup:start_child(Conf).
+
+stop_service({Address, Port}) ->
+ httpd_sup:stop_child(Address, Port);
+
+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});
+ Error ->
+ Error
+ end.
+
+services() ->
+ [{httpd, ChildPid} || {_, ChildPid, _, _} <-
+ supervisor:which_children(httpd_sup)].
+
+service_info(Pid) ->
+ try
+ [{ChildName, ChildPid} ||
+ {ChildName, ChildPid, _, _} <-
+ supervisor:which_children(httpd_sup)] of
+ Children ->
+ child_name2info(child_name(Pid, Children))
+ catch
+ exit:{noproc, _} ->
+ {error, service_not_available}
+ end.
+%%%--------------------------------------------------------------
+%%% Internal functions
+%%%--------------------------------------------------------------------
+
+child_name(_, []) ->
+ undefined;
+child_name(Pid, [{Name, Pid} | _]) ->
+ Name;
+child_name(Pid, [_ | Children]) ->
+ child_name(Pid, Children).
+
+child_name2info(undefined) ->
+ {error, no_such_service};
+child_name2info({httpd_instance_sup, any, Port}) ->
+ {ok, Host} = inet:gethostname(),
+ Info = info(any, Port, [server_name]),
+ {ok, [{bind_address, any}, {host, Host}, {port, Port} | Info]};
+child_name2info({httpd_instance_sup, Address, Port}) ->
+ Info = info(Address, Port, [server_name]),
+ case inet:gethostbyaddr(Address) of
+ {ok, {_, Host, _, _,_, _}} ->
+ {ok, [{bind_address, Address},
+ {host, Host}, {port, Port} | Info]};
+ _ ->
+ {ok, [{bind_address, Address}, {port, Port} | Info]}
+ end.
+
+reload(Config, Address, Port) ->
+ Name = make_name(Address,Port),
+ case whereis(Name) of
+ Pid when is_pid(Pid) ->
+ httpd_manager:reload(Pid, Config);
+ _ ->
+ {error,not_started}
+ end.
+
+reload(Addr, Port) when is_integer(Port) ->
+ Name = make_name(Addr,Port),
+ case whereis(Name) of
+ Pid when is_pid(Pid) ->
+ httpd_manager:reload(Pid, undefined);
+ _ ->
+ {error,not_started}
+ end.
+
+%%% =========================================================
+%%% Function: block/0, block/1, block/2, block/3, block/4
+%%% block()
+%%% block(Port)
+%%% block(ConfigFile)
+%%% block(Addr,Port)
+%%% block(Port,Mode)
+%%% block(ConfigFile,Mode)
+%%% block(Addr,Port,Mode)
+%%% block(ConfigFile,Mode,Timeout)
+%%% block(Addr,Port,Mode,Timeout)
+%%%
+%%% Returns: ok | {error,Reason}
+%%%
+%%% Description: This function is used to block an HTTP server.
+%%% The blocking can be done in two ways,
+%%% disturbing or non-disturbing. Default is disturbing.
+%%% When a HTTP server is blocked, all requests are rejected
+%%% (status code 503).
+%%%
+%%% disturbing:
+%%% By performing a disturbing block, the server
+%%% is blocked forcefully and all ongoing requests
+%%% are terminated. No new connections are accepted.
+%%% If a timeout time is given then, on-going requests
+%%% are given this much time to complete before the
+%%% server is forcefully blocked. In this case no new
+%%% connections is accepted.
+%%%
+%%% non-disturbing:
+%%% A non-disturbing block is more gracefull. No
+%%% new connections are accepted, but the ongoing
+%%% requests are allowed to complete.
+%%% If a timeout time is given, it waits this long before
+%%% giving up (the block operation is aborted and the
+%%% server state is once more not-blocked).
+%%%
+%%% Types: Port -> integer()
+%%% Addr -> {A,B,C,D} | string() | undefined
+%%% ConfigFile -> string()
+%%% Mode -> disturbing | non_disturbing
+%%% Timeout -> integer()
+%%%
+block() -> block(undefined,8888,disturbing).
+
+block(Port) when is_integer(Port) ->
+ block(undefined,Port,disturbing);
+
+block(ConfigFile) when is_list(ConfigFile) ->
+ case get_addr_and_port(ConfigFile) of
+ {ok,Addr,Port} ->
+ block(Addr,Port,disturbing);
+ Error ->
+ Error
+ end.
+
+block(Addr,Port) when is_integer(Port) ->
+ block(Addr,Port,disturbing);
+
+block(Port,Mode) when is_integer(Port) andalso is_atom(Mode) ->
+ block(undefined,Port,Mode);
+
+block(ConfigFile,Mode) when is_list(ConfigFile) andalso is_atom(Mode) ->
+ case get_addr_and_port(ConfigFile) of
+ {ok,Addr,Port} ->
+ block(Addr,Port,Mode);
+ Error ->
+ Error
+ end.
+
+
+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),
+ case whereis(Name) of
+ Pid when is_pid(Pid) ->
+ 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/0, unblock/1, unblock/2
+%%% unblock()
+%%% unblock(Port)
+%%% unblock(ConfigFile)
+%%% unblock(Addr,Port)
+%%%
+%%% Description: This function is used to reverse a previous block
+%%% operation on the HTTP server.
+%%%
+%%% Types: Port -> integer()
+%%% Addr -> {A,B,C,D} | string() | undefined
+%%% ConfigFile -> string()
+%%%
+unblock() -> unblock(undefined,8888).
+unblock(Port) when is_integer(Port) -> unblock(undefined,Port);
+
+unblock(ConfigFile) when is_list(ConfigFile) ->
+ case get_addr_and_port(ConfigFile) of
+ {ok,Addr,Port} ->
+ unblock(Addr,Port);
+ Error ->
+ Error
+ end.
+
+unblock(Addr, Port) when is_integer(Port) ->
+ Name = make_name(Addr,Port),
+ case whereis(Name) of
+ Pid when is_pid(Pid) ->
+ httpd_manager:unblock(Pid);
+ _ ->
+ {error,not_started}
+ end.
+
+foreach([]) ->
+ [];
+foreach([KeyValue|Rest]) ->
+ {ok, Plus2Space, _} = inets_regexp:gsub(KeyValue,"[\+]"," "),
+ case inets_regexp:split(Plus2Space,"=") of
+ {ok,[Key|Value]} ->
+ [{httpd_util:decode_hex(Key),
+ httpd_util:decode_hex(lists:flatten(Value))}|foreach(Rest)];
+ {ok,_} ->
+ foreach(Rest)
+ end.
+
+get_addr_and_port(ConfigFile) ->
+ case httpd_conf:load(ConfigFile) of
+ {ok, ConfigList} ->
+ case 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).
+
+
+%%%--------------------------------------------------------------
+%%% Internal debug functions - Do we want these functions here!?
+%%%--------------------------------------------------------------------
+
+%%% =========================================================
+%%% Function: get_admin_state/0, get_admin_state/1, get_admin_state/2
+%%% get_admin_state()
+%%% get_admin_state(Port)
+%%% get_admin_state(Addr,Port)
+%%%
+%%% Returns: {ok,State} | {error,Reason}
+%%%
+%%% Description: This function is used to retrieve the administrative
+%%% state of the HTTP server.
+%%%
+%%% Types: Port -> integer()
+%%% Addr -> {A,B,C,D} | string() | undefined
+%%% State -> unblocked | shutting_down | blocked
+%%% Reason -> term()
+%%%
+get_admin_state() -> get_admin_state(undefined,8888).
+get_admin_state(Port) when is_integer(Port) -> get_admin_state(undefined,Port);
+
+get_admin_state(ConfigFile) when is_list(ConfigFile) ->
+ case get_addr_and_port(ConfigFile) of
+ {ok,Addr,Port} ->
+ unblock(Addr,Port);
+ Error ->
+ Error
+ end.
+
+get_admin_state(Addr,Port) when is_integer(Port) ->
+ Name = make_name(Addr,Port),
+ case whereis(Name) of
+ Pid when is_pid(Pid) ->
+ httpd_manager:get_admin_state(Pid);
+ _ ->
+ {error,not_started}
+ end.
+
+
+
+%%% =========================================================
+%%% Function: get_usage_state/0, get_usage_state/1, get_usage_state/2
+%%% get_usage_state()
+%%% get_usage_state(Port)
+%%% get_usage_state(Addr,Port)
+%%%
+%%% Returns: {ok,State} | {error,Reason}
+%%%
+%%% Description: This function is used to retrieve the usage
+%%% state of the HTTP server.
+%%%
+%%% Types: Port -> integer()
+%%% Addr -> {A,B,C,D} | string() | undefined
+%%% State -> idle | active | busy
+%%% Reason -> term()
+%%%
+get_usage_state() -> get_usage_state(undefined,8888).
+get_usage_state(Port) when is_integer(Port) -> get_usage_state(undefined,Port);
+
+get_usage_state(ConfigFile) when is_list(ConfigFile) ->
+ case get_addr_and_port(ConfigFile) of
+ {ok,Addr,Port} ->
+ unblock(Addr,Port);
+ Error ->
+ Error
+ end.
+
+get_usage_state(Addr,Port) when is_integer(Port) ->
+ Name = make_name(Addr,Port),
+ case whereis(Name) of
+ Pid when is_pid(Pid) ->
+ httpd_manager:get_usage_state(Pid);
+ _ ->
+ {error,not_started}
+ end.
+
+
+
+%%% =========================================================
+%% Function: get_status(ConfigFile) -> Status
+%% get_status(Port) -> Status
+%% get_status(Addr,Port) -> Status
+%% get_status(Port,Timeout) -> Status
+%% get_status(Addr,Port,Timeout) -> Status
+%%
+%% Arguments: ConfigFile -> string()
+%% Configuration file from which Port and
+%% BindAddress will be extracted.
+%% Addr -> {A,B,C,D} | string()
+%% Bind Address of the http server
+%% Port -> integer()
+%% Port number of the http server
+%% Timeout -> integer()
+%% Timeout time for the call
+%%
+%% Returns: Status -> list()
+%%
+%% Description: This function is used when the caller runs in the
+%% same node as the http server or if calling with a
+%% program such as erl_call (see erl_interface).
+%%
+
+get_status(ConfigFile) when is_list(ConfigFile) ->
+ case get_addr_and_port(ConfigFile) of
+ {ok,Addr,Port} ->
+ get_status(Addr,Port);
+ Error ->
+ Error
+ end;
+
+get_status(Port) when is_integer(Port) ->
+ get_status(undefined,Port,5000).
+
+get_status(Port,Timeout) when is_integer(Port) andalso is_integer(Timeout) ->
+ get_status(undefined,Port,Timeout);
+
+get_status(Addr,Port) ->
+ get_status(Addr,Port,5000).
+
+get_status(Addr,Port,Timeout) when is_integer(Port) ->
+ Name = make_name(Addr,Port),
+ case whereis(Name) of
+ Pid when is_pid(Pid) ->
+ httpd_manager:get_status(Pid,Timeout);
+ _ ->
+ not_started
+ end.
+
+do_reload_config(ConfigList, Mode) ->
+ case httpd_conf:validate_properties(ConfigList) of
+ {ok, Config} ->
+ Address = proplists:get_value(bind_address, Config, any),
+ Port = proplists:get_value(port, Config, 80),
+ block(Address, Port, Mode),
+ reload(Config, Address, Port),
+ unblock(Address, Port);
+ Error ->
+ Error
+ end.
+
+
+%%%--------------------------------------------------------------
+%%% Deprecated
+%%%--------------------------------------------------------------
+start() ->
+ start("/var/tmp/server_root/conf/8888.conf").
+
+start(ConfigFile) ->
+ {ok, Pid} = inets:start(httpd, ConfigFile, stand_alone),
+ unlink(Pid),
+ {ok, Pid}.
+
+start_link() ->
+ start("/var/tmp/server_root/conf/8888.conf").
+
+start_link(ConfigFile) when is_list(ConfigFile) ->
+ inets:start(httpd, ConfigFile, stand_alone).
+
+stop() ->
+ stop(8888).
+
+stop(Port) when is_integer(Port) ->
+ stop(undefined, Port);
+stop(Pid) when is_pid(Pid) ->
+ old_stop(Pid);
+stop(ConfigFile) when is_list(ConfigFile) ->
+ old_stop(ConfigFile).
+
+stop(Addr, Port) when is_integer(Port) ->
+ old_stop(Addr, Port).
+
+start_child() ->
+ start_child("/var/tmp/server_root/conf/8888.conf").
+
+start_child(ConfigFile) ->
+ httpd_sup:start_child(ConfigFile).
+
+stop_child() ->
+ stop_child(8888).
+
+stop_child(Port) ->
+ stop_child(undefined, Port).
+
+stop_child(Addr, Port) when is_integer(Port) ->
+ httpd_sup:stop_child(Addr, Port).
+
+restart() -> reload(undefined, 8888).
+
+restart(Port) when is_integer(Port) ->
+ reload(undefined, Port).
+restart(Addr, Port) ->
+ reload(Addr, Port).
+
+old_stop(Pid) when is_pid(Pid) ->
+ do_stop(Pid);
+old_stop(ConfigFile) when is_list(ConfigFile) ->
+ case get_addr_and_port(ConfigFile) of
+ {ok, Addr, Port} ->
+ old_stop(Addr, Port);
+
+ Error ->
+ Error
+ end;
+old_stop(_StartArgs) ->
+ ok.
+
+old_stop(Addr, Port) when is_integer(Port) ->
+ Name = old_make_name(Addr, Port),
+ case whereis(Name) of
+ Pid when is_pid(Pid) ->
+ do_stop(Pid),
+ ok;
+ _ ->
+ not_started
+ end.
+
+do_stop(Pid) ->
+ exit(Pid, shutdown).
+
+old_make_name(Addr,Port) ->
+ httpd_util:make_name("httpd_instance_sup",Addr,Port).