From 4bb5062494e621c7fd73e9264b00dfce596491f8 Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin <ingela@erlang.org>
Date: Thu, 15 May 2014 16:11:49 +0200
Subject: inets: httpd - Reject incorrect large request lines early

---
 lib/inets/src/http_lib/http_internal.hrl           |   4 +-
 lib/inets/src/http_server/httpd_request.erl        | 188 ++++++-------
 .../src/http_server/httpd_request_handler.erl      |  26 +-
 lib/inets/test/httpd_basic_SUITE.erl               | 294 ++++++++-------------
 4 files changed, 208 insertions(+), 304 deletions(-)

(limited to 'lib')

diff --git a/lib/inets/src/http_lib/http_internal.hrl b/lib/inets/src/http_lib/http_internal.hrl
index 97cf474ab9..53b776c4e7 100644
--- a/lib/inets/src/http_lib/http_internal.hrl
+++ b/lib/inets/src/http_lib/http_internal.hrl
@@ -1,7 +1,7 @@
 %%
 %% %CopyrightBegin%
 %%
-%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2014. 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
@@ -26,6 +26,8 @@
 -define(HTTP_MAX_BODY_SIZE,   nolimit).
 -define(HTTP_MAX_HEADER_SIZE, 10240).
 -define(HTTP_MAX_URI_SIZE,    nolimit).
+-define(HTTP_MAX_VERSION_STRING, 8).
+-define(HTTP_MAX_METHOD_STRING, 20).
 
 -ifndef(HTTP_DEFAULT_SSL_KIND).
 -define(HTTP_DEFAULT_SSL_KIND, essl).
diff --git a/lib/inets/src/http_server/httpd_request.erl b/lib/inets/src/http_server/httpd_request.erl
index 5ba79b2706..68e7c16702 100644
--- a/lib/inets/src/http_server/httpd_request.erl
+++ b/lib/inets/src/http_server/httpd_request.erl
@@ -1,7 +1,7 @@
 %%
 %% %CopyrightBegin%
 %%
-%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2014. 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,26 +44,26 @@
 %%%=========================================================================
 parse([Bin, MaxSizes]) ->
     ?hdrt("parse", [{bin, Bin}, {max_sizes, MaxSizes}]),    
-    parse_method(Bin, [], MaxSizes, []);
+    parse_method(Bin, [], 0, proplists:get_value(max_method, MaxSizes), MaxSizes, []);
 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, MaxSizes, Result]) ->
-    parse_method(Bin, Method, MaxSizes, Result).
+parse_method([Bin, Method, Current, Max, MaxSizes, Result]) ->
+    parse_method(Bin, Method, Current, Max, MaxSizes, Result).
 
-parse_uri([Bin, URI, CurrSize, MaxSizes, Result]) ->
-    parse_uri(Bin, URI, CurrSize, MaxSizes, Result).
+parse_uri([Bin, URI, Current, Max, MaxSizes, Result]) ->
+    parse_uri(Bin, URI, Current, Max, MaxSizes, Result).
 
-parse_version([Bin, Rest, Version, MaxSizes, Result]) ->
-    parse_version(<<Rest/binary, Bin/binary>>, Version, MaxSizes, 
+parse_version([Bin, Rest, Version, Current, Max, MaxSizes, Result]) ->
+    parse_version(<<Rest/binary, Bin/binary>>, Version, Current, Max, MaxSizes, 
 		  Result).
 
-parse_headers([Bin, Rest, Header, Headers, CurrSize, MaxSizes, Result]) ->
+parse_headers([Bin, Rest, Header, Headers, Current, Max, MaxSizes, Result]) ->
     parse_headers(<<Rest/binary, Bin/binary>>, 
-		  Header, Headers, CurrSize, MaxSizes, Result).
+		  Header, Headers, Current, Max, MaxSizes, Result).
 
 whole_body([Bin, Body, Length])  ->
     whole_body(<<Body/binary, Bin/binary>>, Length).    
@@ -131,104 +131,75 @@ update_mod_data(ModData, Method, RequestURI, HTTPVersion, Headers)->
 %%%========================================================================
 %%% Internal functions
 %%%========================================================================
-parse_method(<<>>, Method, MaxSizes, Result) ->
-    ?hdrt("parse_method - empty bin", 
-	  [{method, Method}, {max_sizes, MaxSizes}, {result, Result}]),    
-    {?MODULE, parse_method, [Method, MaxSizes, Result]};
-parse_method(<<?SP, Rest/binary>>, Method, MaxSizes, Result) ->
-    ?hdrt("parse_method - SP begin", 
-	  [{rest,      Rest}, 
-	   {method,    Method}, 
-	   {max_sizes, MaxSizes}, 
-	   {result,    Result}]),    
-    parse_uri(Rest, [], 0, MaxSizes,
+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,
 	      [string:strip(lists:reverse(Method)) | Result]);
-parse_method(<<Octet, Rest/binary>>, Method, MaxSizes, Result) ->
-    ?hdrt("parse_method", 
-	  [{octet,     Octet}, 
-	   {rest,      Rest}, 
-	   {method,    Method}, 
-	   {max_sizes, MaxSizes}, 
-	   {result,    Result}]),    
-    parse_method(Rest, [Octet | Method], MaxSizes, Result).
-
-parse_uri(_, _, CurrSize, {MaxURI, _}, _) 
-  when (CurrSize > MaxURI) andalso (MaxURI =/= nolimit) -> 
-    ?hdrt("parse_uri", 
-	  [{current_size, CurrSize}, 
-	   {max_uri,      MaxURI}]),    
+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(_, _, _, 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
+    %% will be able to handle it.
+    {error, {too_long, Max, 413, "Method unreasonably long"}, lowest_version()}.
+
+parse_uri(_, _, Current, MaxURI, _, _) 
+  when (Current > MaxURI) andalso (MaxURI =/= nolimit) -> 
     %% We do not know the version of the client as it comes after the
     %% uri send the lowest version in the response so that the client
     %% will be able to handle it.
-    HttpVersion = "HTTP/0.9", 
-    {error, {uri_too_long, MaxURI}, HttpVersion};
-parse_uri(<<>>, URI, CurrSize, MaxSizes, Result) ->
-    ?hdrt("parse_uri - empty bin", 
-	  [{uri,          URI},
-	   {current_size, CurrSize}, 
-	   {max_sz,       MaxSizes}, 
-	   {result,       Result}]),    
-    {?MODULE, parse_uri, [URI, CurrSize, MaxSizes, Result]};
-parse_uri(<<?SP, Rest/binary>>, URI, _, MaxSizes, Result) -> 
-    ?hdrt("parse_uri - SP begin", 
-	  [{uri,          URI},
-	   {max_sz,       MaxSizes}, 
-	   {result,       Result}]),    
-    parse_version(Rest, [], MaxSizes, 
+    {error, {too_long, 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, 
 		  [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) ->
-    ?hdrt("parse_uri - CR begin", 
-	  [{uri,          URI},
-	   {max_sz,       MaxSizes}, 
-	   {result,       Result}]),    
-    parse_version(Data, [], MaxSizes, 
+parse_uri(<<?CR, _Rest/binary>> = Data, URI, _, _, MaxSizes, Result) ->
+    parse_version(Data, [], 0, proplists:get_value(max_version, MaxSizes), MaxSizes, 
 		  [string:strip(lists:reverse(URI)) | Result]);
-parse_uri(<<Octet, Rest/binary>>, URI, CurrSize, MaxSizes, Result) ->
-    ?hdrt("parse_uri", 
-	  [{octet,        Octet}, 
-	   {uri,          URI},
-	   {curr_sz,      CurrSize}, 
-	   {max_sz,       MaxSizes}, 
-	   {result,       Result}]),    
-    parse_uri(Rest, [Octet | URI], CurrSize + 1, MaxSizes, Result).
-
-parse_version(<<>>, Version, MaxSizes, Result) ->
-    {?MODULE, parse_version, [<<>>, Version, MaxSizes, Result]};
-parse_version(<<?LF, Rest/binary>>, Version, MaxSizes, Result) ->
+parse_uri(<<Octet, Rest/binary>>, URI, Current, Max, MaxSizes, Result) ->
+    parse_uri(Rest, [Octet | URI], Current + 1, Max, MaxSizes, 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) ->
     %% If ?CR is is missing RFC2616 section-19.3 
-    parse_version(<<?CR, ?LF, Rest/binary>>, Version, MaxSizes, Result);
-parse_version(<<?CR, ?LF, Rest/binary>>, Version, MaxSizes, Result) ->
-    parse_headers(Rest, [], [], 0, MaxSizes, 
+    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, 
 		  [string:strip(lists:reverse(Version)) | Result]);
-parse_version(<<?CR>> = Data, Version, MaxSizes, Result) ->
-    {?MODULE, parse_version, [Data, Version, MaxSizes, Result]};
-parse_version(<<Octet, Rest/binary>>, Version, MaxSizes, Result) ->
-    parse_version(Rest, [Octet | Version], MaxSizes, Result).
-
-parse_headers(_, _, _, CurrSize, {_, MaxHeaderSize}, Result) 
-  when CurrSize > MaxHeaderSize, MaxHeaderSize =/= nolimit -> 
+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(_, _, _, Max,_,_) ->
+    {error, {too_long, Max, 413, "Version string unreasonably long"}, lowest_version()}.
+
+parse_headers(_, _, _, Current, Max, _, Result) 
+  when Max =/= nolimit andalso Current > Max -> 
     HttpVersion = lists:nth(3, lists:reverse(Result)),
-    {error, {header_too_long, MaxHeaderSize}, HttpVersion};
+    {error, {too_long, Max, 413, "Headers unreasonably long"}, HttpVersion};
 
-parse_headers(<<>>, Header, Headers, CurrSize, MaxSizes, Result) ->
-    {?MODULE, parse_headers, [<<>>, Header, Headers, CurrSize, 
+parse_headers(<<>>, Header, Headers, Current, Max, MaxSizes, Result) ->
+    {?MODULE, parse_headers, [<<>>, Header, Headers, Current, Max, 
 			      MaxSizes, Result]};
-parse_headers(<<?CR,?LF,?LF,Body/binary>>, [], [], CurrSize, MaxSizes, Result) ->
+parse_headers(<<?CR,?LF,?LF,Body/binary>>, [], [], Current, Max, MaxSizes, Result) ->
     %% If ?CR is is missing RFC2616 section-19.3 
-    parse_headers(<<?CR,?LF,?CR,?LF,Body/binary>>, [], [], CurrSize,  
+    parse_headers(<<?CR,?LF,?CR,?LF,Body/binary>>, [], [], Current, Max,  
 		  MaxSizes, Result);
 
-parse_headers(<<?LF,?LF,Body/binary>>, [], [], CurrSize, MaxSizes, Result) ->
+parse_headers(<<?LF,?LF,Body/binary>>, [], [], Current, Max,  MaxSizes, Result) ->
     %% If ?CR is is missing RFC2616 section-19.3 
-    parse_headers(<<?CR,?LF,?CR,?LF,Body/binary>>, [], [], CurrSize,  
+    parse_headers(<<?CR,?LF,?CR,?LF,Body/binary>>, [], [], Current, Max, 
 		  MaxSizes, Result);
 
-parse_headers(<<?CR,?LF,?CR,?LF,Body/binary>>, [], [], _,  _, 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, _,
+parse_headers(<<?CR,?LF,?CR,?LF,Body/binary>>, Header, Headers, _, _,
 	      _, Result) ->
     HTTPHeaders = [lists:reverse(Header) | Headers],
     RequestHeaderRcord = 
@@ -238,52 +209,51 @@ parse_headers(<<?CR,?LF,?CR,?LF,Body/binary>>, Header, Headers, _,
 						    HTTPHeaders} | Result])),
     {ok, NewResult};
 
-parse_headers(<<?CR,?LF,?CR>> = Data, Header, Headers, CurrSize, 
+parse_headers(<<?CR,?LF,?CR>> = Data, Header, Headers, Current, Max, 
 	      MaxSizes, Result) ->
-    {?MODULE, parse_headers, [Data, Header, Headers, CurrSize, 
+    {?MODULE, parse_headers, [Data, Header, Headers, Current, Max, 
 			      MaxSizes, Result]};
-parse_headers(<<?LF>>, [], [], CurrSize, MaxSizes, Result) ->
+parse_headers(<<?LF>>, [], [], Current, Max, MaxSizes, Result) ->
     %% If ?CR is is missing RFC2616 section-19.3 
-    parse_headers(<<?CR,?LF>>, [], [], CurrSize, MaxSizes, Result);
+    parse_headers(<<?CR,?LF>>, [], [], Current, Max, MaxSizes, Result);
 
 %% There where no headers, which is unlikely to happen.
-parse_headers(<<?CR,?LF>>, [], [], _, _, Result) ->
+parse_headers(<<?CR,?LF>>, [], [], _, _, _, Result) ->
      NewResult = list_to_tuple(lists:reverse([<<>>, {#http_request_h{}, []} |
 					      Result])),
     {ok, NewResult};
 
-parse_headers(<<?LF>>, Header, Headers, CurrSize, 
+parse_headers(<<?LF>>, Header, Headers, Current, Max,  
 	      MaxSizes, Result) ->
     %% If ?CR is is missing RFC2616 section-19.3 
-    parse_headers(<<?CR,?LF>>, Header, Headers, CurrSize, MaxSizes, Result);
+    parse_headers(<<?CR,?LF>>, Header, Headers, Current, Max, MaxSizes, Result);
 
-parse_headers(<<?CR,?LF>> = Data, Header, Headers, CurrSize, 
+parse_headers(<<?CR,?LF>> = Data, Header, Headers, Current, Max, 
 	      MaxSizes, Result) ->
-    {?MODULE, parse_headers, [Data, Header, Headers, CurrSize, 
+    {?MODULE, parse_headers, [Data, Header, Headers, Current, Max, 
 			      MaxSizes, Result]};
-parse_headers(<<?LF, Octet, Rest/binary>>, Header, Headers, CurrSize,
+parse_headers(<<?LF, Octet, Rest/binary>>, Header, Headers, Current, Max,
 	      MaxSizes, Result) ->
     %% If ?CR is is missing RFC2616 section-19.3 
-    parse_headers(<<?CR,?LF, Octet, Rest/binary>>, Header, Headers, CurrSize,
+    parse_headers(<<?CR,?LF, Octet, Rest/binary>>, Header, Headers, Current, Max,
 		  MaxSizes, Result); 
-parse_headers(<<?CR,?LF, Octet, Rest/binary>>, Header, Headers, CurrSize,
+parse_headers(<<?CR,?LF, Octet, Rest/binary>>, Header, Headers, _, Max,
 	      MaxSizes, Result) ->
     parse_headers(Rest, [Octet], [lists:reverse(Header) | Headers], 
-		  CurrSize + 1, MaxSizes, Result);
-
-parse_headers(<<?CR>> = Data, Header, Headers, CurrSize,  
+		  0, Max, MaxSizes, Result);
+parse_headers(<<?CR>> = Data, Header, Headers, Current, Max,  
 	      MaxSizes, Result) ->
-    {?MODULE, parse_headers, [Data, Header, Headers, CurrSize, 
+    {?MODULE, parse_headers, [Data, Header, Headers, Current, Max, 
 			      MaxSizes, Result]};
-parse_headers(<<?LF>>, Header, Headers, CurrSize,  
+parse_headers(<<?LF>>, Header, Headers, Current,  Max, 
 	      MaxSizes, Result) ->
     %% If ?CR is is missing RFC2616 section-19.3 
-    parse_headers(<<?CR, ?LF>>, Header, Headers, CurrSize,  
+    parse_headers(<<?CR, ?LF>>, Header, Headers, Current, Max,  
 		  MaxSizes, Result);
 
-parse_headers(<<Octet, Rest/binary>>, Header, Headers, 
-	      CurrSize, MaxSizes, Result) ->
-    parse_headers(Rest, [Octet | Header], Headers, CurrSize + 1,
+parse_headers(<<Octet, Rest/binary>>, Header, Headers, Current,
+	      Max, MaxSizes, Result) ->
+    parse_headers(Rest, [Octet | Header], Headers, Current + 1, Max,
 		  MaxSizes, Result).
 
 whole_body(Body, Length) ->
@@ -430,3 +400,5 @@ tag([$:|Rest], Tag) ->
 tag([Chr|Rest], Tag) ->
     tag(Rest, [Chr|Tag]).
 
+lowest_version()->    
+    "HTTP/0.9".
diff --git a/lib/inets/src/http_server/httpd_request_handler.erl b/lib/inets/src/http_server/httpd_request_handler.erl
index bd37066ff6..8dcfec570a 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-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2014. 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
@@ -123,7 +123,8 @@ continue_init(Manager, ConfigDB, SocketType, Socket, TimeOut) ->
     
     {_, Status} = httpd_manager:new_connection(Manager),
     
-    MFA = {httpd_request, parse, [{MaxURISize, MaxHeaderSize}]}, 
+    MFA = {httpd_request, parse, [[{max_uri, MaxURISize}, {max_header, MaxHeaderSize},
+				   {max_version, ?HTTP_MAX_VERSION_STRING}, {max_method, ?HTTP_MAX_METHOD_STRING}]]}, 
 
     State = #state{mod                    = Mod, 
 		   manager                = Manager, 
@@ -207,23 +208,15 @@ handle_info({Proto, Socket, Data},
 			       set_new_data_size(cancel_request_timeout(State), NewDataSize)
 		       end,
             handle_http_msg(Result, NewState); 
-
-	{error, {uri_too_long, MaxSize}, Version} ->
-	    NewModData =  ModData#mod{http_version = Version},
-	    httpd_response:send_status(NewModData, 414, "URI too long"),
-	    Reason = io_lib:format("Uri too long, max size is ~p~n", 
-				   [MaxSize]),
-	    error_log(Reason, NewModData),
-	    {stop, normal, State#state{response_sent = true, 
-				       mod = NewModData}};
-	{error, {header_too_long, MaxSize}, Version} ->
+	{error, {too_long, MaxSize, ErrCode, ErrStr}, Version} ->
 	    NewModData =  ModData#mod{http_version = Version},
-	    httpd_response:send_status(NewModData, 413, "Header too long"),
-	    Reason = io_lib:format("Header too long, max size is ~p~n", 
-				   [MaxSize]),
+	    httpd_response:send_status(NewModData, ErrCode, ErrStr),
+	    Reason = io_lib:format("~p: ~p max size is ~p~n", 
+				   [ErrCode, ErrStr, MaxSize]),
 	    error_log(Reason, NewModData),
 	    {stop, normal, State#state{response_sent = true, 
 				       mod = NewModData}};
+
 	NewMFA ->
 	    http_transport:setopts(SockType, Socket, [{active, once}]),
 	    case NewDataSize of
@@ -549,7 +542,8 @@ 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), 
 
-    MFA = {httpd_request, parse, [{MaxURISize, MaxHeaderSize}]}, 
+    MFA = {httpd_request, parse, [[{max_uri, MaxURISize}, {max_header, MaxHeaderSize},
+				   {max_version, ?HTTP_MAX_VERSION_STRING}, {max_method, ?HTTP_MAX_METHOD_STRING}]]}, 
     TmpState = State#state{mod                    = NewModData,
 			   mfa                    = MFA,
 			   max_keep_alive_request = decrease(Max),
diff --git a/lib/inets/test/httpd_basic_SUITE.erl b/lib/inets/test/httpd_basic_SUITE.erl
index fbe65145dc..1eb852e85a 100644
--- a/lib/inets/test/httpd_basic_SUITE.erl
+++ b/lib/inets/test/httpd_basic_SUITE.erl
@@ -32,9 +32,9 @@
 suite() -> [{ct_hooks,[ts_install_cth]}].
 
 all() -> 
-    [
-     uri_too_long_414, 
+    [uri_too_long_414, 
      header_too_long_413,
+     entity_too_long,
      erl_script_nocache_opt,
      script_nocache,
      escaped_url_in_error_body,
@@ -63,15 +63,13 @@ end_per_group(_GroupName, Config) ->
 %% variable, but should NOT alter/remove any existing entries.
 %%--------------------------------------------------------------------
 init_per_suite(Config) ->
-    tsp("init_per_suite -> entry with"
-	"~n   Config: ~p", [Config]),
     inets_test_lib:stop_apps([inets]),
     inets_test_lib:start_apps([inets]),
     PrivDir = ?config(priv_dir, Config),
     DataDir = ?config(data_dir, Config), 
-
+    
     Dummy = 
-"<HTML>
+	"<HTML>
 <HEAD>
 <TITLE>/index.html</TITLE>
 </HEAD>
@@ -79,7 +77,7 @@ init_per_suite(Config) ->
 DUMMY
 </BODY>
 </HTML>",
-
+    
     DummyFile = filename:join([PrivDir,"dummy.html"]),
     CgiDir =  filename:join(PrivDir, "cgi-bin"),
     ok = file:make_dir(CgiDir),
@@ -116,8 +114,6 @@ DUMMY
 %% Description: Cleanup after the whole suite
 %%--------------------------------------------------------------------
 end_per_suite(_Config) ->
-    tsp("end_per_suite -> entry with"
-	"~n   Config: ~p", [_Config]),
     inets:stop(),
     ok.
 
@@ -134,8 +130,6 @@ end_per_suite(_Config) ->
 %% variable, but should NOT alter/remove any existing entries.
 %%--------------------------------------------------------------------
 init_per_testcase(Case, Config) ->
-    tsp("init_per_testcase(~w) -> entry with"
-	"~n   Config: ~p", [Case, Config]),
     Config.
 
 
@@ -147,22 +141,18 @@ init_per_testcase(Case, Config) ->
 %%   A list of key/value pairs, holding the test case configuration.
 %% Description: Cleanup after each test case
 %%--------------------------------------------------------------------
-end_per_testcase(Case, Config) ->
-    tsp("end_per_testcase(~w) -> entry with"
-	"~n   Config: ~p", [Case, Config]),
+end_per_testcase(_Case, Config) ->
     Config.
 
 
 %%-------------------------------------------------------------------------
 %% Test cases starts here.
 %%-------------------------------------------------------------------------
-uri_too_long_414(doc) ->
-    ["Test that too long uri's get 414 HTTP code"];
-uri_too_long_414(suite) ->
-    [];
+uri_too_long_414() ->
+    [{doc, "Test that too long uri's get 414 HTTP code"}].
 uri_too_long_414(Config) when is_list(Config) ->
     HttpdConf =   ?config(httpd_conf, Config),    
-    {ok, Pid} = inets:start(httpd, [{port, 0}, {max_uri_size, 10} 
+    {ok, Pid} = inets:start(httpd, [{max_uri_size, 10} 
 				    | HttpdConf]),
     Info = httpd:info(Pid),
     Port = proplists:get_value(port, Info),
@@ -178,17 +168,12 @@ uri_too_long_414(Config) when is_list(Config) ->
  				        {version, "HTTP/0.9"}]),    
     inets:stop(httpd, Pid).
     
-
-%%-------------------------------------------------------------------------
 %%-------------------------------------------------------------------------
-
-header_too_long_413(doc) ->
-    ["Test that too long headers's get 413 HTTP code"];
-header_too_long_413(suite) ->
-    [];
+header_too_long_413() ->
+    [{doc,"Test that too long headers's get 413 HTTP code"}].
 header_too_long_413(Config) when is_list(Config) ->
     HttpdConf = ?config(httpd_conf, Config), 
-    {ok, Pid} = inets:start(httpd, [{port, 0}, {max_header_size, 10}
+    {ok, Pid} = inets:start(httpd, [{max_header_size, 10}
 				    | HttpdConf]),
     Info = httpd:info(Pid),
     Port = proplists:get_value(port, Info),
@@ -202,8 +187,49 @@ header_too_long_413(Config) when is_list(Config) ->
     inets:stop(httpd, Pid).
    
 %%-------------------------------------------------------------------------
+
+entity_too_long() ->
+    [{doc, "Test that too long versions and method strings are rejected"}].
+entity_too_long(Config) when is_list(Config) ->
+    HttpdConf =   ?config(httpd_conf, Config),    
+    {ok, Pid} = inets:start(httpd, HttpdConf),
+    Info = httpd:info(Pid),
+    Port = proplists:get_value(port, Info),
+    Address = proplists:get_value(bind_address, Info),
+    ok = httpd_test_lib:verify_request(ip_comm, Address, Port, node(), 
+ 				       "GET / " ++
+ 				       lists:duplicate(100, $A) ++ "\r\n\r\n",
+ 				       [{statuscode, 413},
+					%% Server will send lowest version
+					%% as it will not get to the 
+					%% client version
+					%% before aborting
+ 				        {version, "HTTP/0.9"}]),
+    
+    ok = httpd_test_lib:verify_request(ip_comm, Address, Port, node(), 
+				       lists:duplicate(100, $A) ++ " / "
+				       "HTTP/1.1\r\n\r\n",
+ 				       [{statuscode, 413},
+					%% Server will send lowest version
+					%% as it will not get to the 
+					%% client version
+					%% before aborting
+ 				        {version, "HTTP/0.9"}]),   
+    inets:stop(httpd, Pid).
+    
 %%-------------------------------------------------------------------------
 
+script_nocache() ->
+    [{doc,"Test nocache option for mod_cgi and mod_esi"}].
+script_nocache(Config) when is_list(Config) ->
+    Normal = {no_header, "cache-control"},
+    NoCache = {header, "cache-control", "no-cache"},
+    verify_script_nocache(Config, false, false, Normal, Normal),
+    verify_script_nocache(Config, true, false, NoCache, Normal),
+    verify_script_nocache(Config, false, true, Normal, NoCache),
+    verify_script_nocache(Config, true, true, NoCache, NoCache).
+
+%%-------------------------------------------------------------------------
 erl_script_nocache_opt(doc) ->
     ["Test that too long headers's get 413 HTTP code"];
 erl_script_nocache_opt(suite) ->
@@ -225,154 +251,48 @@ erl_script_nocache_opt(Config) when is_list(Config) ->
     inets:stop(httpd, Pid).
 
 %%-------------------------------------------------------------------------
-%%-------------------------------------------------------------------------
 
-script_nocache(doc) ->
-    ["Test nocache option for mod_cgi and mod_esi"];
-script_nocache(suite) ->
-    [];
-script_nocache(Config) when is_list(Config) ->
-    Normal = {no_header, "cache-control"},
-    NoCache = {header, "cache-control", "no-cache"},
-    verify_script_nocache(Config, false, false, Normal, Normal),
-    verify_script_nocache(Config, true, false, NoCache, Normal),
-    verify_script_nocache(Config, false, true, Normal, NoCache),
-    verify_script_nocache(Config, true, true, NoCache, NoCache),
-    ok.
 
-verify_script_nocache(Config, CgiNoCache, EsiNoCache, CgiOption, EsiOption) ->
-    HttpdConf = ?config(httpd_conf, Config),
-    CgiScript = ?config(cgi_printenv, Config),
-    CgiDir = ?config(cgi_dir, Config),
-    {ok, Pid} = inets:start(httpd, [{port, 0},
-				    {script_alias,
-				     {"/cgi-bin/", CgiDir ++ "/"}},
-				    {script_nocache, CgiNoCache},
-				    {erl_script_alias,
-				     {"/cgi-bin/erl", [httpd_example,io]}},
-				    {erl_script_nocache, EsiNoCache}
-				    | HttpdConf]),
-    Info = httpd:info(Pid),
-    Port = proplists:get_value(port, Info),
-    Address = proplists:get_value(bind_address, Info),
-    ok = httpd_test_lib:verify_request(ip_comm, Address, Port, node(),
-				       "GET /cgi-bin/" ++ CgiScript ++
-					   " HTTP/1.0\r\n\r\n",
-				       [{statuscode, 200},
-					CgiOption,
-					{version, "HTTP/1.0"}]),
-    ok = httpd_test_lib:verify_request(ip_comm, Address, Port, node(),
-				       "GET /cgi-bin/erl/httpd_example:get "
-				       "HTTP/1.0\r\n\r\n",
-				       [{statuscode, 200},
-					EsiOption,
-					{version, "HTTP/1.0"}]),
-    inets:stop(httpd, Pid).
-
-
-%%-------------------------------------------------------------------------
 %%-------------------------------------------------------------------------
 
-escaped_url_in_error_body(doc) ->
-    ["Test Url-encoding see OTP-8940"];
-escaped_url_in_error_body(suite) ->
-    [];
-escaped_url_in_error_body(Config) when is_list(Config) ->
-    %% <CONDITIONAL-SKIP>
-    %% This skip is due to a problem on windows with long path's
-    %% If a path is too long file:open fails with, for example, eio.
-    %% Until that problem is fixed, we skip this case...
-    Skippable = [win32],
-    Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
-    ?NON_PC_TC_MAYBE_SKIP(Config, Condition),
-    %% </CONDITIONAL-SKIP>
-
-    tsp("escaped_url_in_error_body -> entry"),
+escaped_url_in_error_body() ->
+    [{doc, "Test Url-encoding see OTP-8940"}].
+escaped_url_in_error_body(Config) when is_list(Config) -> 
     HttpdConf   = ?config(httpd_conf, Config),
     {ok, Pid}   = inets:start(httpd, [{port, 0} | HttpdConf]),
     Info        = httpd:info(Pid),
     Port        = proplists:get_value(port,         Info),
-    _Address    = proplists:get_value(bind_address, Info),
-
-    %% Request 1
-    tss(1000), 
-    tsp("escaped_url_in_error_body -> request 1"),
     URL1        = ?URL_START ++ integer_to_list(Port),
-    %% Make sure the server is ok, by making a request for a valid page
-    case httpc:request(get, {URL1 ++ "/dummy.html", []},
-		       [{url_encode,  false}, 
-			{version,     "HTTP/1.0"}],
-		       [{full_result, false}]) of
-	{ok, {200, _}} ->
-	    %% Don't care about the the body, just that we get a ok response
-	    ok;
-	{ok, {StatusCode1, Body1}} ->
-	    tsf({unexpected_ok_1, StatusCode1, Body1})
-    end,
-
-    %% Request 2
-    tss(1000), 
-    tsp("escaped_url_in_error_body -> request 2"),
-    %% Make sure the server is ok, by making a request for a valid page
-    case httpc:request(get, {URL1 ++ "/dummy.html", []},
-		       [{url_encode,  true}, 
-			{version,     "HTTP/1.0"}],
-		       [{full_result, false}]) of
-	{ok, {200, _}} ->
-	    %% Don't care about the the body, just that we get a ok response
-	    ok;
-	{ok, {StatusCode2, Body2}} ->
-	    tsf({unexpected_ok_2, StatusCode2, Body2})
-    end,
-
-    %% Request 3
-    tss(1000), 
-    tsp("escaped_url_in_error_body -> request 3"),
+   
+    %% Sanity check
+    {ok, {200, _}} = httpc:request(get, {URL1 ++ "/dummy.html", []},
+     				   [{url_encode,  false}, 
+     				    {version,     "HTTP/1.0"}],
+     				   [{full_result, false}]),
+    {ok, {200, _}} = httpc:request(get, {URL1 ++ "/dummy.html", []},
+     				   [{url_encode,  true}, 
+     				    {version,     "HTTP/1.0"}],
+     				   [{full_result, false}]),
+    
     %% Ask for a non-existing page(1)
     Path            = "/<b>this_is_bold<b>",
     HTMLEncodedPath = http_util:html_encode(Path),
     URL2            = URL1 ++ Path,
-    case httpc:request(get, {URL2, []},
-		       [{url_encode,  true}, 
-			{version,     "HTTP/1.0"}],
-		       [{full_result, false}]) of
-	{ok, {404, Body3}} ->
-	    case find_URL_path(string:tokens(Body3, " ")) of
-		HTMLEncodedPath ->
-		    ok;
-		BadPath3 ->
-		    tsf({unexpected_path_3, HTMLEncodedPath, BadPath3})
-	    end;
-	{ok, UnexpectedOK3} ->
-	    tsf({unexpected_ok_3, UnexpectedOK3})
-    end,
+    {ok, {404, Body3}} = httpc:request(get, {URL2, []},
+				       [{url_encode,  true}, 
+					{version,     "HTTP/1.0"}],
+				       [{full_result, false}]),
 
-    %% Request 4
-    tss(1000), 
-    tsp("escaped_url_in_error_body -> request 4"),
-    %% Ask for a non-existing page(2)
-    case httpc:request(get, {URL2, []}, 
-		       [{url_encode,  false}, 
-			{version,     "HTTP/1.0"}],
-		       [{full_result, false}]) of
-	{ok, {404, Body4}} ->
-	    case find_URL_path(string:tokens(Body4, " ")) of
-		HTMLEncodedPath ->
-		    ok;
-		BadPath4 ->
-		    tsf({unexpected_path_4, HTMLEncodedPath, BadPath4})
-	    end;
-	{ok, UnexpectedOK4} ->
-	    tsf({unexpected_ok_4, UnexpectedOK4})
-    end, 
-    tss(1000), 
-    tsp("escaped_url_in_error_body -> stop inets"),
-    inets:stop(httpd, Pid),
-    tsp("escaped_url_in_error_body -> done"),    
-    ok.
+    HTMLEncodedPath = find_URL_path(string:tokens(Body3, " ")),
 
+    {ok, {404, Body4}} = httpc:request(get, {URL2, []}, 
+				       [{url_encode,  false}, 
+					{version,     "HTTP/1.0"}],
+				       [{full_result, false}]),
+    
+    HTMLEncodedPath = find_URL_path(string:tokens(Body4, " ")),
+    inets:stop(httpd, Pid).
 
-%%-------------------------------------------------------------------------
 %%-------------------------------------------------------------------------
 
 keep_alive_timeout(doc) ->
@@ -393,7 +313,6 @@ keep_alive_timeout(Config) when is_list(Config) ->
     inets:stop(httpd, Pid).
 
 %%-------------------------------------------------------------------------
-%%-------------------------------------------------------------------------
 
 script_timeout(doc) ->
     ["Test the httpd script_timeout option"];
@@ -423,12 +342,10 @@ verify_script_timeout(Config, ScriptTimeout, StatusCode) ->
 					{version, "HTTP/1.0"}]),
     inets:stop(httpd, Pid).
 
-
-%%-------------------------------------------------------------------------
 %%-------------------------------------------------------------------------
 
-slowdose(doc) ->
-    ["Testing minimum bytes per second option"];
+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]),
@@ -439,6 +356,40 @@ slowdose(Config) when is_list(Config) ->
     after 6000 ->
 	    {error, closed} = gen_tcp:send(Socket, "Hey")
     end.
+
+%%-------------------------------------------------------------------------
+%% Internal functions
+%%-------------------------------------------------------------------------
+
+verify_script_nocache(Config, CgiNoCache, EsiNoCache, CgiOption, EsiOption) ->
+    HttpdConf = ?config(httpd_conf, Config),
+    CgiScript = ?config(cgi_printenv, Config),
+    CgiDir = ?config(cgi_dir, Config),
+    {ok, Pid} = inets:start(httpd, [{port, 0},
+				    {script_alias,
+				     {"/cgi-bin/", CgiDir ++ "/"}},
+				    {script_nocache, CgiNoCache},
+				    {erl_script_alias,
+				     {"/cgi-bin/erl", [httpd_example,io]}},
+				    {erl_script_nocache, EsiNoCache}
+				    | HttpdConf]),
+    Info = httpd:info(Pid),
+    Port = proplists:get_value(port, Info),
+    Address = proplists:get_value(bind_address, Info),
+    ok = httpd_test_lib:verify_request(ip_comm, Address, Port, node(),
+				       "GET /cgi-bin/" ++ CgiScript ++
+					   " HTTP/1.0\r\n\r\n",
+				       [{statuscode, 200},
+					CgiOption,
+					{version, "HTTP/1.0"}]),
+    ok = httpd_test_lib:verify_request(ip_comm, Address, Port, node(),
+				       "GET /cgi-bin/erl/httpd_example:get "
+				       "HTTP/1.0\r\n\r\n",
+				       [{statuscode, 200},
+					EsiOption,
+					{version, "HTTP/1.0"}]),
+    inets:stop(httpd, Pid).
+
 find_URL_path([]) ->
     "";
 find_URL_path(["URL", URL | _]) ->
@@ -446,21 +397,6 @@ find_URL_path(["URL", URL | _]) ->
 find_URL_path([_ | Rest]) ->
     find_URL_path(Rest).
 
-
-tsp(F) ->
-    inets_test_lib:tsp(F).
-tsp(F, A) ->
-    inets_test_lib:tsp(F, A).
-
-tsf(Reason) ->
-    inets_test_lib:tsf(Reason).
-
-tss(Time) ->
-    inets_test_lib:tss(Time).
-
-
-
-
 skip(Reason) ->
     {skip, Reason}.
 
-- 
cgit v1.2.3


From bf352a0d19499f9041cb887ce83c1c13b9def759 Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin <ingela@erlang.org>
Date: Fri, 16 May 2014 12:20:41 +0200
Subject: inets: httpc - update test suite framwork to adopt to change in httpd

---
 lib/inets/test/http_format_SUITE.erl | 15 +++++++++++----
 lib/inets/test/httpc_SUITE.erl       | 25 ++++++++++++++++++-------
 lib/inets/test/httpd_test_lib.erl    |  2 +-
 3 files changed, 30 insertions(+), 12 deletions(-)

(limited to 'lib')

diff --git a/lib/inets/test/http_format_SUITE.erl b/lib/inets/test/http_format_SUITE.erl
index c5920a3968..d4a3f28f38 100644
--- a/lib/inets/test/http_format_SUITE.erl
+++ b/lib/inets/test/http_format_SUITE.erl
@@ -1,7 +1,7 @@
 %%
 %% %CopyrightBegin%
 %%
-%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2014. 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
@@ -356,7 +356,10 @@ http_request(Config) when is_list(Config) ->
      "HTTP/1.1",
      {#http_request_h{host = "www.erlang.org", te = []},
       ["te: ","host:www.erlang.org"]}, <<>>} =
-	parse(httpd_request, parse, [?HTTP_MAX_HEADER_SIZE], HttpHead),
+	parse(httpd_request, parse, [[{max_header, ?HTTP_MAX_HEADER_SIZE},
+				      {max_version, ?HTTP_MAX_VERSION_STRING}, 
+				      {max_method, ?HTTP_MAX_METHOD_STRING}]],
+	      HttpHead),
 
     HttpHead1 = ["GET http://www.erlang.org HTTP/1.1" ++ 
 		 [?CR], [?LF, ?CR, ?LF]],
@@ -364,7 +367,9 @@ http_request(Config) when is_list(Config) ->
      "http://www.erlang.org",
      "HTTP/1.1",
      {#http_request_h{}, []}, <<>>} =
-	parse(httpd_request, parse, [?HTTP_MAX_HEADER_SIZE], HttpHead1),
+	parse(httpd_request, parse,  [[{max_header, ?HTTP_MAX_HEADER_SIZE},
+				       {max_version, ?HTTP_MAX_VERSION_STRING}, 
+				       {max_method, ?HTTP_MAX_METHOD_STRING}]], HttpHead1),
 
 
     HttpHead2 = ["GET http://www.erlang.org HTTP/1.1" ++ 
@@ -373,7 +378,9 @@ http_request(Config) when is_list(Config) ->
      "http://www.erlang.org",
      "HTTP/1.1",
      {#http_request_h{}, []}, <<>>} =
-	parse(httpd_request, parse, [?HTTP_MAX_HEADER_SIZE], HttpHead2),
+	parse(httpd_request, parse, [[{max_header, ?HTTP_MAX_HEADER_SIZE},
+				      {max_version, ?HTTP_MAX_VERSION_STRING}, 
+				      {max_method, ?HTTP_MAX_METHOD_STRING}]], HttpHead2),
 
     %% Note the following body is not related to the headers above
     HttpBody = ["<HTML>\n<HEAD>\n<TITLE> dummy </TITLE>\n</HEAD>\n<BODY>\n",
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index b1b799c953..d3079e2bdd 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -27,15 +27,14 @@
 -include_lib("kernel/include/file.hrl").
 -include_lib("common_test/include/ct.hrl").
 -include("inets_test_lib.hrl").
-
+-include("http_internal.hrl").
 %% Note: This directive should only be used in test suites.
 -compile(export_all).
 
 -define(URL_START, "http://").
 -define(TLS_URL_START, "https://").
 -define(NOT_IN_USE_PORT, 8997).
--define(LF, $\n).
--define(HTTP_MAX_HEADER_SIZE, 10240).
+
 -record(sslsocket, {fd = nil, pid = nil}).
 %%--------------------------------------------------------------------
 %% Common Test interface functions -----------------------------------
@@ -1226,7 +1225,10 @@ dummy_server_init(Caller, ip_comm, Inet, _) ->
     {ok, ListenSocket} = gen_tcp:listen(0, [Inet | BaseOpts]),
     {ok, Port} = inet:port(ListenSocket),
     Caller ! {port, Port},
-    dummy_ipcomm_server_loop({httpd_request, parse, [?HTTP_MAX_HEADER_SIZE]},
+    dummy_ipcomm_server_loop({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}]]},
 			     [], ListenSocket);
 
 dummy_server_init(Caller, ssl, Inet, SSLOptions) ->
@@ -1238,7 +1240,10 @@ dummy_ssl_server_init(Caller, BaseOpts, Inet) ->
     {ok, ListenSocket} = ssl:listen(0, [Inet | BaseOpts]),
     {ok, {_, Port}} = ssl:sockname(ListenSocket),
     Caller ! {port, Port},
-    dummy_ssl_server_loop({httpd_request, parse, [?HTTP_MAX_HEADER_SIZE]},
+    dummy_ssl_server_loop({httpd_request, parse, [[{max_uri,    ?HTTP_MAX_URI_SIZE},
+						   {max_method, ?HTTP_MAX_METHOD_STRING},
+						   {max_version,?HTTP_MAX_VERSION_STRING}, 
+						   {max_method, ?HTTP_MAX_METHOD_STRING}]]},
 			  [], ListenSocket).
 
 dummy_ipcomm_server_loop(MFA, Handlers, ListenSocket) ->
@@ -1314,10 +1319,16 @@ handle_request(Module, Function, Args, Socket) ->
 		stop ->
 		    stop;
 		<<>> ->
-		    {httpd_request, parse, [[<<>>, ?HTTP_MAX_HEADER_SIZE]]};
+		    {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}]]]};
 		Data ->	
 		    handle_request(httpd_request, parse, 
-				   [Data |[?HTTP_MAX_HEADER_SIZE]], Socket)
+				   [Data, [{max_uri,    ?HTTP_MAX_URI_SIZE},
+					   {max_header, ?HTTP_MAX_HEADER_SIZE},
+					   {max_version,?HTTP_MAX_VERSION_STRING}, 
+					   {max_method, ?HTTP_MAX_METHOD_STRING}]], Socket)
 	    end;
 	NewMFA ->
 	    NewMFA
diff --git a/lib/inets/test/httpd_test_lib.erl b/lib/inets/test/httpd_test_lib.erl
index ed466fd727..36a5bb9e71 100644
--- a/lib/inets/test/httpd_test_lib.erl
+++ b/lib/inets/test/httpd_test_lib.erl
@@ -103,7 +103,7 @@ verify_request(SocketType, Host, Port, TranspOpts0, Node, RequestStr, Options, T
     
     try inets_test_lib:connect_bin(SocketType, Host, Port, TranspOpts) of
 	{ok, Socket} ->
-	    SendRes = inets_test_lib:send(SocketType, Socket, RequestStr),
+	    ok = inets_test_lib:send(SocketType, Socket, RequestStr),
 	    State = case inets_regexp:match(RequestStr, "printenv") of
 			nomatch ->
 			    #state{};
-- 
cgit v1.2.3


From ee3fd715255a865b80532ad1cf88e51a8a4147ba Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin <ingela@erlang.org>
Date: Fri, 16 May 2014 14:46:13 +0200
Subject: inets: httpd - Behave well on not so long but wrong request lines

---
 lib/inets/src/http_server/httpd_request.erl        | 16 +++++++++++--
 .../src/http_server/httpd_request_handler.erl      |  5 ++++
 lib/inets/test/httpd_basic_SUITE.erl               | 27 ++++++++++++++++++++--
 3 files changed, 44 insertions(+), 4 deletions(-)

(limited to 'lib')

diff --git a/lib/inets/src/http_server/httpd_request.erl b/lib/inets/src/http_server/httpd_request.erl
index 68e7c16702..712c73599f 100644
--- a/lib/inets/src/http_server/httpd_request.erl
+++ b/lib/inets/src/http_server/httpd_request.erl
@@ -107,8 +107,12 @@ validate("POST", Uri, "HTTP/1." ++ _N) ->
 validate("TRACE", Uri, "HTTP/1." ++ N) when hd(N) >= $1 ->
     validate_uri(Uri);
 validate(Method, Uri, Version) ->
-    {error, {not_supported, {Method, Uri, Version}}}.
-
+    case validate_version(Version) of
+	true ->
+	    {error, {not_supported, {Method, Uri, Version}}};
+	false ->
+	    {error, {bad_version, Version}}
+    end.
 %%----------------------------------------------------------------------
 %% The request is passed through the server as a record of type mod 
 %% create it.
@@ -296,6 +300,14 @@ validate_path([".." | Rest], N, RequestURI) ->
 validate_path([_ | Rest], N, RequestURI) ->
     validate_path(Rest, N + 1, RequestURI).
 
+validate_version("HTTP/1.1") ->
+    true;
+validate_version("HTTP/1.0") ->
+    true;
+validate_version("HTTP/0.9") ->
+    true;
+validate_version(_) ->
+    false.
 %%----------------------------------------------------------------------
 %% There are 3 possible forms of the reuqest URI 
 %%
diff --git a/lib/inets/src/http_server/httpd_request_handler.erl b/lib/inets/src/http_server/httpd_request_handler.erl
index 8dcfec570a..b3c9cbc46a 100644
--- a/lib/inets/src/http_server/httpd_request_handler.erl
+++ b/lib/inets/src/http_server/httpd_request_handler.erl
@@ -375,6 +375,11 @@ handle_http_msg({Method, Uri, Version, {RecordHeaders, Headers}, Body},
 				       400, URI),
 	    Reason = io_lib:format("Malformed syntax in URI: ~p~n", [URI]),
 	    error_log(Reason, ModData),
+	    {stop, normal, State#state{response_sent = true}};
+	{error, {bad_version, Ver}} ->
+	    httpd_response:send_status(ModData#mod{http_version = "HTTP/0.9"}, 400, Ver),
+	    Reason = io_lib:format("Malformed syntax version: ~p~n", [Ver]),
+	    error_log(Reason, ModData),
 	    {stop, normal, State#state{response_sent = true}}
     end;
 handle_http_msg({ChunkedHeaders, Body}, 
diff --git a/lib/inets/test/httpd_basic_SUITE.erl b/lib/inets/test/httpd_basic_SUITE.erl
index 1eb852e85a..1fcc5f257e 100644
--- a/lib/inets/test/httpd_basic_SUITE.erl
+++ b/lib/inets/test/httpd_basic_SUITE.erl
@@ -196,16 +196,39 @@ entity_too_long(Config) when is_list(Config) ->
     Info = httpd:info(Pid),
     Port = proplists:get_value(port, Info),
     Address = proplists:get_value(bind_address, Info),
+    
+    %% Not so long but wrong
+    ok = httpd_test_lib:verify_request(ip_comm, Address, Port, node(), 
+     				       "GET / " ++
+					   lists:duplicate(5, $A) ++ "\r\n\r\n",
+     				       [{statuscode, 400},
+     					%% Server will send lowest version
+    					%% as it will not get to the 
+     					%% client version
+     					%% before aborting
+     				        {version, "HTTP/0.9"}]),
+    
+    %% Too long
     ok = httpd_test_lib:verify_request(ip_comm, Address, Port, node(), 
  				       "GET / " ++
- 				       lists:duplicate(100, $A) ++ "\r\n\r\n",
+					   lists:duplicate(100, $A) ++ "\r\n\r\n",
  				       [{statuscode, 413},
 					%% Server will send lowest version
 					%% as it will not get to the 
 					%% client version
 					%% before aborting
  				        {version, "HTTP/0.9"}]),
-    
+    %% Not so long but wrong
+    ok = httpd_test_lib:verify_request(ip_comm, Address, Port, node(), 
+				       lists:duplicate(5, $A) ++ " / "
+				       "HTTP/1.1\r\n\r\n",
+ 				       [{statuscode, 501},
+					%% Server will send lowest version
+					%% as it will not get to the 
+					%% client version
+					%% before aborting
+ 				        {version, "HTTP/1.1"}]),
+    %% Too long
     ok = httpd_test_lib:verify_request(ip_comm, Address, Port, node(), 
 				       lists:duplicate(100, $A) ++ " / "
 				       "HTTP/1.1\r\n\r\n",
-- 
cgit v1.2.3


From a004919e744907ad70300df391eccc1fa72bc289 Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin <ingela@erlang.org>
Date: Fri, 23 May 2014 17:43:49 +0200
Subject: inets: Prepare for release

Do application restart as old soft upgrade was not correct
---
 lib/inets/src/inets_app/inets.appup.src | 13 +++++++++++--
 lib/inets/vsn.mk                        |  2 +-
 2 files changed, 12 insertions(+), 3 deletions(-)

(limited to 'lib')

diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index dd081962cc..5499596bbd 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -17,11 +17,20 @@
 %% %CopyrightEnd%
 {"%VSN%",
  [
-  {"5.9.8", [{load_module, ftp, soft_purge, soft_purge, []}]},
+  {"5.10", 
+   [{load_module, httpd, soft_purge, soft_purge, []},
+    {load_module, httpd_manager, soft_purge, soft_purge, []},
+    {load_module, httpd_request, soft_purge, soft_purge, []},
+    {load_module, httpd_request_handler, soft_purge, soft_purge, 
+     []}]},
   {<<"5\\..*">>,[{restart_application, inets}]}
  ],
  [
-  {"5.9.8", [{load_module, ftp, soft_purge, soft_purge, []}]},
+  {"5.10", 
+   [{load_module, httpd, soft_purge, soft_purge, []},
+    {load_module, httpd_manager, soft_purge, soft_purge, []},
+    {load_module, httpd_request, soft_purge, soft_purge, []},
+    {load_module, httpd_request_handler, soft_purge, soft_purge, []}]},
   {<<"5\\..*">>,[{restart_application, inets}]}
  ]
 }.
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index cbcf0362c9..bbd86c3eb3 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -18,6 +18,6 @@
 # %CopyrightEnd%
 
 APPLICATION = inets
-INETS_VSN   = 5.10
+INETS_VSN   = 5.10.1
 PRE_VSN     =
 APP_VSN     = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
-- 
cgit v1.2.3


From e123ced89eda3dba0ddc30dbbaab5716adee886a Mon Sep 17 00:00:00 2001
From: Hans Nilsson <hans@erlang.org>
Date: Wed, 23 Apr 2014 21:45:27 +0200
Subject: ssh: Add max_session parameter to ssh:daemon

---
 lib/ssh/doc/src/ssh.xml          | 21 ++++++++++++---
 lib/ssh/src/ssh.erl              |  4 +++
 lib/ssh/src/ssh_acceptor.erl     | 47 +++++++++++++++++++++++++--------
 lib/ssh/test/ssh_basic_SUITE.erl | 56 ++++++++++++++++++++++++++++++++++++++--
 4 files changed, 111 insertions(+), 17 deletions(-)

(limited to 'lib')

diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index 7fbd70c87e..5a141ced3c 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -307,18 +307,31 @@
 
 	  <tag><c><![CDATA[{negotiation_timeout, integer()}]]></c></tag>
 	  <item>
-	    <p>Max time in milliseconds for the authentication negotiation.  The default value is 2 minutes.
+	    <p>Max time in milliseconds for the authentication negotiation.  The default value is 2 minutes. If the client fails to login within this time, the connection is closed.
+	    </p>
+	  </item>
+
+	  <tag><c><![CDATA[{max_sessions, pos_integer()}]]></c></tag>
+	  <item>
+	    <p>The maximum number of simultaneous sessions that are accepted at any time for this daemon.  This includes sessions that are being authorized.  So if set to <c>N</c>, and <c>N</c> clients have connected but not started the login process, the <c>N+1</c> connection attempt will be aborted.  If <c>N</c> connections are authenticated and still logged in, no more loggins will be accepted until one of the existing ones log out.
+	    </p>
+	    <p>The counter is per listening port, so if two daemons are started, one with <c>{max_sessions,N}</c> and the other with <c>{max_sessions,M}</c> there will be in total <c>N+M</c> connections accepted for the whole ssh application.
+	    </p>
+	    <p>Note that if <c>parallel_login</c> is <c>false</c>, only one client at a time may be in the authentication phase.
+	    </p>
+	    <p>As default, the option is not set. This means that the number is not limited.
 	    </p>
 	  </item>
 
 	  <tag><c><![CDATA[{parallel_login, boolean()}]]></c></tag>
 	  <item>
-	    <p>If set to false (the default value), only one login is handled a time.  If set to true, an unlimited logins will be allowed simultanously. Note that this affects only the connections with authentication in progress, not the already authenticated connections.
+	    <p>If set to false (the default value), only one login is handled a time.  If set to true, an unlimited number of login attempts will be allowed simultanously.
+	    </p>
+	    <p>If the <c>max_sessions</c> option is set to <c>N</c> and <c>parallel_login</c> is set to <c>true</c>, the max number of simultaneous login attempts at any time is limited to <c>N-K</c> where <c>K</c> is the number of authenticated connections present at this daemon.
 	    </p>
 	    <warning>
-	      <p>Do not enable parallel_logins without protecting the server by other means like a firewall. If set to true, there is no protection against dos attacs.</p>
+	      <p>Do not enable <c>parallel_logins</c> without protecting the server by other means, for example the <c>max_sessions</c> option or a firewall configuration. If set to <c>true</c>, there is no protection against DOS attacks.</p>
 	    </warning>
-
 	  </item>
 
 	  <tag><c><![CDATA[{key_cb, atom()}]]></c></tag>
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index de6e8cc421..75081b7a61 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -332,6 +332,8 @@ handle_option([{idle_time, _} = Opt | Rest], SocketOptions, SshOptions) ->
     handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
 handle_option([{rekey_limit, _} = Opt|Rest], SocketOptions, SshOptions) ->
     handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
+handle_option([{max_sessions, _} = Opt|Rest], SocketOptions, SshOptions) ->
+    handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
 handle_option([{negotiation_timeout, _} = Opt|Rest], SocketOptions, SshOptions) ->
     handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
 handle_option([{parallel_login, _} = Opt|Rest], SocketOptions, SshOptions) ->
@@ -366,6 +368,8 @@ handle_ssh_option({pref_public_key_algs, Value} = Opt) when is_list(Value), leng
     end;
 handle_ssh_option({connect_timeout, Value} = Opt) when is_integer(Value); Value == infinity ->
     Opt;
+handle_ssh_option({max_sessions, Value} = Opt) when is_integer(Value), Value>0 ->
+    Opt;
 handle_ssh_option({negotiation_timeout, Value} = Opt) when is_integer(Value); Value == infinity ->
     Opt;
 handle_ssh_option({parallel_login, Value} = Opt) when Value==true ; Value==false ->
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index e57b07cee8..7302196674 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -80,18 +80,36 @@ acceptor_loop(Callback, Port, Address, Opts, ListenSocket, AcceptTimeout) ->
 				  ListenSocket, AcceptTimeout)
     end.
 
-handle_connection(_Callback, Address, Port, Options, Socket) ->
+handle_connection(Callback, Address, Port, Options, Socket) ->
     SystemSup = ssh_system_sup:system_supervisor(Address, Port),
-    {ok, SubSysSup} = ssh_system_sup:start_subsystem(SystemSup, Options),
-    ConnectionSup = ssh_subsystem_sup:connection_supervisor(SubSysSup),
-    Timeout = proplists:get_value(negotiation_timeout, 
-				  proplists:get_value(ssh_opts, Options, []),
-				  2*60*1000),
-    ssh_connection_handler:start_connection(server, Socket,
-					    [{supervisors, [{system_sup, SystemSup},
-							    {subsystem_sup, SubSysSup},
-							    {connection_sup, ConnectionSup}]}
-					     | Options], Timeout).
+    SSHopts = proplists:get_value(ssh_opts, Options, []),
+    MaxSessions = proplists:get_value(max_sessions,SSHopts,infinity),
+    case number_of_connections(SystemSup) < MaxSessions of
+	true ->
+	    {ok, SubSysSup} = ssh_system_sup:start_subsystem(SystemSup, Options),
+	    ConnectionSup = ssh_subsystem_sup:connection_supervisor(SubSysSup),
+	    Timeout = proplists:get_value(negotiation_timeout, SSHopts, 2*60*1000),
+	    ssh_connection_handler:start_connection(server, Socket,
+						    [{supervisors, [{system_sup, SystemSup},
+								    {subsystem_sup, SubSysSup},
+								    {connection_sup, ConnectionSup}]}
+						     | Options], Timeout);
+	false ->
+	    Callback:close(Socket),
+	    IPstr = if is_tuple(Address) -> inet:ntoa(Address);
+		     true -> Address
+		  end,
+	    Str = try io_lib:format('~s:~p',[IPstr,Port])
+		  catch _:_ -> "port "++integer_to_list(Port)
+		  end,
+	    error_logger:info_report("Ssh login attempt to "++Str++" denied due to option "
+				     "max_sessions limits to "++ io_lib:write(MaxSessions) ++
+				     " sessions."
+				     ),
+	    {error,max_sessions}
+    end.
+
+
 handle_error(timeout) ->
     ok;
 
@@ -117,3 +135,10 @@ handle_error(Reason) ->
     String = lists:flatten(io_lib:format("Accept error: ~p", [Reason])),
     error_logger:error_report(String),
     exit({accept_failed, String}).    
+
+
+number_of_connections(SystemSup) ->
+    length([X || 
+	       {R,X,supervisor,[ssh_subsystem_sup]} <- supervisor:which_children(SystemSup),
+	       is_reference(R)
+	  ]).
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index d2e52379fa..a8b64b1425 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -47,21 +47,26 @@ all() ->
      daemon_already_started,
      server_password_option,
      server_userpassword_option,
-     double_close].
+     double_close,
+     {group, hardening_tests}
+    ].
 
 groups() -> 
     [{dsa_key, [], basic_tests()},
      {rsa_key, [], basic_tests()},
      {dsa_pass_key, [], [pass_phrase]},
      {rsa_pass_key, [], [pass_phrase]},
-     {internal_error, [], [internal_error]}
+     {internal_error, [], [internal_error]},
+     {hardening_tests, [], [max_sessions]}
     ].
 
+
 basic_tests() ->
     [send, close, peername_sockname,
      exec, exec_compressed, shell, cli, known_hosts, 
      idle_time, rekey, openssh_zlib_basic_test].
 
+
 %%--------------------------------------------------------------------
 init_per_suite(Config) ->
     case catch crypto:start() of
@@ -74,6 +79,8 @@ end_per_suite(_Config) ->
     ssh:stop(),
     crypto:stop().
 %%--------------------------------------------------------------------
+init_per_group(hardening_tests, Config) ->
+    init_per_group(dsa_key, Config);
 init_per_group(dsa_key, Config) ->
     DataDir = ?config(data_dir, Config),
     PrivDir = ?config(priv_dir, Config),
@@ -103,6 +110,8 @@ init_per_group(internal_error, Config) ->
 init_per_group(_, Config) ->
     Config.
 
+end_per_group(hardening_tests, Config) ->
+    end_per_group(dsa_key, Config);
 end_per_group(dsa_key, Config) ->
     PrivDir = ?config(priv_dir, Config),
     ssh_test_lib:clean_dsa(PrivDir),
@@ -638,6 +647,49 @@ openssh_zlib_basic_test(Config) ->
     ok = ssh:close(ConnectionRef),
     ssh:stop_daemon(Pid).
 
+%%--------------------------------------------------------------------
+
+max_sessions(Config) ->
+    SystemDir = filename:join(?config(priv_dir, Config), system),
+    UserDir = ?config(priv_dir, Config),
+    MaxSessions = 2,
+    {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+					     {user_dir, UserDir},
+					     {user_passwords, [{"carni", "meat"}]},
+					     {parallel_login, true},
+					     {max_sessions, MaxSessions}
+					    ]),
+
+    Connect = fun() ->
+		      R=ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+							  {user_dir, UserDir},
+							  {user_interaction, false},
+							  {user, "carni"},
+							  {password, "meat"}
+							 ]),
+		      ct:log("Connection ~p up",[R])
+	      end,
+
+    try [Connect() || _ <- lists:seq(1,MaxSessions)]
+    of
+	_ ->
+	    ct:pal("Expect Info Report:",[]),
+	    try Connect()
+	    of
+		_ConnectionRef ->
+		    ssh:stop_daemon(Pid),
+		    {fail,"Too many connections accepted"}
+	    catch
+		error:{badmatch,{error,"Connection closed"}} ->
+		    ssh:stop_daemon(Pid),
+		    ok
+	    end
+    catch
+	error:{badmatch,{error,"Connection closed"}} ->
+	    ssh:stop_daemon(Pid),
+	    {fail,"Too few connections accepted"}
+    end.
+
 %%--------------------------------------------------------------------
 %% Internal functions ------------------------------------------------
 %%--------------------------------------------------------------------
-- 
cgit v1.2.3


From d841653fbfeb185349db42527a9774f91f153573 Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin <ingela@erlang.org>
Date: Mon, 5 May 2014 10:36:34 +0200
Subject: ssh: Use correct timeout value for the connection timeout

---
 lib/ssh/src/ssh.erl              |  5 ++-
 lib/ssh/test/ssh_basic_SUITE.erl | 82 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 85 insertions(+), 2 deletions(-)

(limited to 'lib')

diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 75081b7a61..240de69eff 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -1,7 +1,7 @@
 %
 %% %CopyrightBegin%
 %%
-%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2014. 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
@@ -73,8 +73,9 @@ connect(Host, Port, Options, Timeout) ->
 	{SocketOptions, SshOptions} ->
 	    {_, Transport, _} = TransportOpts =
 		proplists:get_value(transport, Options, {tcp, gen_tcp, tcp_closed}),
+	    ConnectionTimeout = proplists:get_value(connect_timeout, Options, infinity),
 	    Inet = proplists:get_value(inet, SshOptions, inet),
-	    try Transport:connect(Host, Port,  [ {active, false}, Inet | SocketOptions], Timeout) of
+	    try Transport:connect(Host, Port,  [ {active, false}, Inet | SocketOptions], ConnectionTimeout) of
 		{ok, Socket} ->
 		    Opts =  [{user_pid, self()}, {host, Host} | fix_idle_time(SshOptions)],
 		    ssh_connection_handler:start_connection(client, Socket, Opts, Timeout);
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index a8b64b1425..8217e643c1 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -48,6 +48,8 @@ all() ->
      server_password_option,
      server_userpassword_option,
      double_close,
+     ssh_connect_timeout,
+     ssh_connect_arg4_timeout,
      {group, hardening_tests}
     ].
 
@@ -628,6 +630,86 @@ double_close(Config) when is_list(Config) ->
     exit(CM, {shutdown, normal}),
     ok = ssh:close(CM).
 
+%%--------------------------------------------------------------------
+ssh_connect_timeout() ->
+    [{doc, "Test connect_timeout option in ssh:connect/4"}].
+ssh_connect_timeout(_Config) ->
+    ConnTimeout = 2000,
+    {error,{faked_transport,connect,TimeoutToTransport}} = 
+	ssh:connect("localhost", 12345, 
+		    [{transport,{tcp,?MODULE,tcp_closed}},
+		     {connect_timeout,ConnTimeout}],
+		    1000),
+    case TimeoutToTransport of
+	ConnTimeout -> ok;
+	Other -> 
+	    ct:log("connect_timeout is ~p but transport received ~p",[ConnTimeout,Other]),
+	    {fail,"ssh:connect/4 wrong connect_timeout received in transport"}
+    end.
+    
+%% Help for the test above
+connect(_Host, _Port, _Opts, Timeout) ->
+    {error, {faked_transport,connect,Timeout}}.
+
+
+%%--------------------------------------------------------------------
+ssh_connect_arg4_timeout() ->
+    [{doc, "Test fourth argument in ssh:connect/4"}].
+ssh_connect_arg4_timeout(_Config) ->
+    Timeout = 1000,
+    Parent = self(),
+    %% start the server
+    Server = spawn(fun() ->
+			   {ok,Sl} = gen_tcp:listen(0,[]),
+			   {ok,{_,Port}} = inet:sockname(Sl),
+			   Parent ! {port,self(),Port},
+			   Rsa = gen_tcp:accept(Sl),
+			   ct:log("Server gen_tcp:accept got ~p",[Rsa]),
+			   receive after 2*Timeout -> ok end %% let client timeout first
+		   end),
+
+    %% Get listening port
+    Port = receive
+	       {port,Server,ServerPort} -> ServerPort
+	   end,
+
+    %% try to connect with a timeout, but "supervise" it
+    Client = spawn(fun() ->
+			   T0 = now(),
+			   Rc = ssh:connect("localhost",Port,[],Timeout),
+			   ct:log("Client ssh:connect got ~p",[Rc]),
+			   Parent ! {done,self(),Rc,T0}
+		   end),
+
+    %% Wait for client reaction on the connection try:
+    receive
+	{done, Client, {error,_E}, T0} ->
+	    Msp = ms_passed(T0, now()),
+	    exit(Server,hasta_la_vista___baby),
+	    Low = 0.9*Timeout,
+	    High =  1.1*Timeout,
+	    ct:log("Timeout limits: ~p--~p, timeout was ~p, expected ~p",[Low,High,Msp,Timeout]),
+	    if
+		Low<Msp, Msp<High -> ok;
+		true -> {fail, "timeout not within limits"}
+	    end;
+	{done, Client, {ok,_Ref}, _T0} ->
+	    {fail,"ssh-connected ???"}
+    after
+	5000 ->
+	    exit(Server,hasta_la_vista___baby),
+	    exit(Client,hasta_la_vista___baby),
+	    {fail, "Didn't timeout"}
+    end.
+
+
+%% Help function
+%% N2-N1
+ms_passed(N1={_,_,M1}, N2={_,_,M2}) ->
+    {0,{0,Min,Sec}} = calendar:time_difference(calendar:now_to_local_time(N1),
+					       calendar:now_to_local_time(N2)),
+    1000 * (Min*60 + Sec + (M2-M1)/1000000).
+
 %%--------------------------------------------------------------------
 
 openssh_zlib_basic_test() ->
-- 
cgit v1.2.3


From b21d30d84e1790107aaa8cc7b39eb1095dea1fca Mon Sep 17 00:00:00 2001
From: Hans Nilsson <hans@erlang.org>
Date: Mon, 26 May 2014 11:07:56 +0200
Subject: ssh: Prepare for release

---
 lib/ssh/src/ssh.appup.src | 4 ++++
 lib/ssh/vsn.mk            | 2 +-
 2 files changed, 5 insertions(+), 1 deletion(-)

(limited to 'lib')

diff --git a/lib/ssh/src/ssh.appup.src b/lib/ssh/src/ssh.appup.src
index 1917c95f5a..42eb2167e0 100644
--- a/lib/ssh/src/ssh.appup.src
+++ b/lib/ssh/src/ssh.appup.src
@@ -19,9 +19,13 @@
 
 {"%VSN%",	
  [
+  {"3.0.1", [{load_module, ssh, soft_purge, soft_purge, []},
+	     {load_module, ssh_acceptor, soft_purge, soft_purge, []}]},
   {<<".*">>, [{restart_application, ssh}]}
  ],
  [
+  {"3.0.1", [{load_module, ssh, soft_purge, soft_purge, []},
+	     {load_module, ssh_acceptor, soft_purge, soft_purge, []}]},
   {<<".*">>, [{restart_application, ssh}]}
  ]
 }.
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index 9ffc59dbaf..40ed27d8f5 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
 #-*-makefile-*-   ; force emacs to enter makefile-mode
 
-SSH_VSN = 3.0.1
+SSH_VSN = 3.0.2
 APP_VSN    = "ssh-$(SSH_VSN)"
 
-- 
cgit v1.2.3


From 622fd3c35bd277353374adc45b18839f7ca988f3 Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin <ingela@erlang.org>
Date: Tue, 6 May 2014 17:30:38 +0200
Subject: inets: Correct distirbing mode for httpd:reload_config/2

config_reload tests are not enough to test httpd "block/unblock"
used by config_reload, so renable some test cases in the old_httpd_SUITE
after making them work with the new code. Should be cleaned up and moved
to httpd_SUITE.
---
 lib/inets/src/http_server/httpd.erl         | 12 ++++++----
 lib/inets/src/http_server/httpd_manager.erl | 36 ++++++++++++++---------------
 lib/inets/test/httpd_block.erl              |  6 ++---
 lib/inets/test/old_httpd_SUITE.erl          | 34 ++++++++++++++-------------
 4 files changed, 45 insertions(+), 43 deletions(-)

(limited to 'lib')

diff --git a/lib/inets/src/http_server/httpd.erl b/lib/inets/src/http_server/httpd.erl
index 6052ae9022..e8148ea362 100644
--- a/lib/inets/src/http_server/httpd.erl
+++ b/lib/inets/src/http_server/httpd.erl
@@ -1,7 +1,7 @@
 %%
 %% %CopyrightBegin%
 %%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2014. 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
@@ -294,9 +294,13 @@ do_reload_config(ConfigList, Mode) ->
 	{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);
+	    case block(Address, Port, Mode) of
+		ok ->
+		    reload(Config, Address, Port),
+		    unblock(Address, Port);
+		Error ->
+		    Error
+	    end;
 	Error ->
 	    Error
     end.
diff --git a/lib/inets/src/http_server/httpd_manager.erl b/lib/inets/src/http_server/httpd_manager.erl
index e155498bb8..3da0343401 100644
--- a/lib/inets/src/http_server/httpd_manager.erl
+++ b/lib/inets/src/http_server/httpd_manager.erl
@@ -210,9 +210,10 @@ handle_call({block , Blocker, Mode, Timeout}, From,
 handle_call({block , _, _, _}, _, State) ->
     {reply, {error, blocked}, State};
 
-handle_call({unblock, Blocker}, _, #state{blocker_ref = {Blocker,_},
+handle_call({unblock, Blocker}, _, #state{blocker_ref = {Blocker, Monitor},
 					  admin_state = blocked} = State) ->
-    
+   
+    erlang:demonitor(Monitor),
     {reply, ok, 
      State#state{admin_state = unblocked, blocker_ref = undefined}};
 
@@ -247,37 +248,36 @@ handle_cast(Message, State) ->
 handle_info(connections_terminated, #state{admin_state = shutting_down,
 					   blocking_from = From} = State) ->
     gen_server:reply(From, ok),
-    {noreply, State#state{admin_state = blocked, blocking_from = undefined,
-			  blocker_ref = undefined}};
+    {noreply, State#state{admin_state = blocked, blocking_from = undefined}};
 handle_info(connections_terminated, State) ->
     {noreply, State};
 
-handle_info({block_timeout, non_disturbing}, 
+handle_info({block_timeout, non_disturbing, Blocker}, 
 	    #state{admin_state = shutting_down,
 		   blocking_from = From,
-		   blocker_ref = {_, Monitor}} = State) ->
+		   blocker_ref = {_, Monitor} = Blocker} = State) ->
     erlang:demonitor(Monitor),		  
     gen_server:reply(From, {error, timeout}),
     {noreply, State#state{admin_state = unblocked, blocking_from = undefined,
 			  blocker_ref = undefined}};
-handle_info({block_timeout, disturbing}, 
+handle_info({block_timeout, disturbing, Blocker}, 
 	    #state{admin_state = shutting_down,
 		   blocking_from = From,
-		   blocker_ref = {_, Monitor},
+		   blocker_ref = Blocker,
 		   connection_sup = Sup} = State) ->
     SupPid = whereis(Sup),
     shutdown_connections(SupPid),
-    erlang:demonitor(Monitor),		  
     gen_server:reply(From, ok),
-    {noreply, State#state{admin_state = blocked, blocker_ref = undefined,
+    {noreply, State#state{admin_state = blocked,
 			  blocking_from = undefined}};
 handle_info({block_timeout, _, _}, State) ->
     {noreply, State};	   
 
 handle_info({'DOWN', _, process, Pid, _Info}, 
 	    #state{admin_state = Admin,
-		   blocker_ref = {Pid, _}} = State) when 
+		   blocker_ref = {Pid, Monitor}} = State) when 
       Admin =/= unblocked ->
+    erlang:demonitor(Monitor),	
     {noreply, State#state{admin_state = unblocked,
 			  blocking_from = undefined,
 			  blocker_ref = undefined}};
@@ -333,18 +333,16 @@ handle_new_connection(_UsageState, _AdminState, State, _Handler) ->
 
 handle_block(disturbing, infinity, 
 	     #state{connection_sup = CSup,
-		    blocking_from = From,
-		    blocker_ref = {_, Monitor}} = State) ->
+		    blocking_from = From} = State) ->
     SupPid = whereis(CSup),
     shutdown_connections(SupPid),
-    erlang:demonitor(Monitor),		  
     gen_server:reply(From, ok),
-    {noreply, State#state{admin_state = blocked, blocker_ref = undefined,
+    {noreply, State#state{admin_state = blocked,
 			  blocking_from = undefined}};
-handle_block(disturbing, Timeout, #state{connection_sup = CSup} = State) ->
+handle_block(disturbing, Timeout, #state{connection_sup = CSup, blocker_ref = Blocker} = State) ->
     Manager = self(),
     spawn_link(fun() -> wait_for_shutdown(CSup, Manager) end),
-    erlang:send_after(Timeout, self(), {block_timeout, disturbing}),
+    erlang:send_after(Timeout, self(), {block_timeout, disturbing, Blocker}),
     {noreply, State#state{admin_state = shutting_down}};
 
 handle_block(non_disturbing, infinity, 
@@ -354,10 +352,10 @@ handle_block(non_disturbing, infinity,
     {noreply, State#state{admin_state = shutting_down}};
 
 handle_block(non_disturbing, Timeout,  
-	     #state{connection_sup = CSup} = State) ->
+	     #state{connection_sup = CSup, blocker_ref = Blocker} = State) ->
     Manager = self(),
     spawn_link(fun() -> wait_for_shutdown(CSup, Manager) end),
-    erlang:send_after(Timeout, self(), {block_timeout, non_disturbing}),
+    erlang:send_after(Timeout, self(), {block_timeout, non_disturbing, Blocker}),
     {noreply, State#state{admin_state = shutting_down}}.
     
 handle_reload(undefined, #state{config_file = undefined} = State) ->
diff --git a/lib/inets/test/httpd_block.erl b/lib/inets/test/httpd_block.erl
index 706d014bda..9790623b6f 100644
--- a/lib/inets/test/httpd_block.erl
+++ b/lib/inets/test/httpd_block.erl
@@ -111,8 +111,7 @@ block_disturbing_active_timeout_not_released(Type, Port, Host, Node) ->
     process_flag(trap_exit, true),
     Poller = long_poll(Type, Host, Port, Node, 200, 60000),
     ct:sleep(15000),
-    Blocker = blocker(Node, Host, Port, 50000),
-    await_normal_process_exit(Blocker, "blocker", 50000),
+    ok = httpd_block(undefined,  Port, disturbing, 50000),
     await_normal_process_exit(Poller, "poller", 30000),
     blocked = get_admin_state(Node, Host, Port),
     process_flag(trap_exit, false),
@@ -123,8 +122,7 @@ block_disturbing_active_timeout_released(Type, Port, Host, Node) ->
     process_flag(trap_exit, true),
     Poller = long_poll(Type, Host, Port, Node, 200, 40000),
     ct:sleep(5000),
-    Blocker = blocker(Node, Host, Port, 10000),
-    await_normal_process_exit(Blocker, "blocker", 15000),
+    ok = httpd_block(undefined,  Port, disturbing, 10000),
     await_suite_failed_process_exit(Poller, "poller", 40000, 
 					  connection_closed),
     blocked = get_admin_state(Node, Host, Port),
diff --git a/lib/inets/test/old_httpd_SUITE.erl b/lib/inets/test/old_httpd_SUITE.erl
index 3e1a1a3845..19c2bc129e 100644
--- a/lib/inets/test/old_httpd_SUITE.erl
+++ b/lib/inets/test/old_httpd_SUITE.erl
@@ -182,22 +182,24 @@ groups() ->
        %% ip_load_medium,
        %% ip_load_heavy, 
        %%ip_dos_hostname, 
-       ip_time_test
-       %% Replaced by load_config
-       %% ip_restart_no_block, 
-       %% ip_restart_disturbing_block,
-       %% ip_restart_non_disturbing_block,
-       %% ip_block_disturbing_idle, 
-       %% ip_block_non_disturbing_idle,
-       %% ip_block_503, 
-       %% ip_block_disturbing_active,
-       %% ip_block_non_disturbing_active,
-       %% ip_block_disturbing_active_timeout_not_released,
-       %% ip_block_disturbing_active_timeout_released,
-       %% ip_block_non_disturbing_active_timeout_not_released,
-       %% ip_block_non_disturbing_active_timeout_released,
-       %% ip_block_disturbing_blocker_dies,
-       %% ip_block_non_disturbing_blocker_dies
+       ip_time_test,
+       %% Only used through load_config
+       %% but we still need these tests
+       %% should be cleaned up and moved to new test suite 
+       ip_restart_no_block, 
+       ip_restart_disturbing_block,
+       ip_restart_non_disturbing_block,
+       ip_block_disturbing_idle, 
+       ip_block_non_disturbing_idle,
+       ip_block_503, 
+       ip_block_disturbing_active,
+       ip_block_non_disturbing_active,
+       ip_block_disturbing_active_timeout_not_released,
+       ip_block_disturbing_active_timeout_released,
+       ip_block_non_disturbing_active_timeout_not_released,
+       ip_block_non_disturbing_active_timeout_released,
+       ip_block_disturbing_blocker_dies,
+       ip_block_non_disturbing_blocker_dies
       ]},
      {ssl, [], [{group, essl}]},
      {essl, [],
-- 
cgit v1.2.3


From 3c1cd8121a9aeab7d13fc8de863b7cfabedcc3be Mon Sep 17 00:00:00 2001
From: Erlang/OTP <otp@erlang.org>
Date: Tue, 27 May 2014 13:42:28 +0200
Subject: Update release notes

---
 lib/inets/doc/src/notes.xml | 32 +++++++++++++++++++++++++++++++-
 lib/ssh/doc/src/notes.xml   | 30 ++++++++++++++++++++++++++++++
 2 files changed, 61 insertions(+), 1 deletion(-)

(limited to 'lib')

diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index e29144f014..a69999f30c 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -32,7 +32,37 @@
     <file>notes.xml</file>
   </header>
   
-  <section><title>Inets 5.10</title>
+  <section><title>Inets 5.10.1</title>
+
+    <section><title>Fixed Bugs and Malfunctions</title>
+      <list>
+        <item>
+          <p>
+	    Correct distirbing mode for httpd:reload_config/2</p>
+          <p>
+	    Own Id: OTP-11914</p>
+        </item>
+      </list>
+    </section>
+
+
+    <section><title>Improvements and New Features</title>
+      <list>
+        <item>
+          <p>
+	    Improved handling of invalid strings in the HTTP request
+	    line.</p>
+          <p>
+	    Impact: May improve memory consumption</p>
+          <p>
+	    Own Id: OTP-11925 Aux Id: Sequence 12601 </p>
+        </item>
+      </list>
+    </section>
+
+</section>
+
+<section><title>Inets 5.10</title>
 
     <section><title>Fixed Bugs and Malfunctions</title>
       <list>
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index bce02966ae..f455ec1eba 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -29,6 +29,36 @@
     <file>notes.xml</file>
   </header>
 
+<section><title>Ssh 3.0.2</title>
+
+    <section><title>Fixed Bugs and Malfunctions</title>
+      <list>
+        <item>
+          <p>
+	    Fixed timeout bug in ssh:connect.</p>
+          <p>
+	    Own Id: OTP-11908</p>
+        </item>
+      </list>
+    </section>
+
+
+    <section><title>Improvements and New Features</title>
+      <list>
+        <item>
+          <p>
+	    Option <c>max_sessions</c> added to
+	    <c>ssh:daemon/{2,3}</c>. This option, if set, limits the
+	    number of simultaneous connections accepted by the
+	    daemon.</p>
+          <p>
+	    Own Id: OTP-11885</p>
+        </item>
+      </list>
+    </section>
+
+</section>
+
 <section><title>Ssh 3.0.1</title>
 
     <section><title>Fixed Bugs and Malfunctions</title>
-- 
cgit v1.2.3