aboutsummaryrefslogtreecommitdiffstats
path: root/lib/inets
diff options
context:
space:
mode:
Diffstat (limited to 'lib/inets')
-rw-r--r--lib/inets/doc/src/http_uri.xml5
-rw-r--r--lib/inets/doc/src/httpd.xml10
-rw-r--r--lib/inets/doc/src/notes.xml22
-rw-r--r--lib/inets/src/http_server/httpd_conf.erl15
-rw-r--r--lib/inets/src/http_server/httpd_request_handler.erl62
-rw-r--r--lib/inets/src/inets_app/Makefile4
-rw-r--r--lib/inets/src/inets_app/inets.appup.src14
-rw-r--r--lib/inets/test/erl_make_certs.erl4
-rw-r--r--lib/inets/test/ftp_suite_lib.erl1
-rw-r--r--lib/inets/test/httpc_SUITE.erl2
-rw-r--r--lib/inets/test/httpc_cookie_SUITE.erl3
-rw-r--r--lib/inets/test/httpd_SUITE.erl18
-rw-r--r--lib/inets/test/httpd_basic_SUITE.erl16
-rw-r--r--lib/inets/test/inets_SUITE.erl7
-rw-r--r--lib/inets/test/inets_app_test.erl18
-rw-r--r--lib/inets/test/inets_sup_SUITE.erl6
-rw-r--r--lib/inets/vsn.mk2
17 files changed, 140 insertions, 69 deletions
diff --git a/lib/inets/doc/src/http_uri.xml b/lib/inets/doc/src/http_uri.xml
index bd31ae42d2..d9e8587bbf 100644
--- a/lib/inets/doc/src/http_uri.xml
+++ b/lib/inets/doc/src/http_uri.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2012</year><year>2012</year>
+ <year>2012</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -55,7 +55,8 @@ string() = list of ASCII characters
<p>For more information about URI, see RFC 3986. </p>
<code type="none"><![CDATA[
-uri() = string() - Syntax according to the URI definition in rfc 3986, ex: "http://www.erlang.org/"
+uri() = string() - Syntax according to the URI definition in rfc 3986,
+ e.g.: "http://www.erlang.org/"
user_info() = string()
scheme() = atom() - Example: http, https
host() = string()
diff --git a/lib/inets/doc/src/httpd.xml b/lib/inets/doc/src/httpd.xml
index 7e21229fcf..3fced5dfcd 100644
--- a/lib/inets/doc/src/httpd.xml
+++ b/lib/inets/doc/src/httpd.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2011</year>
+ <year>1997</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -178,7 +178,13 @@
<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>
+ <p>If given, sets a minimum bytes per second value for connections.</p>
+ <p>If the value is not reached, the socket will close for that connection.</p>
+ <p>The option is good for reducing the risk of "slow dos" attacks.</p>
+ </item>
</taglist>
<marker id="props_api_modules"></marker>
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index 3aae1ff70a..e0d6ae3454 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -33,7 +33,27 @@
</header>
- <section>
+ <section><title>Inets 5.9.2</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Minimum bytes per second</p>
+ <p>
+ New option to http server, {minimum_bytes_per_second,
+ integer()}, for a connection, if it is not reached the
+ socket will close for that specific connection. Can be
+ used to prevent hanging requests from faulty clients.</p>
+ <p>
+ Own Id: OTP-10392</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section>
<title>Inets 5.9.1</title>
<section>
diff --git a/lib/inets/src/http_server/httpd_conf.erl b/lib/inets/src/http_server/httpd_conf.erl
index 747118431e..a97bbd9b25 100644
--- a/lib/inets/src/http_server/httpd_conf.erl
+++ b/lib/inets/src/http_server/httpd_conf.erl
@@ -483,7 +483,7 @@ validate_properties(Properties) ->
case mandatory_properties(Properties) of
ok ->
%% Second, check that property dependency are ok
- {ok, validate_properties2(Properties)};
+ {ok, check_minimum_bytes_per_second(validate_properties2(Properties))};
Error ->
throw(Error)
end.
@@ -522,7 +522,18 @@ validate_properties2(Properties) ->
throw(Error)
end
end.
-
+check_minimum_bytes_per_second(Properties) ->
+ case proplists:get_value(minimum_bytes_per_second, Properties, false) of
+ false ->
+ Properties;
+ Nr ->
+ case is_integer(Nr) of
+ false ->
+ throw({error, {minimum_bytes_per_second, is_not_integer}});
+ _ ->
+ Properties
+ end
+ end.
mandatory_properties(ConfigList) ->
a_must(ConfigList, [server_name, port, server_root, document_root]).
diff --git a/lib/inets/src/http_server/httpd_request_handler.erl b/lib/inets/src/http_server/httpd_request_handler.erl
index b62c10bbc7..0f47d785ef 100644
--- a/lib/inets/src/http_server/httpd_request_handler.erl
+++ b/lib/inets/src/http_server/httpd_request_handler.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
@@ -44,7 +44,9 @@
timeout, %% infinity | integer() > 0
timer, %% ref() - Request timer
headers, %% #http_request_h{}
- body %% binary()
+ body, %% binary()
+ data, %% The total data received in bits, checked after 10s
+ byte_limit %% Bit limit per second before kick out
}).
%%====================================================================
@@ -98,7 +100,6 @@ init([Manager, ConfigDB, AcceptTimeout]) ->
[{socket_type, SocketType}, {socket, Socket}]),
TimeOut = httpd_util:lookup(ConfigDB, keep_alive_timeout, 150000),
-
Then = erlang:now(),
?hdrd("negotiate", []),
@@ -139,12 +140,11 @@ continue_init(Manager, ConfigDB, SocketType, Socket, TimeOut) ->
mfa = MFA},
?hdrt("activate request timeout", []),
- NewState = activate_request_timeout(State),
?hdrt("set socket options (binary, packet & active)", []),
http_transport:setopts(SocketType, Socket,
[binary, {packet, 0}, {active, once}]),
-
+ NewState = data_receive_counter(activate_request_timeout(State), httpd_util:lookup(ConfigDB, minimum_bytes_per_second, false)),
?hdrt("init done", []),
gen_server:enter_loop(?MODULE, [], NewState).
@@ -205,16 +205,25 @@ handle_info({Proto, Socket, Data},
?hdrd("received data",
[{data, Data}, {proto, Proto},
{socket, Socket}, {socket_type, SockType}, {mfa, MFA}]),
-
+
%% case (catch Module:Function([Data | Args])) of
PROCESSED = (catch Module:Function([Data | Args])),
-
+ NewDataSize = case State#state.byte_limit of
+ undefined ->
+ undefined;
+ _ ->
+ State#state.data + byte_size(Data)
+ end,
?hdrt("data processed", [{processing_result, PROCESSED}]),
-
case PROCESSED of
{ok, Result} ->
?hdrd("data processed", [{result, Result}]),
- NewState = cancel_request_timeout(State),
+ NewState = case NewDataSize of
+ undefined ->
+ cancel_request_timeout(State);
+ _ ->
+ set_new_data_size(cancel_request_timeout(State), NewDataSize)
+ end,
handle_http_msg(Result, NewState);
{error, {uri_too_long, MaxSize}, Version} ->
@@ -239,7 +248,12 @@ handle_info({Proto, Socket, Data},
NewMFA ->
?hdrd("data processed - reactivate socket", [{new_mfa, NewMFA}]),
http_transport:setopts(SockType, Socket, [{active, once}]),
- {noreply, State#state{mfa = NewMFA}}
+ case NewDataSize of
+ undefined ->
+ {noreply, State#state{mfa = NewMFA}};
+ _ ->
+ {noreply, State#state{mfa = NewMFA, data = NewDataSize}}
+ end
end;
%% Error cases
@@ -263,7 +277,22 @@ handle_info(timeout, #state{mod = ModData} = State) ->
error_log("The client did not send the whole request before the "
"server side timeout", ModData),
{stop, normal, State#state{response_sent = true}};
-
+handle_info(check_data_first, #state{data = Data, byte_limit = Byte_Limit} = State) ->
+ case Data >= (Byte_Limit*3) of
+ true ->
+ erlang:send_after(1000, self(), check_data),
+ {noreply, State#state{data = 0}};
+ _ ->
+ {stop, normal, State#state{response_sent = true}}
+ end;
+handle_info(check_data, #state{data = Data, byte_limit = Byte_Limit} = State) ->
+ case Data >= Byte_Limit of
+ true ->
+ erlang:send_after(1000, self(), check_data),
+ {noreply, State#state{data = 0}};
+ _ ->
+ {stop, normal, State#state{response_sent = true}}
+ end;
%% Default case
handle_info(Info, #state{mod = ModData} = State) ->
Error = lists:flatten(
@@ -311,6 +340,8 @@ code_change(_OldVsn, State, _Extra) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+set_new_data_size(State, NewData) ->
+ State#state{data = NewData}.
await_socket_ownership_transfer(AcceptTimeout) ->
receive
{socket_ownership_transfered, SocketType, Socket} ->
@@ -603,7 +634,14 @@ activate_request_timeout(#state{timeout = Time} = State) ->
?hdrt("activate request timeout", [{time, Time}]),
Ref = erlang:send_after(Time, self(), timeout),
State#state{timer = Ref}.
-
+data_receive_counter(State, Byte_limit) ->
+ case Byte_limit of
+ false ->
+ State#state{data = 0};
+ Nr ->
+ erlang:send_after(3000, self(), check_data_first),
+ State#state{data = 0, byte_limit = Nr}
+ end.
cancel_request_timeout(#state{timer = undefined} = State) ->
State;
cancel_request_timeout(#state{timer = Timer} = State) ->
diff --git a/lib/inets/src/inets_app/Makefile b/lib/inets/src/inets_app/Makefile
index 7d68145287..22426eee79 100644
--- a/lib/inets/src/inets_app/Makefile
+++ b/lib/inets/src/inets_app/Makefile
@@ -99,10 +99,10 @@ docs:
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index 2adb2a0fc8..ffd0ed622f 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -18,8 +18,14 @@
{"%VSN%",
[
+ {"5.9.1",
+ [
+ {load_module, httpd_request_handler, soft_purge, soft_purge, []}
+ ]
+ },
{"5.9",
[
+ {load_module, httpd_request_handler, soft_purge, soft_purge, []},
{load_module, tftp, soft_purge, soft_purge, [inets_service]},
{load_module, inets_service, soft_purge, soft_purge, []},
{load_module, httpc, soft_purge, soft_purge, [httpc_manager]},
@@ -29,6 +35,7 @@
},
{"5.8.1",
[
+ {load_module, httpd_request_handler, soft_purge, soft_purge, []},
{load_module, tftp, soft_purge, soft_purge, [inets_service]},
{load_module, inets_service, soft_purge, soft_purge, []},
@@ -64,8 +71,14 @@
}
],
[
+ {"5.9.1",
+ [
+ {load_module, httpd_request_handler, soft_purge, soft_purge, []}
+ ]
+ },
{"5.9",
[
+ {load_module, httpd_request_handler, soft_purge, soft_purge, []},
{load_module, tftp, soft_purge, soft_purge, [inets_service]},
{load_module, inets_service, soft_purge, soft_purge, []},
{load_module, httpc, soft_purge, soft_purge, [httpc_manager]},
@@ -75,6 +88,7 @@
},
{"5.8.1",
[
+ {load_module, httpd_request_handler, soft_purge, soft_purge, []},
{load_module, tftp, soft_purge, soft_purge, [inets_service]},
{load_module, inets_service, soft_purge, soft_purge, []},
diff --git a/lib/inets/test/erl_make_certs.erl b/lib/inets/test/erl_make_certs.erl
index 254aa6d2f9..d6bdd05d01 100644
--- a/lib/inets/test/erl_make_certs.erl
+++ b/lib/inets/test/erl_make_certs.erl
@@ -137,10 +137,10 @@ decode_key(PemBin, Pw) ->
encode_key(Key = #'RSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('RSAPrivateKey', Key),
- {'RSAPrivateKey', list_to_binary(Der), not_encrypted};
+ {'RSAPrivateKey', Der, not_encrypted};
encode_key(Key = #'DSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key),
- {'DSAPrivateKey', list_to_binary(Der), not_encrypted}.
+ {'DSAPrivateKey', Der, not_encrypted}.
make_tbs(SubjectKey, Opts) ->
Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))),
diff --git a/lib/inets/test/ftp_suite_lib.erl b/lib/inets/test/ftp_suite_lib.erl
index ffb58c91b6..211c9b5bee 100644
--- a/lib/inets/test/ftp_suite_lib.erl
+++ b/lib/inets/test/ftp_suite_lib.erl
@@ -206,7 +206,6 @@ init_per_testcase(Case, Config)
init_per_testcase(Case, Config) ->
put(ftp_testcase, Case),
- inets:enable_trace(max, io, ftpc),
do_init_per_testcase(Case, Config).
do_init_per_testcase(Case, Config)
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index cb81d2cc5e..644b01120c 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -337,7 +337,6 @@ init_per_testcase(Case, Timeout, Config) ->
%% so this value will be overwritten (see "ipv6_" below).
%% </IPv6>
- inets:enable_trace(max, io, httpc),
%% inets:enable_trace(max, io, all),
%% snmp:set_trace([gen_tcp]),
tsp("init_per_testcase(~w) -> done when"
@@ -381,7 +380,6 @@ end_per_testcase(http_save_to_file = Case, Config) ->
end_per_testcase(Case, Config) ->
io:format(user, "~n~n*** END ~w:~w ***~n~n",
[?MODULE, Case]),
- dbg:stop(), % ?
case atom_to_list(Case) of
"ipv6_" ++ _Rest ->
tsp("end_per_testcase(~w) -> stop ssl", [Case]),
diff --git a/lib/inets/test/httpc_cookie_SUITE.erl b/lib/inets/test/httpc_cookie_SUITE.erl
index 93dbc270c5..3862bf7a20 100644
--- a/lib/inets/test/httpc_cookie_SUITE.erl
+++ b/lib/inets/test/httpc_cookie_SUITE.erl
@@ -276,8 +276,6 @@ secure_cookie(Config) when is_list(Config) ->
tsp("secure_cookie -> entry with"
"~n Config: ~p", [Config]),
- inets:enable_trace(max, io, httpc),
-
%% httpc:reset_cookies(),
tsp("secure_cookie -> Cookies 1: ~p", [httpc:which_cookies()]),
@@ -309,7 +307,6 @@ secure_cookie(Config) when is_list(Config) ->
tsp("secure_cookie -> Cookies 4: ~p", [httpc:which_cookies()]),
- inets:disable_trace(),
tsp("secure_cookie -> done"),
ok.
diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl
index 58f7d4fa25..592469a12f 100644
--- a/lib/inets/test/httpd_SUITE.erl
+++ b/lib/inets/test/httpd_SUITE.erl
@@ -530,24 +530,10 @@ init_per_testcase3(Case, Config) ->
application:stop(inets),
application:stop(ssl),
cleanup_mnesia(),
-
- %% Set trace level
- case lists:reverse(atom_to_list(Case)) of
- "tset_emit" ++ _Rest -> % test-cases ending with time_test
- tsp("init_per_testcase3(~w) -> disabling trace", [Case]),
- inets:disable_trace();
- _ ->
- tsp("init_per_testcase3(~w) -> enabling trace", [Case]),
- %% TraceLevel = 70,
- TraceLevel = max,
- TraceDest = io,
- inets:enable_trace(TraceLevel, TraceDest, httpd)
- end,
-
+
%% Start initialization
tsp("init_per_testcase3(~w) -> start init", [Case]),
-
-
+
Dog = test_server:timetrap(inets_test_lib:minutes(10)),
NewConfig = lists:keydelete(watchdog, 1, Config),
TcTopDir = ?config(tc_top_dir, Config),
diff --git a/lib/inets/test/httpd_basic_SUITE.erl b/lib/inets/test/httpd_basic_SUITE.erl
index 7a476ea14a..523cf9d38c 100644
--- a/lib/inets/test/httpd_basic_SUITE.erl
+++ b/lib/inets/test/httpd_basic_SUITE.erl
@@ -34,7 +34,8 @@ all() ->
[
uri_too_long_414,
header_too_long_413,
- escaped_url_in_error_body
+ escaped_url_in_error_body,
+ slowdose
].
groups() ->
@@ -278,7 +279,18 @@ escaped_url_in_error_body(Config) when is_list(Config) ->
inets:stop(httpd, Pid),
tsp("escaped_url_in_error_body -> done"),
ok.
-
+slowdose(doc) ->
+ ["Testing minimum bytes per second option"];
+slowdose(Config) when is_list(Config) ->
+ HttpdConf = ?config(httpd_conf, Config),
+ {ok, Pid} = inets:start(httpd, [{port, 0}, {minimum_bytes_per_second, 200}|HttpdConf]),
+ Info = httpd:info(Pid),
+ Port = proplists:get_value(port, Info),
+ {ok, Socket} = gen_tcp:connect("localhost", Port, []),
+ receive
+ after 6000 ->
+ {error, closed} = gen_tcp:send(Socket, "Hey")
+ end.
find_URL_path([]) ->
"";
find_URL_path(["URL", URL | _]) ->
diff --git a/lib/inets/test/inets_SUITE.erl b/lib/inets/test/inets_SUITE.erl
index 6fa0f44d77..069c68fa1e 100644
--- a/lib/inets/test/inets_SUITE.erl
+++ b/lib/inets/test/inets_SUITE.erl
@@ -363,8 +363,6 @@ start_ftpc(suite) ->
[];
start_ftpc(Config) when is_list(Config) ->
process_flag(trap_exit, true),
- inets:disable_trace(),
- inets:enable_trace(max, io, ftpc),
ok = inets:start(),
try
begin
@@ -393,16 +391,13 @@ start_ftpc(Config) when is_list(Config) ->
tsf(stand_alone_not_shutdown)
end,
ok = inets:stop(),
- inets:disable_trace(),
ok;
_ ->
- inets:disable_trace(),
{skip, "Unable to reach selected FTP server " ++ FtpdHost}
end
end
catch
throw:{error, not_found} ->
- inets:disable_trace(),
{skip, "No available FTP servers"}
end.
@@ -462,8 +457,6 @@ httpd_reload(Config) when is_list(Config) ->
{document_root, PrivDir},
{bind_address, "localhost"}],
- inets:enable_trace(max, io),
-
i("httpd_reload -> start inets"),
ok = inets:start(),
diff --git a/lib/inets/test/inets_app_test.erl b/lib/inets/test/inets_app_test.erl
index db2218f3b6..eabfa69f7c 100644
--- a/lib/inets/test/inets_app_test.erl
+++ b/lib/inets/test/inets_app_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2002-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
@@ -35,6 +35,15 @@
init_per_testcase(undef_funcs, Config) ->
NewConfig = lists:keydelete(watchdog, 1, Config),
Dog = test_server:timetrap(inets_test_lib:minutes(10)),
+
+ %% We need to check if there is a point to run this test.
+ %% On some platforms, crypto will not build, which in turn
+ %% causes ssl to not build (at this time, this will
+ %% change in the future).
+ %% So, we first check if we can start crypto, and if not,
+ %% we skip this test case!
+ ?ENSURE_STARTED(crypto),
+
[{watchdog, Dog}| NewConfig];
init_per_testcase(_, Config) ->
Config.
@@ -240,13 +249,6 @@ undef_funcs(suite) ->
undef_funcs(doc) ->
[];
undef_funcs(Config) when is_list(Config) ->
- %% We need to check if there is a point to run this test.
- %% On some platforms, crypto will not build, which in turn
- %% causes ssl to not build (at this time, this will
- %% change in the future).
- %% So, we first check if we can start crypto, and if not,
- %% we skip this test case!
- ?ENSURE_STARTED(crypto),
App = inets,
AppFile = key1search(app_file, Config),
Mods = key1search(modules, AppFile),
diff --git a/lib/inets/test/inets_sup_SUITE.erl b/lib/inets/test/inets_sup_SUITE.erl
index 1d262a2739..65f0f0e09a 100644
--- a/lib/inets/test/inets_sup_SUITE.erl
+++ b/lib/inets/test/inets_sup_SUITE.erl
@@ -226,8 +226,6 @@ ftpc_worker(doc) ->
ftpc_worker(suite) ->
[];
ftpc_worker(Config) when is_list(Config) ->
- inets:disable_trace(),
- inets:enable_trace(max, io, ftpc),
[] = supervisor:which_children(ftp_sup),
try
begin
@@ -239,20 +237,16 @@ ftpc_worker(Config) when is_list(Config) ->
inets:stop(ftpc, Pid),
test_server:sleep(5000),
[] = supervisor:which_children(ftp_sup),
- inets:disable_trace(),
ok;
Children ->
- inets:disable_trace(),
exit({unexpected_children, Children})
end;
_ ->
- inets:disable_trace(),
{skip, "Unable to reach test FTP server"}
end
end
catch
throw:{error, not_found} ->
- inets:disable_trace(),
{skip, "No available FTP servers"}
end.
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index 949eceea7f..0c7cb5e7c2 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -18,7 +18,7 @@
# %CopyrightEnd%
APPLICATION = inets
-INETS_VSN = 5.9.1
+INETS_VSN = 5.9.2
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"