aboutsummaryrefslogtreecommitdiffstats
path: root/lib/inets/src/http_server
diff options
context:
space:
mode:
Diffstat (limited to 'lib/inets/src/http_server')
-rw-r--r--lib/inets/src/http_server/Makefile2
-rw-r--r--lib/inets/src/http_server/httpd_conf.erl110
-rw-r--r--lib/inets/src/http_server/httpd_response.erl27
-rw-r--r--lib/inets/src/http_server/httpd_script_env.erl57
-rw-r--r--lib/inets/src/http_server/httpd_sup.erl19
-rw-r--r--lib/inets/src/http_server/mod_get.erl16
6 files changed, 191 insertions, 40 deletions
diff --git a/lib/inets/src/http_server/Makefile b/lib/inets/src/http_server/Makefile
index 55cc68dede..c341a2cec7 100644
--- a/lib/inets/src/http_server/Makefile
+++ b/lib/inets/src/http_server/Makefile
@@ -88,6 +88,8 @@ ERL_FILES = $(MODULES:%=%.erl)
TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"'
+
# ----------------------------------------------------
# FLAGS
diff --git a/lib/inets/src/http_server/httpd_conf.erl b/lib/inets/src/http_server/httpd_conf.erl
index 7646300409..b575d7331b 100644
--- a/lib/inets/src/http_server/httpd_conf.erl
+++ b/lib/inets/src/http_server/httpd_conf.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2012. 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
@@ -210,12 +210,32 @@ load("MaxBodySize " ++ MaxBodySize, []) ->
{ok, Integer} ->
{ok, [], {max_body_size,Integer}};
{error, _} ->
- {error, ?NICE(clean(MaxBodySize)++
+ {error, ?NICE(clean(MaxBodySize) ++
" is an invalid number of MaxBodySize")}
end;
load("ServerName " ++ ServerName, []) ->
- {ok,[],{server_name,clean(ServerName)}};
+ {ok,[], {server_name, clean(ServerName)}};
+
+load("ServerTokens " ++ ServerTokens, []) ->
+ %% These are the valid *plain* server tokens:
+ %% sprod, major, minor, minimum, os, full
+ %% It can also be a "private" server token: private:<any string>
+ case string:tokens(ServerTokens, [$:]) of
+ ["private", Private] ->
+ {ok,[], {server_tokens, clean(Private)}};
+ [TokStr] ->
+ Tok = list_to_atom(clean(TokStr)),
+ case lists:member(Tok, [prod, major, minor, minimum, os, full]) of
+ true ->
+ {ok,[], {server_tokens, Tok}};
+ false ->
+ {error, ?NICE(clean(ServerTokens) ++
+ " is an invalid ServerTokens")}
+ end;
+ _ ->
+ {error, ?NICE(clean(ServerTokens) ++ " is an invalid ServerTokens")}
+ end;
load("SocketType " ++ SocketType, []) ->
%% ssl is the same as HTTP_DEFAULT_SSL_KIND
@@ -475,7 +495,7 @@ validate_properties(Properties) ->
validate_properties2(Properties) ->
case proplists:get_value(bind_address, Properties) of
undefined ->
- case proplists:get_value(sock_type, Properties, ip_comm) of
+ case proplists:get_value(sock_type, Properties, ip_comm) of
ip_comm ->
case proplists:get_value(ipfamily, Properties) of
undefined ->
@@ -537,6 +557,20 @@ validate_config_params([{server_name, Value} | Rest])
validate_config_params([{server_name, Value} | _]) ->
throw({server_name, Value});
+validate_config_params([{server_tokens, Value} | Rest])
+ when is_atom(Value) ->
+ case lists:member(Value, plain_server_tokens()) of
+ true ->
+ validate_config_params(Rest);
+ false ->
+ throw({server_tokens, Value})
+ end;
+validate_config_params([{server_tokens, {private, Value}} | Rest])
+ when is_list(Value) ->
+ validate_config_params(Rest);
+validate_config_params([{server_tokens, Value} | _]) ->
+ throw({server_tokens, Value});
+
validate_config_params([{socket_type, Value} | Rest])
when (Value =:= ip_comm) orelse
(Value =:= ssl) orelse
@@ -737,9 +771,73 @@ store({log_format, LogFormat}, _ConfigList)
store({log_format, LogFormat}, _ConfigList)
when (LogFormat =:= compact) orelse (LogFormat =:= pretty) ->
{ok, {log_format, LogFormat}};
+store({server_tokens, ServerTokens} = Entry, _ConfigList) ->
+ Server = server(ServerTokens),
+ {ok, [Entry, {server, Server}]};
store(ConfigListEntry, _ConfigList) ->
{ok, ConfigListEntry}.
+
+%% The SERVER_SOFTWARE macro has the following structure:
+%% <product>/<version>
+%% Example: "inets/1.2.3"
+%% So, with this example (on a linux machine, with OTP R15B),
+%% this will result in:
+%% prod: "inets"
+%% major: "inets/1"
+%% minor: "inets/1.2"
+%% minimal: "inets/1.2.3"
+%% os: "inets/1.2.3 (unix)
+%% full: "inets/1.2.3 (unix/linux) OTP/R15B"
+%% Note that the format of SERVER_SOFTWARE is that of 'minimal'.
+%% Also, there will always be atleast two digits in a version:
+%% Not just 1 but 1.0
+%%
+%% We have already checked that the value is valid,
+%% so there is no need to check enything here.
+%%
+server(prod = _ServerTokens) ->
+ [Prod|_Version] = string:tokens(?SERVER_SOFTWARE, [$/]),
+ Prod;
+server(major = _ServerTokens) ->
+ [Prod|Version] = string:tokens(?SERVER_SOFTWARE, [$/]),
+ [Major|_] = string:tokens(Version, [$.]),
+ Prod ++ "/" ++ Major;
+server(minor = _ServerTokens) ->
+ [Prod|Version] = string:tokens(?SERVER_SOFTWARE, [$/]),
+ [Major,Minor|_] = string:tokens(Version, [$.]),
+ Prod ++ "/" ++ Major ++ "." ++ Minor;
+server(minimal = _ServerTokens) ->
+ %% This is the default
+ ?SERVER_SOFTWARE;
+server(os = _ServerTokens) ->
+ OS = os_info(partial),
+ lists:flatten(io_lib:format("~s ~s", [?SERVER_SOFTWARE, OS]));
+server(full = _ServerTokens) ->
+ OTPRelease = otp_release(),
+ OS = os_info(full),
+ lists:flatten(
+ io_lib:format("~s ~s OTP/~s", [?SERVER_SOFTWARE, OS, OTPRelease]));
+server({private, Server} = _ServerTokens) when is_list(Server) ->
+ %% The user provide its own
+ Server;
+server(_) ->
+ ?SERVER_SOFTWARE.
+
+os_info(Info) ->
+ case os:type() of
+ {OsFamily, _OsName} when Info =:= partial ->
+ lists:flatten(io_lib:format("(~w)", [OsFamily]));
+ {OsFamily, OsName} ->
+ lists:flatten(io_lib:format("(~w/~w)", [OsFamily, OsName]));
+ OsFamily ->
+ lists:flatten(io_lib:format("(~w)", [OsFamily]))
+ end.
+
+otp_release() ->
+ erlang:system_info(otp_release).
+
+
%% Phase 3: Remove
remove_all(ConfigDB) ->
Modules = httpd_util:lookup(ConfigDB,modules,[]),
@@ -1159,6 +1257,10 @@ ssl_ca_certificate_file(ConfigDB) ->
[{cacertfile, File}]
end.
+plain_server_tokens() ->
+ [prod, major, minor, minimum, os, full].
+
error_report(Where,M,F,Error) ->
error_logger:error_report([{?MODULE, Where},
{apply, {M, F, []}}, Error]).
+
diff --git a/lib/inets/src/http_server/httpd_response.erl b/lib/inets/src/http_server/httpd_response.erl
index dd7223876e..2dedb088e4 100644
--- a/lib/inets/src/http_server/httpd_response.erl
+++ b/lib/inets/src/http_server/httpd_response.erl
@@ -144,10 +144,14 @@ send_response(ModData, Header, Body) ->
end
end.
-send_header(#mod{socket_type = Type, socket = Sock,
- http_version = Ver, connection = Conn} = _ModData,
+send_header(#mod{socket_type = Type,
+ socket = Sock,
+ http_version = Ver,
+ connection = Conn,
+ config_db = ConfigDb} = _ModData,
StatusCode, KeyValueTupleHeaders) ->
- Headers = create_header(lists:map(fun transform/1, KeyValueTupleHeaders)),
+ Headers = create_header(ConfigDb,
+ lists:map(fun transform/1, KeyValueTupleHeaders)),
NewVer = case {Ver, StatusCode} of
{[], _} ->
%% May be implicit!
@@ -275,13 +279,20 @@ cache_headers(#mod{config_db = Db}) ->
[]
end.
-create_header(KeyValueTupleHeaders) ->
- NewHeaders = add_default_headers([{"date", httpd_util:rfc1123_date()},
- {"content-type", "text/html"},
- {"server", ?SERVER_SOFTWARE}],
- KeyValueTupleHeaders),
+create_header(ConfigDb, KeyValueTupleHeaders) ->
+ Date = httpd_util:rfc1123_date(),
+ ContentType = "text/html",
+ Server = server(ConfigDb),
+ NewHeaders = add_default_headers([{"date", Date},
+ {"content-type", ContentType},
+ {"server", Server}],
+ KeyValueTupleHeaders),
lists:map(fun fix_header/1, NewHeaders).
+
+server(ConfigDb) ->
+ httpd_util:lookup(ConfigDb, server, ?SERVER_SOFTWARE).
+
fix_header({Key0, Value}) ->
%% make sure first letter is capital
Words1 = string:tokens(Key0, "-"),
diff --git a/lib/inets/src/http_server/httpd_script_env.erl b/lib/inets/src/http_server/httpd_script_env.erl
index d3115150b0..a5613ba4a4 100644
--- a/lib/inets/src/http_server/httpd_script_env.erl
+++ b/lib/inets/src/http_server/httpd_script_env.erl
@@ -50,29 +50,44 @@ create_env(ScriptType, ModData, ScriptElements) ->
%%%========================================================================
%%% Internal functions
%%%========================================================================
+
+which_server(#mod{config_db = ConfigDb}) ->
+ httpd_util:lookup(ConfigDb, server, ?SERVER_SOFTWARE).
+
+which_port(#mod{config_db = ConfigDb}) ->
+ httpd_util:lookup(ConfigDb, port, 80).
+
+which_peername(#mod{init_data = #init_data{peername = {_, RemoteAddr}}}) ->
+ RemoteAddr.
+
+which_resolve(#mod{init_data = #init_data{resolve = Resolve}}) ->
+ Resolve.
+
+which_method(#mod{method = Method}) ->
+ Method.
+
+which_request_uri(#mod{request_uri = RUri}) ->
+ RUri.
+
create_basic_elements(esi, ModData) ->
- {_, RemoteAddr} = (ModData#mod.init_data)#init_data.peername,
- [{server_software, ?SERVER_SOFTWARE},
- {server_name, (ModData#mod.init_data)#init_data.resolve},
- {gateway_interface,?GATEWAY_INTERFACE},
- {server_protocol, ?SERVER_PROTOCOL},
- {server_port, httpd_util:lookup(ModData#mod.config_db,port,80)},
- {request_method, ModData#mod.method},
- {remote_addr, RemoteAddr},
- {script_name, ModData#mod.request_uri}];
+ [{server_software, which_server(ModData)},
+ {server_name, which_resolve(ModData)},
+ {gateway_interface, ?GATEWAY_INTERFACE},
+ {server_protocol, ?SERVER_PROTOCOL},
+ {server_port, which_port(ModData)},
+ {request_method, which_method(ModData)},
+ {remote_addr, which_peername(ModData)},
+ {script_name, which_request_uri(ModData)}];
create_basic_elements(cgi, ModData) ->
- {_, RemoteAddr} = (ModData#mod.init_data)#init_data.peername,
- [{"SERVER_SOFTWARE",?SERVER_SOFTWARE},
- {"SERVER_NAME", (ModData#mod.init_data)#init_data.resolve},
- {"GATEWAY_INTERFACE",?GATEWAY_INTERFACE},
- {"SERVER_PROTOCOL",?SERVER_PROTOCOL},
- {"SERVER_PORT",
- integer_to_list(httpd_util:lookup(
- ModData#mod.config_db, port, 80))},
- {"REQUEST_METHOD", ModData#mod.method},
- {"REMOTE_ADDR", RemoteAddr},
- {"SCRIPT_NAME", ModData#mod.request_uri}].
+ [{"SERVER_SOFTWARE", which_server(ModData)},
+ {"SERVER_NAME", which_resolve(ModData)},
+ {"GATEWAY_INTERFACE", ?GATEWAY_INTERFACE},
+ {"SERVER_PROTOCOL", ?SERVER_PROTOCOL},
+ {"SERVER_PORT", integer_to_list(which_port(ModData))},
+ {"REQUEST_METHOD", which_method(ModData)},
+ {"REMOTE_ADDR", which_peername(ModData)},
+ {"SCRIPT_NAME", which_request_uri(ModData)}].
create_http_header_elements(ScriptType, Headers) ->
create_http_header_elements(ScriptType, Headers, []).
@@ -80,7 +95,7 @@ create_http_header_elements(ScriptType, Headers) ->
create_http_header_elements(_, [], Acc) ->
Acc;
create_http_header_elements(ScriptType, [{Name, [Value | _] = Values } |
- Headers], Acc)
+ Headers], Acc)
when is_list(Value) ->
NewName = lists:map(fun(X) -> if X == $- -> $_; true -> X end end, Name),
Element = http_env_element(ScriptType, NewName, multi_value(Values)),
diff --git a/lib/inets/src/http_server/httpd_sup.erl b/lib/inets/src/http_server/httpd_sup.erl
index 264dc9f006..8f3e8f9500 100644
--- a/lib/inets/src/http_server/httpd_sup.erl
+++ b/lib/inets/src/http_server/httpd_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2012. 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
@@ -162,17 +162,30 @@ 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);
-httpd_child_spec(ConfigFile, AcceptTimeout, Debug) ->
+%% 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),
+ 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);
Error ->
@@ -183,7 +196,7 @@ httpd_child_spec(ConfigFile, AcceptTimeout, Debug) ->
end.
httpd_child_spec(Config, AcceptTimeout, Debug, Addr, Port) ->
- case Port == 0 orelse proplists:is_defined(fd, Config) of
+ case (Port =:= 0) orelse proplists:is_defined(fd, Config) of
true ->
httpd_child_spec_listen(Config, AcceptTimeout, Debug, Addr, Port);
false ->
diff --git a/lib/inets/src/http_server/mod_get.erl b/lib/inets/src/http_server/mod_get.erl
index 5cb30e3d97..c58d1f3508 100644
--- a/lib/inets/src/http_server/mod_get.erl
+++ b/lib/inets/src/http_server/mod_get.erl
@@ -18,9 +18,16 @@
%%
%%
-module(mod_get).
+
-export([do/1]).
+
-include("httpd.hrl").
-include("httpd_internal.hrl").
+-include("inets_internal.hrl").
+
+-define(VMODULE,"GET").
+
+
%% do
do(Info) ->
@@ -84,15 +91,16 @@ send_response(_Socket, _SocketType, Path, Info)->
file:close(FileDescriptor),
{proceed,[{response,{already_sent,200,
FileInfo#file_info.size}},
- {mime_type,MimeType}|Info#mod.data]};
+ {mime_type,MimeType} | Info#mod.data]};
{error, Reason} ->
+ ?hdrt("send_response -> failed open file",
+ [{path, Path}, {reason, Reason}]),
Status = httpd_file:handle_error(Reason, "open", Info, Path),
- {proceed,
- [{status, Status}| Info#mod.data]}
+ {proceed, [{status, Status} | Info#mod.data]}
end.
%% send
-
+
send(#mod{socket = Socket, socket_type = SocketType} = Info,
StatusCode, Headers, FileDescriptor) ->
?DEBUG("send -> send header",[]),