X-Original-To: alpine-aports@lists.alpinelinux.org Received: from mail-qk0-f193.google.com (mail-qk0-f193.google.com [209.85.220.193]) by lists.alpinelinux.org (Postfix) with ESMTP id B9D3D5C411B for ; Sun, 19 Jun 2016 22:46:37 +0000 (GMT) Received: by mail-qk0-f193.google.com with SMTP id a186so20679188qkf.0 for ; Sun, 19 Jun 2016 15:46:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:subject:date:message-id; bh=Git86uduH/7rXdfZVoODsaLrDTQCLVbBKXsGdpBD03w=; b=zHkByFfBe2NV747g6Jj5NVGTZKo9WiR0TgRsEBzmdJNjs+aOCgRnGXeGdDTexnluZh bI6XJ3h8Q2WxTLrELMHcjOaloW2hyWdGjfvcHqrLaLZkhykWfOv3cEETtXBnT9un57yT 81C3XIjQ9YDg0fbvycQiWIcDGC6KgS4esQblAnDR83J32YmT3lrBuffabTL6PE/MVTnl P7hTFgI6Ov/W2YiKwIRzafcGLrROTzSrzDoSk3e8X/Abr1JehELhDDH/fB/jRVm10hiV AG+UpiS0x5e9objnttpnVoinafd9yjmVhjqg7XYF66gvjHPsQBVlvj8E0sqQe8U7cmO6 3Peg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:subject:date:message-id; bh=Git86uduH/7rXdfZVoODsaLrDTQCLVbBKXsGdpBD03w=; b=M/T333o+7zCcvUI3K261dHnepp32fGMB7gHCuURtmefEjMClv8Y9hK2ae2AH8RudsY nRjeXJrRvxnbO1/EzKTbJrRy3mgVylmOmm3k9f+QzRbHdFpgT6ikhDLevGW1OSfvmxWw BkEJ05UbU2yFMD8xqSgEnJdPvZMcjsdwhTzpNmAVF3iVJ1tQ8tlrBcyOh+FQFnlhny75 EEmXbdJ2r7vbgwhgD30bkxJv521xvyLdQnh4g5H981FqIjBIq912tfK3EM1qtlA1+RpM oHPaLkmuZhctcZmHwkOTC9kBhnPXdX8ZXXtq05gn/Qo/p3LlxuFJuJpNxj09Us+5U4it E29w== X-Gm-Message-State: ALyK8tKTm87pSP9wmcxMKNCt6LMQOMDTEGA5F4Mpqxc2pxtlk8CwS3RGxWvPYhW7wzbFfQ== X-Received: by 10.55.100.75 with SMTP id y72mr18289480qkb.106.1466376394585; Sun, 19 Jun 2016 15:46:34 -0700 (PDT) Received: from d4f5457fab20.ec2.internal (ec2-54-173-137-211.compute-1.amazonaws.com. [54.173.137.211]) by smtp.gmail.com with ESMTPSA id o27sm15561501qto.29.2016.06.19.15.46.33 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sun, 19 Jun 2016 15:46:33 -0700 (PDT) From: Marlus Saraiva To: alpine-aports@lists.alpinelinux.org Subject: [alpine-aports] [PATCH] community/erlang: upgrade to 18.3.4 Date: Sun, 19 Jun 2016 22:46:29 +0000 Message-Id: <20160619224629.14933-1-marlus.saraiva@gmail.com> X-Mailer: git-send-email 2.9.0 X-Mailinglist: alpine-aports Precedence: list List-Id: Alpine Development List-Unsubscribe: List-Post: List-Help: List-Subscribe: --- .../erlang/0080-otp-update-version-18.3.4.patch | 2964 ++++++++++++++++++++ community/erlang/APKBUILD | 14 +- 2 files changed, 2973 insertions(+), 5 deletions(-) create mode 100644 community/erlang/0080-otp-update-version-18.3.4.patch diff --git a/community/erlang/0080-otp-update-version-18.3.4.patch b/community/erlang/0080-otp-update-version-18.3.4.patch new file mode 100644 index 0000000..cd669f0 --- /dev/null +++ b/community/erlang/0080-otp-update-version-18.3.4.patch @@ -0,0 +1,2964 @@ +--- a/OTP_VERSION ++++ b/OTP_VERSION +@@ -1 +1 @@ +-18.3.2 ++18.3.4 +--- a/lib/common_test/doc/src/ct.xml ++++ b/lib/common_test/doc/src/ct.xml +@@ -601,18 +601,21 @@ + + + +- get_timetrap_info() -> {Time, Scale} ++ get_timetrap_info() -> {Time, {Scaling,ScaleVal}} + Reads information about the timetrap set for the current + test case. + + Time = integer() | infinity +- Scale = true | false ++ Scaling = true | false ++ ScaleVal = integer() + + +

Reads information about the timetrap set for the current test +- case. Scale indicates if Common Test will attempt ++ case. Scaling indicates if Common Test will attempt + to compensate timetraps automatically for runtime delays +- introduced by, for example, tools like cover.

++ introduced by, for example, tools like cover. ScaleVal is ++ the value of the current scaling multipler (always 1 if scaling is ++ disabled). Note the Time is not the scaled result.

+
+
+ +@@ -1136,7 +1139,7 @@ + Opts. + + Opts = [OptTuples] +- OptTuples = {dir, TestDirs} | {suite, Suites} | {group, Groups} | {testcase, Cases} | {spec, TestSpecs} | {join_specs, Bool} | {label, Label} | {config, CfgFiles} | {userconfig, UserConfig} | {allow_user_terms, Bool} | {logdir, LogDir} | {silent_connections, Conns} | {stylesheet, CSSFile} | {cover, CoverSpecFile} | {cover_stop, Bool} | {step, StepOpts} | {event_handler, EventHandlers} | {include, InclDirs} | {auto_compile, Bool} | {abort_if_missing_suites, Bool} | {create_priv_dir, CreatePrivDir} | {multiply_timetraps, M} | {scale_timetraps, Bool} | {repeat, N} | {duration, DurTime} | {until, StopTime} | {force_stop, ForceStop} | {decrypt, DecryptKeyOrFile} | {refresh_logs, LogDir} | {logopts, LogOpts} | {verbosity, VLevels} | {basic_html, Bool} | {ct_hooks, CTHs} | {enable_builtin_hooks, Bool} | {release_shell, Bool} ++ OptTuples = {dir, TestDirs} | {suite, Suites} | {group, Groups} | {testcase, Cases} | {spec, TestSpecs} | {join_specs, Bool} | {label, Label} | {config, CfgFiles} | {userconfig, UserConfig} | {allow_user_terms, Bool} | {logdir, LogDir} | {silent_connections, Conns} | {stylesheet, CSSFile} | {cover, CoverSpecFile} | {cover_stop, Bool} | {step, StepOpts} | {event_handler, EventHandlers} | {include, InclDirs} | {auto_compile, Bool} | {abort_if_missing_suites, Bool} | {create_priv_dir, CreatePrivDir} | {multiply_timetraps, M} | {scale_timetraps, Bool} | {repeat, N} | {duration, DurTime} | {until, StopTime} | {force_stop, ForceStop} | {decrypt, DecryptKeyOrFile} | {refresh_logs, LogDir} | {logopts, LogOpts} | {verbosity, VLevels} | {basic_html, Bool} | {esc_chars, Bool} | {ct_hooks, CTHs} | {enable_builtin_hooks, Bool} | {release_shell, Bool} + TestDirs = [string()] | string() + Suites = [string()] | [atom()] | string() | atom() + Cases = [atom()] | atom() +--- a/lib/common_test/doc/src/ct_run.xml ++++ b/lib/common_test/doc/src/ct_run.xml +@@ -124,6 +124,7 @@ + [-duration HHMMSS [-force_stop [skip_rest]]] | + [-until [YYMoMoDD]HHMMSS [-force_stop [skip_rest]]] + [-basic_html] ++ [-no_esc_chars] + [-ct_hooks CTHModule1 CTHOpts1 and CTHModule2 CTHOpts2 and .. + CTHModuleN CTHOptsN] + [-exit_status ignore_config] +@@ -162,6 +163,7 @@ + [-duration HHMMSS [-force_stop [skip_rest]]] | + [-until [YYMoMoDD]HHMMSS [-force_stop [skip_rest]]] + [-basic_html] ++ [-no_esc_chars] + [-ct_hooks CTHModule1 CTHOpts1 and CTHModule2 CTHOpts2 and .. + CTHModuleN CTHOptsN] + [-exit_status ignore_config] +@@ -186,7 +188,8 @@ + [-muliply_timetraps Multiplier] + [-scale_timetraps] + [-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc] +- [-basic_html] ++ [-basic_html] ++ [-no_esc_chars] + + +
+--- a/lib/common_test/doc/src/ct_telnet.xml ++++ b/lib/common_test/doc/src/ct_telnet.xml +@@ -64,6 +64,8 @@ + remaining string terminated) = 0

+

Polling interval (sleep time between polls) = 1 second

+
++

The TCP_NODELAY option for the telnet socket ++ is disabled (set to false) per default

+ + +

These parameters can be modified by the user with the following +@@ -76,7 +78,8 @@ + {reconnection_interval,Millisec}, + {keep_alive,Bool}, + {poll_limit,N}, +- {poll_interval,Millisec}]}. ++ {poll_interval,Millisec}, ++ {tcp_nodelay,Bool}]}. + +

Millisec = integer(), N = integer()

+ +--- a/lib/common_test/doc/src/notes.xml ++++ b/lib/common_test/doc/src/notes.xml +@@ -33,6 +33,68 @@ + notes.xml + + ++
Common_Test 1.12.1 ++ ++
Fixed Bugs and Malfunctions ++ ++ ++

++ The nodelay option used to be enabled ++ (true) by default for sockets opened by the Common ++ Test telnet client. This appeared to cause communication ++ problems with telnet servers on some systems, and ++ therefore the option is no longer used. Its value may ++ instead be specified in the telnet connection settings. ++ See the man page for ct_telnet for details. Please ++ note that the interface function connect in ++ unix_telnet has been updated with an extra ++ argument and is now unix_telnet:connect/7.

++

++ Own Id: OTP-13462 Aux Id: seq13077

++
++ ++

++ Fix bug in cth_surefire: When a pre_init_per_suite hook ++ fails before reaching the ++ cth_surefire:pre_init_per_suite, cth_surefire produced ++ incorrect XML.

++

++ Own Id: OTP-13513

++
++ ++

++ The ct:get_timetrap_info/0 function has been ++ updated to return more information about timetrap ++ scaling.

++

++ Own Id: OTP-13535

++
++ ++

++ A problem with stylesheet HTML tags getting incorrectly ++ escaped by Common Test has been corrected.

++

++ Own Id: OTP-13536

++
++ ++

++ The ct_run start flag -no_esc_chars and ++ ct:run_test/1 start option {esc_chars,Bool} ++ have been introduced to make it possible to disable ++ automatic escaping of characters. Automatic escaping of ++ special HTML characters printed with io:format/1,2 ++ and ct:pal/1,2,3,4 was introduced in Common Test ++ 1.12. The new flag/option may be used to disable this ++ feature for backwards compatibility reasons. (The option ++ is also supported in test specifications).

++

++ Own Id: OTP-13537

++
++
++
++ ++
++ +
Common_Test 1.12 + +
Fixed Bugs and Malfunctions +--- a/lib/common_test/doc/src/run_test_chapter.xml ++++ b/lib/common_test/doc/src/run_test_chapter.xml +@@ -266,6 +266,10 @@ + ]]> +

Sets verbosity levels + for printouts.

++ ++ ++

Disables automatic escaping of special HTML characters. ++ See the Logging chapter.

+ + +

Directories passed to Common Test can have either relative or absolute paths.

+@@ -802,7 +806,7 @@ + program for an overview of available start flags + (as most flags have a corresponding configuration term) + Logging +- (for terms verbosity, stylesheet and basic_html) ++ (for terms verbosity, stylesheet, basic_html and esc_chars) + External Configuration Data + (for terms config and userconfig) + Event +@@ -887,6 +891,9 @@ + {basic_html, Bool}. + {basic_html, NodeRefs, Bool}. + ++ {esc_chars, Bool}. ++ {esc_chars, NodeRefs, Bool}. ++ + {release_shell, Bool}. + +

Test terms:

+--- a/lib/common_test/doc/src/unix_telnet.xml ++++ b/lib/common_test/doc/src/unix_telnet.xml +@@ -80,7 +80,7 @@ + + + +- connect(ConnName, Ip, Port, Timeout, KeepAlive, Extra) -> {ok, Handle} | {error, Reason} ++ connect(ConnName, Ip, Port, Timeout, KeepAlive, TCPNoDelay, Extra) -> {ok, Handle} | {error, Reason} + Callback for ct_telnet.erl. + + ConnName = target_name() +@@ -88,6 +88,7 @@ + Port = integer() + Timeout = integer() + KeepAlive = bool() ++ TCPNoDelay = bool() + Extra = target_name() | {Username, Password} + Username = string() + Password = string() +--- a/lib/common_test/doc/src/write_test_chapter.xml ++++ b/lib/common_test/doc/src/write_test_chapter.xml +@@ -1047,9 +1047,15 @@ + +

Common Test will escape special HTML characters (<, > and &) in printouts + to the log file made with ct:pal/4 and io:format/2. In order to print +- strings with HTML tags to the log, use the ct:log/5 function. The character escaping +- feature is per default disabled for ct:log/5, but can be enabled with the +- esc_chars option.

++ strings with HTML tags to the log, use the ct:log/3,4,5 function. The character ++ escaping feature is per default disabled for ct:log/3,4,5 but can be enabled with ++ the esc_chars option in the Opts list, see ++ ct:log/3,4,5.

++ ++

If the character escaping feature needs to be disabled (typically for backwards ++ compatibility reasons), use the ct_run start flag -no_esc_chars, or the ++ ct:run_test/1 start option {esc_chars,Bool} (this start option is also ++ supported in test specifications).

+ +

For more information about log files, see section + Log Files +--- a/lib/common_test/src/ct.erl ++++ b/lib/common_test/src/ct.erl +@@ -161,9 +161,9 @@ run(TestDirs) -> + %%% {repeat,N} | {duration,DurTime} | {until,StopTime} | + %%% {force_stop,ForceStop} | {decrypt,DecryptKeyOrFile} | + %%% {refresh_logs,LogDir} | {logopts,LogOpts} | +-%%% {verbosity,VLevels} | {basic_html,Bool} | +-%%% {ct_hooks, CTHs} | {enable_builtin_hooks,Bool} | +-%%% {release_shell,Bool} ++%%% {verbosity,VLevels} | {basic_html,Bool} | ++%%% {esc_chars,Bool} | {ct_hooks, CTHs} | ++%%% {enable_builtin_hooks,Bool} | {release_shell,Bool} + %%% TestDirs = [string()] | string() + %%% Suites = [string()] | [atom()] | string() | atom() + %%% Cases = [atom()] | atom() +--- a/lib/common_test/src/ct_groups.erl ++++ b/lib/common_test/src/ct_groups.erl +@@ -325,7 +325,7 @@ modify_tc_list1(GrSpecTs, TSCs) -> + true -> + {[TC|TSCs1],lists:delete(TC,GrSpecTs2)}; + false -> +- case lists:keymember(TC, 2, GrSpecTs) of ++ case lists:keysearch(TC, 2, GrSpecTs) of + {value,Test} -> + {[Test|TSCs1], + lists:keydelete(TC, 2, GrSpecTs2)}; +--- a/lib/common_test/src/ct_hooks.erl ++++ b/lib/common_test/src/ct_hooks.erl +@@ -67,6 +67,8 @@ terminate(Hooks) -> + %% tests. + -spec init_tc(Mod :: atom(), + FuncSpec :: atom() | ++ {ConfigFunc :: init_per_testcase | end_per_testcase, ++ TestCase :: atom()} | + {ConfigFunc :: init_per_group | end_per_group, + GroupName :: atom(), + Properties :: list()}, +@@ -103,7 +105,9 @@ init_tc(_Mod, TC = error_in_suite, Config) -> + %% @doc Called as each test case is completed. This includes all configuration + %% tests. + -spec end_tc(Mod :: atom(), +- FuncSpec :: atom() | ++ FuncSpec :: atom() | ++ {ConfigFunc :: init_per_testcase | end_per_testcase, ++ TestCase :: atom()} | + {ConfigFunc :: init_per_group | end_per_group, + GroupName :: atom(), + Properties :: list()}, +--- a/lib/common_test/src/ct_logs.erl ++++ b/lib/common_test/src/ct_logs.erl +@@ -609,7 +609,8 @@ log_timestamp({MS,S,US}) -> + ct_log_fd, + tc_groupleaders, + stylesheet, +- async_print_jobs}). ++ async_print_jobs, ++ tc_esc_chars}). + + logger(Parent, Mode, Verbosity) -> + register(?MODULE,self()), +@@ -728,14 +729,18 @@ logger(Parent, Mode, Verbosity) -> + end + end || {Cat,VLvl} <- Verbosity], + io:nl(CtLogFd), +- ++ TcEscChars = case application:get_env(common_test, esc_chars) of ++ {ok,ECBool} -> ECBool; ++ _ -> true ++ end, + logger_loop(#logger_state{parent=Parent, + log_dir=AbsDir, + start_time=Time, + orig_GL=group_leader(), + ct_log_fd=CtLogFd, + tc_groupleaders=[], +- async_print_jobs=[]}). ++ async_print_jobs=[], ++ tc_esc_chars=TcEscChars}). + + copy_priv_files([SrcF | SrcFs], [DestF | DestFs]) -> + case file:copy(SrcF, DestF) of +@@ -761,20 +766,21 @@ logger_loop(State) -> + end, + if Importance >= (100-VLvl) -> + CtLogFd = State#logger_state.ct_log_fd, ++ DoEscChars = State#logger_state.tc_esc_chars and EscChars, + case get_groupleader(Pid, GL, State) of + {tc_log,TCGL,TCGLs} -> + case erlang:is_process_alive(TCGL) of + true -> + State1 = print_to_log(SyncOrAsync, Pid, + Category, TCGL, Content, +- EscChars, State), ++ DoEscChars, State), + logger_loop(State1#logger_state{ + tc_groupleaders = TCGLs}); + false -> + %% Group leader is dead, so write to the + %% CtLog or unexpected_io log instead + unexpected_io(Pid, Category, Importance, +- Content, CtLogFd, EscChars), ++ Content, CtLogFd, DoEscChars), + + logger_loop(State) + end; +@@ -783,7 +789,7 @@ logger_loop(State) -> + %% to ct_log, else write to unexpected_io + %% log + unexpected_io(Pid, Category, Importance, Content, +- CtLogFd, EscChars), ++ CtLogFd, DoEscChars), + logger_loop(State#logger_state{ + tc_groupleaders = TCGLs}) + end; +@@ -794,7 +800,7 @@ logger_loop(State) -> + %% make sure no IO for this test case from the + %% CT logger gets rejected + test_server:permit_io(GL, self()), +- print_style(GL, State#logger_state.stylesheet), ++ print_style(GL,GL,State#logger_state.stylesheet), + set_evmgr_gl(GL), + TCGLs = add_tc_gl(TCPid,GL,State), + if not RefreshLog -> +@@ -882,7 +888,7 @@ create_io_fun(FromPid, CtLogFd, EscChars) -> + {_HdOrFt,S,A} -> {false,S,A}; + {S,A} -> {true,S,A} + end, +- try io_lib:format(Str,Args) of ++ try io_lib:format(Str, Args) of + IoStr when Escapable, EscChars, IoList == [] -> + escape_chars(IoStr); + IoStr when Escapable, EscChars -> +@@ -925,7 +931,12 @@ print_to_log(sync, FromPid, Category, TCGL, Content, EscChars, State) -> + if FromPid /= TCGL -> + IoFun = create_io_fun(FromPid, CtLogFd, EscChars), + IoList = lists:foldl(IoFun, [], Content), +- io:format(TCGL,["$tc_html","~ts"], [IoList]); ++ try io:format(TCGL,["$tc_html","~ts"], [IoList]) of ++ ok -> ok ++ catch ++ _:_ -> ++ io:format(TCGL,"~ts", [IoList]) ++ end; + true -> + unexpected_io(FromPid, Category, ?MAX_IMPORTANCE, Content, + CtLogFd, EscChars) +@@ -958,7 +969,10 @@ print_to_log(async, FromPid, Category, TCGL, Content, EscChars, State) -> + _:terminated -> + unexpected_io(FromPid, Category, + ?MAX_IMPORTANCE, +- Content, CtLogFd, EscChars) ++ Content, CtLogFd, EscChars); ++ _:_ -> ++ io:format(TCGL, "~ts", ++ [lists:foldl(IoFun,[],Content)]) + end; + false -> + unexpected_io(FromPid, Category, +@@ -1099,26 +1113,27 @@ open_ctlog(MiscIoName) -> + "View I/O logged after the test run\n\n", + [MiscIoName,MiscIoName]), + +- print_style(Fd,undefined), ++ print_style(Fd,group_leader(),undefined), + io:format(Fd, + xhtml("

Progress Log

\n
\n",
+ 		    "
\n

PROGRESS LOG

\n
\n"), []),
+     Fd.
+ 
+-print_style(Fd,undefined) ->
++print_style(Fd,GL,undefined) ->
+     case basic_html() of
+ 	true ->
+-	    io:format(Fd,
+-		      "\n",
+-		      []);
++	    Style = "\n",
++	    if Fd == GL -> io:format(["$tc_html",Style], []);
++	       true     -> io:format(Fd, Style, [])
++	    end;
+ 	_ ->
+ 	    ok
+     end;
+ 
+-print_style(Fd,StyleSheet) ->
++print_style(Fd,GL,StyleSheet) ->
+     case file:read_file(StyleSheet) of
+ 	{ok,Bin} ->
+ 	    Str = b2s(Bin,encoding(StyleSheet)),
+@@ -1131,23 +1146,30 @@ print_style(Fd,StyleSheet) ->
+ 		       N1 -> N1
+ 		   end,
+ 	    if (Pos0 == 0) and (Pos1 /= 0) ->
+-		    print_style_error(Fd,StyleSheet,missing_style_start_tag);
++		    print_style_error(Fd,GL,StyleSheet,missing_style_start_tag);
+ 	       (Pos0 /= 0) and (Pos1 == 0) ->
+-		    print_style_error(Fd,StyleSheet,missing_style_end_tag);
++		    print_style_error(Fd,GL,StyleSheet,missing_style_end_tag);
+ 	       Pos0 /= 0 ->
+ 		    Style = string:sub_string(Str,Pos0,Pos1+7),
+-		    io:format(Fd,"~ts\n",[Style]);
++		    if Fd == GL -> io:format(Fd,["$tc_html","~ts\n"],[Style]);
++		       true     -> io:format(Fd,"~ts\n",[Style])
++		    end;
+ 	       Pos0 == 0 ->
+-		    io:format(Fd,"\n",[Str])
++		    if Fd == GL -> io:format(Fd,["$tc_html","\n"],[Str]);
++		       true     -> io:format(Fd,"\n",[Str])
++		    end
+ 	    end;
+ 	{error,Reason} ->
+-	    print_style_error(Fd,StyleSheet,Reason)  
++	    print_style_error(Fd,GL,StyleSheet,Reason)  
+     end.
+ 
+-print_style_error(Fd,StyleSheet,Reason) ->
+-    io:format(Fd,"\n\n",
+-	      [StyleSheet,Reason]),
+-    print_style(Fd,undefined).    
++print_style_error(Fd,GL,StyleSheet,Reason) ->
++    IO = io_lib:format("\n\n",
++		       [StyleSheet,Reason]),
++    if Fd == GL -> io:format(Fd,["$tc_html",IO],[]);
++       true     -> io:format(Fd,IO,[])
++    end,
++    print_style(Fd,GL,undefined).    
+ 
+ close_ctlog(Fd) ->
+     io:format(Fd, "\n
\n", []), +--- a/lib/common_test/src/ct_master.erl ++++ b/lib/common_test/src/ct_master.erl +@@ -27,7 +27,7 @@ + -export([run_on_node/2,run_on_node/3]). + -export([run_test/1,run_test/2]). + -export([get_event_mgr_ref/0]). +--export([basic_html/1]). ++-export([basic_html/1,esc_chars/1]). + + -export([abort/0,abort/1,progress/0]). + +@@ -317,6 +317,16 @@ basic_html(Bool) -> + ok. + + %%%----------------------------------------------------------------- ++%%% @spec esc_chars(Bool) -> ok ++%%% Bool = true | false ++%%% ++%%% @doc If set to false, the ct_master logs will be written without ++%%% special characters being escaped in the HTML logs. ++esc_chars(Bool) -> ++ application:set_env(common_test_master, esc_chars, Bool), ++ ok. ++ ++%%%----------------------------------------------------------------- + %%% MASTER, runs on central controlling node. + %%%----------------------------------------------------------------- + start_master(NodeOptsList) -> +--- a/lib/common_test/src/ct_run.erl ++++ b/lib/common_test/src/ct_run.erl +@@ -65,6 +65,7 @@ + logdir, + logopts = [], + basic_html, ++ esc_chars = true, + verbosity = [], + config = [], + event_handlers = [], +@@ -346,6 +347,15 @@ script_start1(Parent, Args) -> + application:set_env(common_test, basic_html, true), + true + end, ++ %% esc_chars - used by ct_logs ++ EscChars = case proplists:get_value(no_esc_chars, Args) of ++ undefined -> ++ application:set_env(common_test, esc_chars, true), ++ undefined; ++ _ -> ++ application:set_env(common_test, esc_chars, false), ++ false ++ end, + %% disable_log_cache - used by ct_logs + case proplists:get_value(disable_log_cache, Args) of + undefined -> +@@ -359,6 +369,7 @@ script_start1(Parent, Args) -> + cover = Cover, cover_stop = CoverStop, + logdir = LogDir, logopts = LogOpts, + basic_html = BasicHtml, ++ esc_chars = EscChars, + verbosity = Verbosity, + event_handlers = EvHandlers, + ct_hooks = CTHooks, +@@ -587,6 +598,17 @@ combine_test_opts(TS, Specs, Opts) -> + BHBool + end, + ++ EscChars = ++ case choose_val(Opts#opts.esc_chars, ++ TSOpts#opts.esc_chars) of ++ undefined -> ++ true; ++ ECBool -> ++ application:set_env(common_test, esc_chars, ++ ECBool), ++ ECBool ++ end, ++ + Opts#opts{label = Label, + profile = Profile, + testspec_files = Specs, +@@ -595,6 +617,7 @@ combine_test_opts(TS, Specs, Opts) -> + logdir = which(logdir, LogDir), + logopts = AllLogOpts, + basic_html = BasicHtml, ++ esc_chars = EscChars, + verbosity = AllVerbosity, + silent_connections = AllSilentConns, + config = TSOpts#opts.config, +@@ -795,6 +818,7 @@ script_usage() -> + "\n\t [-scale_timetraps]" + "\n\t [-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]" + "\n\t [-basic_html]" ++ "\n\t [-no_esc_chars]" + "\n\t [-repeat N] |" + "\n\t [-duration HHMMSS [-force_stop [skip_rest]]] |" + "\n\t [-until [YYMoMoDD]HHMMSS [-force_stop [skip_rest]]]" +@@ -822,6 +846,7 @@ script_usage() -> + "\n\t [-scale_timetraps]" + "\n\t [-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]" + "\n\t [-basic_html]" ++ "\n\t [-no_esc_chars]" + "\n\t [-repeat N] |" + "\n\t [-duration HHMMSS [-force_stop [skip_rest]]] |" + "\n\t [-until [YYMoMoDD]HHMMSS [-force_stop [skip_rest]]]\n\n"), +@@ -847,7 +872,8 @@ script_usage() -> + "\n\t [-multiply_timetraps N]" + "\n\t [-scale_timetraps]" + "\n\t [-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]" +- "\n\t [-basic_html]\n\n"). ++ "\n\t [-basic_html]" ++ "\n\t [-no_esc_chars]\n\n"). + + %%%----------------------------------------------------------------- + %%% @hidden +@@ -1089,7 +1115,17 @@ run_test2(StartOpts) -> + application:set_env(common_test, basic_html, BasicHtmlBool), + BasicHtmlBool + end, +- ++ %% esc_chars - used by ct_logs ++ EscChars = ++ case proplists:get_value(esc_chars, StartOpts) of ++ undefined -> ++ application:set_env(common_test, esc_chars, true), ++ undefined; ++ EscCharsBool -> ++ application:set_env(common_test, esc_chars, EscCharsBool), ++ EscCharsBool ++ end, ++ %% disable_log_cache - used by ct_logs + case proplists:get_value(disable_log_cache, StartOpts) of + undefined -> + application:set_env(common_test, disable_log_cache, false); +@@ -1104,6 +1140,7 @@ run_test2(StartOpts) -> + cover = Cover, cover_stop = CoverStop, + step = Step, logdir = LogDir, + logopts = LogOpts, basic_html = BasicHtml, ++ esc_chars = EscChars, + config = CfgFiles, + verbosity = Verbosity, + event_handlers = EvHandlers, +@@ -1445,6 +1482,7 @@ get_data_for_node(#testspec{label = Labels, + logdir = LogDirs, + logopts = LogOptsList, + basic_html = BHs, ++ esc_chars = EscChs, + stylesheet = SSs, + verbosity = VLvls, + silent_connections = SilentConnsList, +@@ -1472,6 +1510,7 @@ get_data_for_node(#testspec{label = Labels, + LOs -> LOs + end, + BasicHtml = proplists:get_value(Node, BHs), ++ EscChars = proplists:get_value(Node, EscChs), + Stylesheet = proplists:get_value(Node, SSs), + Verbosity = case proplists:get_value(Node, VLvls) of + undefined -> []; +@@ -1498,6 +1537,7 @@ get_data_for_node(#testspec{label = Labels, + logdir = LogDir, + logopts = LogOpts, + basic_html = BasicHtml, ++ esc_chars = EscChars, + stylesheet = Stylesheet, + verbosity = Verbosity, + silent_connections = SilentConns, +@@ -2182,10 +2222,18 @@ do_run_test(Tests, Skip, Opts0) -> + %% test_server needs to know the include path too + InclPath = case application:get_env(common_test, include) of + {ok,Incls} -> Incls; +- _ -> [] ++ _ -> [] + end, + application:set_env(test_server, include, InclPath), + ++ %% copy the escape characters setting to test_server ++ EscChars = ++ case application:get_env(common_test, esc_chars) of ++ {ok,ECBool} -> ECBool; ++ _ -> true ++ end, ++ application:set_env(test_server, esc_chars, EscChars), ++ + test_server_ctrl:start_link(local), + + %% let test_server expand the test tuples and count no of cases +@@ -3071,6 +3119,10 @@ opts2args(EnvStartOpts) -> + [{basic_html,[]}]; + ({basic_html,false}) -> + []; ++ ({esc_chars,false}) -> ++ [{no_esc_chars,[]}]; ++ ({esc_chars,true}) -> ++ []; + ({event_handler,EH}) when is_atom(EH) -> + [{event_handler,[atom_to_list(EH)]}]; + ({event_handler,EHs}) when is_list(EHs) -> +--- a/lib/common_test/src/ct_telnet.erl ++++ b/lib/common_test/src/ct_telnet.erl +@@ -42,7 +42,8 @@ + %% {reconnection_interval,Millisec}, + %% {keep_alive,Bool}, + %% {poll_limit,N}, +-%% {poll_interval,Millisec}]}.
++%% {poll_interval,Millisec}, ++%% {tcp_nodelay,Bool}]}. + %%

Millisec = integer(), N = integer()

+ %%

Enter the telnet_settings term in a configuration + %% file included in the test and ct_telnet will retrieve the information +@@ -182,7 +183,8 @@ + conn_to=?DEFAULT_TIMEOUT, + com_to=?DEFAULT_TIMEOUT, + reconns=?RECONNS, +- reconn_int=?RECONN_TIMEOUT}). ++ reconn_int=?RECONN_TIMEOUT, ++ tcp_nodelay=false}). + + %%%----------------------------------------------------------------- + %%% @spec open(Name) -> {ok,Handle} | {error,Reason} +@@ -602,8 +604,18 @@ init(Name,{Ip,Port,Type},{TargetMod,KeepAlive,Extra}) -> + Settings -> + set_telnet_defaults(Settings,#state{}) + end, +- case catch TargetMod:connect(Name,Ip,Port,S0#state.conn_to, +- KeepAlive,Extra) of ++ %% Handle old user versions of TargetMod ++ code:ensure_loaded(TargetMod), ++ try ++ case erlang:function_exported(TargetMod,connect,7) of ++ true -> ++ TargetMod:connect(Name,Ip,Port,S0#state.conn_to, ++ KeepAlive,S0#state.tcp_nodelay,Extra); ++ false -> ++ TargetMod:connect(Name,Ip,Port,S0#state.conn_to, ++ KeepAlive,Extra) ++ end ++ of + {ok,TelnPid} -> + put({ct_telnet_pid2name,TelnPid},Name), + S1 = S0#state{host=Ip, +@@ -625,15 +637,18 @@ init(Name,{Ip,Port,Type},{TargetMod,KeepAlive,Extra}) -> + "Connection timeout: ~p\n" + "Keep alive: ~w\n" + "Poll limit: ~w\n" +- "Poll interval: ~w", ++ "Poll interval: ~w\n" ++ "TCP nodelay: ~w", + [Ip,Port,S1#state.com_to,S1#state.reconns, + S1#state.reconn_int,S1#state.conn_to,KeepAlive, +- S1#state.poll_limit,S1#state.poll_interval]), ++ S1#state.poll_limit,S1#state.poll_interval, ++ S1#state.tcp_nodelay]), + {ok,TelnPid,S1}; +- {'EXIT',Reason} -> +- {error,Reason}; + Error -> + Error ++ catch ++ _:Reason -> ++ {error,Reason} + end. + + type(telnet) -> ip; +@@ -653,6 +668,8 @@ set_telnet_defaults([{poll_limit,PL}|Ss],S) -> + set_telnet_defaults(Ss,S#state{poll_limit=PL}); + set_telnet_defaults([{poll_interval,PI}|Ss],S) -> + set_telnet_defaults(Ss,S#state{poll_interval=PI}); ++set_telnet_defaults([{tcp_nodelay,NoDelay}|Ss],S) -> ++ set_telnet_defaults(Ss,S#state{tcp_nodelay=NoDelay}); + set_telnet_defaults([Unknown|Ss],S) -> + force_log(S,error, + "Bad element in telnet_settings: ~p",[Unknown]), +@@ -794,8 +811,17 @@ reconnect(Ip,Port,N,State=#state{name=Name, + keep_alive=KeepAlive, + extra=Extra, + conn_to=ConnTo, +- reconn_int=ReconnInt}) -> +- case TargetMod:connect(Name,Ip,Port,ConnTo,KeepAlive,Extra) of ++ reconn_int=ReconnInt, ++ tcp_nodelay=NoDelay}) -> ++ %% Handle old user versions of TargetMod ++ ConnResult = ++ case erlang:function_exported(TargetMod,connect,7) of ++ true -> ++ TargetMod:connect(Name,Ip,Port,ConnTo,KeepAlive,NoDelay,Extra); ++ false -> ++ TargetMod:connect(Name,Ip,Port,ConnTo,KeepAlive,Extra) ++ end, ++ case ConnResult of + {ok,NewPid} -> + put({ct_telnet_pid2name,NewPid},Name), + {ok, NewPid, State#state{teln_pid=NewPid}}; +--- a/lib/common_test/src/ct_telnet_client.erl ++++ b/lib/common_test/src/ct_telnet_client.erl +@@ -35,7 +35,7 @@ + + %%-define(debug, true). + +--export([open/2, open/3, open/4, open/5, close/1]). ++-export([open/2, open/3, open/4, open/5, open/6, close/1]). + -export([send_data/2, send_data/3, get_data/1]). + + -define(TELNET_PORT, 23). +@@ -70,19 +70,22 @@ + -record(state,{conn_name, get_data, keep_alive=true, log_pos=1}). + + open(Server, ConnName) -> +- open(Server, ?TELNET_PORT, ?OPEN_TIMEOUT, true, ConnName). ++ open(Server, ?TELNET_PORT, ?OPEN_TIMEOUT, true, false, ConnName). + + open(Server, Port, ConnName) -> +- open(Server, Port, ?OPEN_TIMEOUT, true, ConnName). ++ open(Server, Port, ?OPEN_TIMEOUT, true, false, ConnName). + + open(Server, Port, Timeout, ConnName) -> +- open(Server, Port, Timeout, true, ConnName). ++ open(Server, Port, Timeout, true, false, ConnName). + + open(Server, Port, Timeout, KeepAlive, ConnName) -> ++ open(Server, Port, Timeout, KeepAlive, false, ConnName). ++ ++open(Server, Port, Timeout, KeepAlive, NoDelay, ConnName) -> + Self = self(), + Pid = spawn(fun() -> + init(Self, Server, Port, Timeout, +- KeepAlive, ConnName) ++ KeepAlive, NoDelay, ConnName) + end), + receive + {open,Pid} -> +@@ -114,8 +117,8 @@ get_data(Pid) -> + + %%%----------------------------------------------------------------- + %%% Internal functions +-init(Parent, Server, Port, Timeout, KeepAlive, ConnName) -> +- case gen_tcp:connect(Server, Port, [list,{packet,0},{nodelay,true}], Timeout) of ++init(Parent, Server, Port, Timeout, KeepAlive, NoDelay, ConnName) -> ++ case gen_tcp:connect(Server, Port, [list,{packet,0},{nodelay,NoDelay}], Timeout) of + {ok,Sock} -> + dbg("~p connected to: ~p (port: ~w, keep_alive: ~w)\n", + [ConnName,Server,Port,KeepAlive]), +--- a/lib/common_test/src/ct_testspec.erl ++++ b/lib/common_test/src/ct_testspec.erl +@@ -1146,8 +1146,9 @@ should_be_added(Tag,Node,_Data,Spec) -> + if + %% list terms *without* possible duplicates here + Tag == logdir; Tag == logopts; +- Tag == basic_html; Tag == label; +- Tag == auto_compile; Tag == abort_if_missing_suites; ++ Tag == basic_html; Tag == esc_chars; ++ Tag == label; Tag == auto_compile; ++ Tag == abort_if_missing_suites; + Tag == stylesheet; Tag == verbosity; + Tag == silent_connections -> + lists:keymember(ref2node(Node,Spec#testspec.nodes),1, +@@ -1544,6 +1545,8 @@ valid_terms() -> + {logopts,3}, + {basic_html,2}, + {basic_html,3}, ++ {esc_chars,2}, ++ {esc_chars,3}, + {verbosity,2}, + {verbosity,3}, + {silent_connections,2}, +--- a/lib/common_test/src/ct_util.erl ++++ b/lib/common_test/src/ct_util.erl +@@ -459,6 +459,7 @@ loop(Mode,TestData,StartDir) -> + error:badarg -> [] + end, + ct_hooks:terminate(Callbacks), ++ + close_connections(ets:tab2list(?conn_table)), + ets:delete(?conn_table), + ets:delete(?board_table), +--- a/lib/common_test/src/ct_util.hrl ++++ b/lib/common_test/src/ct_util.hrl +@@ -37,6 +37,7 @@ + logdir=["."], + logopts=[], + basic_html=[], ++ esc_chars=[], + verbosity=[], + silent_connections=[], + cover=[], +--- a/lib/common_test/src/cth_log_redirect.erl ++++ b/lib/common_test/src/cth_log_redirect.erl +@@ -130,7 +130,14 @@ handle_event(Event, #eh_state{log_func = LogFunc} = State) -> + tag_event(Event)), + if is_list(SReport) -> + SaslHeader = format_header(State), +- ct_logs:LogFunc(sasl, ?STD_IMPORTANCE, SaslHeader, SReport, []); ++ case LogFunc of ++ tc_log -> ++ ct_logs:tc_log(sasl, ?STD_IMPORTANCE, ++ SaslHeader, SReport, [], []); ++ tc_log_async -> ++ ct_logs:tc_log_async(sasl, ?STD_IMPORTANCE, ++ SaslHeader, SReport, []) ++ end; + true -> %% Report is an atom if no logging is to be done + ignore + end +@@ -139,7 +146,14 @@ handle_event(Event, #eh_state{log_func = LogFunc} = State) -> + tag_event(Event),io_lib), + if is_list(EReport) -> + ErrHeader = format_header(State), +- ct_logs:LogFunc(error_logger, ?STD_IMPORTANCE, ErrHeader, EReport, []); ++ case LogFunc of ++ tc_log -> ++ ct_logs:tc_log(error_logger, ?STD_IMPORTANCE, ++ ErrHeader, EReport, [], []); ++ tc_log_async -> ++ ct_logs:tc_log_async(error_logger, ?STD_IMPORTANCE, ++ ErrHeader, EReport, []) ++ end; + true -> %% Report is an atom if no logging is to be done + ignore + end, +--- a/lib/common_test/src/cth_surefire.erl ++++ b/lib/common_test/src/cth_surefire.erl +@@ -82,7 +82,8 @@ init(Path, Opts) -> + url_base = proplists:get_value(url_base,Opts), + timer = ?now }. + +-pre_init_per_suite(Suite,SkipOrFail,State) when is_tuple(SkipOrFail) -> ++pre_init_per_suite(Suite,SkipOrFail,#state{ test_cases = [] } = State) ++ when is_tuple(SkipOrFail) -> + {SkipOrFail, init_tc(State#state{curr_suite = Suite, + curr_suite_ts = ?now}, + SkipOrFail) }; +--- a/lib/common_test/src/unix_telnet.erl ++++ b/lib/common_test/src/unix_telnet.erl +@@ -27,7 +27,8 @@ + %%% {port,PortNum}, % optional + %%% {username,UserName}, + %%% {password,Password}, +-%%% {keep_alive,Bool}]}. % optional ++%%% {keep_alive,Bool}, % optional ++%%% {tcp_nodely,Bool}]} % optional + %%% + %%%

To communicate via telnet to the host specified by + %%% HostNameOrIpAddress, use the interface functions in +@@ -55,7 +56,7 @@ + -compile(export_all). + + %% Callbacks for ct_telnet.erl +--export([connect/6,get_prompt_regexp/0]). ++-export([connect/7,get_prompt_regexp/0]). + -import(ct_telnet,[start_gen_log/1,log/4,end_gen_log/0]). + + -define(username,"login: "). +@@ -82,6 +83,7 @@ get_prompt_regexp() -> + %%% Port = integer() + %%% Timeout = integer() + %%% KeepAlive = bool() ++%%% TCPNoDelay = bool() + %%% Extra = ct:target_name() | {Username,Password} + %%% Username = string() + %%% Password = string() +@@ -91,25 +93,25 @@ get_prompt_regexp() -> + %%% @doc Callback for ct_telnet.erl. + %%% + %%%

Setup telnet connection to a unix host.

+-connect(ConnName,Ip,Port,Timeout,KeepAlive,Extra) -> ++connect(ConnName,Ip,Port,Timeout,KeepAlive,TCPNoDelay,Extra) -> + case Extra of + {Username,Password} -> +- connect1(ConnName,Ip,Port,Timeout,KeepAlive, ++ connect1(ConnName,Ip,Port,Timeout,KeepAlive,TCPNoDelay, + Username,Password); + KeyOrName -> + case get_username_and_password(KeyOrName) of + {ok,{Username,Password}} -> +- connect1(ConnName,Ip,Port,Timeout,KeepAlive, ++ connect1(ConnName,Ip,Port,Timeout,KeepAlive,TCPNoDelay, + Username,Password); + Error -> + Error + end + end. + +-connect1(Name,Ip,Port,Timeout,KeepAlive,Username,Password) -> ++connect1(Name,Ip,Port,Timeout,KeepAlive,TCPNoDelay,Username,Password) -> + start_gen_log("unix_telnet connect"), + Result = +- case ct_telnet_client:open(Ip,Port,Timeout,KeepAlive,Name) of ++ case ct_telnet_client:open(Ip,Port,Timeout,KeepAlive,TCPNoDelay,Name) of + {ok,Pid} -> + case ct_telnet:silent_teln_expect(Name,Pid,[], + [prompt],?prx,[]) of +--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_update_config_SUITE.erl ++++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_update_config_SUITE.erl +@@ -1,8 +1,8 @@ +-%% +-%% %CopyrightBegin% +-%% +-%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +-%% ++%% ++%% %CopyrightBegin% ++%% ++%% Copyright Ericsson AB 2010-2011. All Rights Reserved. ++%% + %% Licensed under the Apache License, Version 2.0 (the "License"); + %% you may not use this file except in compliance with the License. + %% You may obtain a copy of the License at +@@ -14,46 +14,46 @@ + %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + %% See the License for the specific language governing permissions and + %% limitations under the License. +-%% +-%% %CopyrightEnd% +-%% +- +--module(ct_update_config_SUITE). +- +--suite_defaults([{timetrap, {minutes, 10}}]). +- +-%% Note: This directive should only be used in test suites. +--compile(export_all). +- +--include("ct.hrl"). +- +--define(now, os:timestamp()). +- +-%% Test server callback functions +-init_per_suite(Config) -> +- [{init_per_suite,?now}|Config]. +- +-end_per_suite(_Config) -> +- ok. +- +-init_per_testcase(_TestCase, Config) -> +- [{init_per_testcase,?now}|Config]. +- +-end_per_testcase(_TestCase, _Config) -> +- ok. +- +-init_per_group(GroupName, Config) -> +- [{init_per_group,?now}|Config]. +- +-end_per_group(GroupName, Config) -> +- ok. +- +-all() -> +- [{group,group1}]. +- +-groups() -> +- [{group1,[],[test_case]}]. +- +-%% Test cases starts here. +-test_case(Config) when is_list(Config) -> +- ok. ++%% ++%% %CopyrightEnd% ++%% ++ ++-module(ct_update_config_SUITE). ++ ++-suite_defaults([{timetrap, {minutes, 10}}]). ++ ++%% Note: This directive should only be used in test suites. ++-compile(export_all). ++ ++-include("ct.hrl"). ++ ++-define(now, ct_test_support:unique_timestamp()). ++ ++%% Test server callback functions ++init_per_suite(Config) -> ++ [{init_per_suite,?now}|Config]. ++ ++end_per_suite(_Config) -> ++ ok. ++ ++init_per_testcase(_TestCase, Config) -> ++ [{init_per_testcase,?now}|Config]. ++ ++end_per_testcase(_TestCase, _Config) -> ++ ok. ++ ++init_per_group(GroupName, Config) -> ++ [{init_per_group,?now}|Config]. ++ ++end_per_group(GroupName, Config) -> ++ ok. ++ ++all() -> ++ [{group,group1}]. ++ ++groups() -> ++ [{group1,[],[test_case]}]. ++ ++%% Test cases starts here. ++test_case(Config) when is_list(Config) -> ++ ok. +--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl ++++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl +@@ -90,7 +90,7 @@ id(Opts) -> + gen_event:notify(?CT_EVMGR_REF, #event{ name = cth, node = node(), + data = {?MODULE, id, [Opts]}}), + ct:log("~w:id called", [?MODULE]), +- os:timestamp(). ++ ct_test_support:unique_timestamp(). + + %% @doc Called before init_per_suite is called. Note that this callback is + %% only called if the CTH is added before init_per_suite is run (eg. in a test +--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/update_config_cth.erl ++++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/update_config_cth.erl +@@ -25,7 +25,7 @@ + -include_lib("common_test/src/ct_util.hrl"). + -include_lib("common_test/include/ct_event.hrl"). + +--define(now, os:timestamp()). ++-define(now, ct_test_support:unique_timestamp()). + + %% CT Hooks + -compile(export_all). +--- a/lib/common_test/test/ct_pre_post_test_io_SUITE.erl ++++ b/lib/common_test/test/ct_pre_post_test_io_SUITE.erl +@@ -44,13 +44,29 @@ + %% instance, the tests need to be performed on a separate node (or + %% there will be clashes with logging processes etc). + %%-------------------------------------------------------------------- ++suite() -> ++ [{ct_hooks,[ts_install_cth]}, ++ {timetrap,{seconds,120}}]. ++ ++all() -> ++ [ ++ pre_post_io ++ ]. ++ + init_per_suite(Config) -> +- DataDir = ?config(data_dir, Config), +- CTH = filename:join(DataDir, "cth_ctrl.erl"), +- ct:pal("Compiling ~p: ~p", +- [CTH,compile:file(CTH,[{outdir,DataDir},debug_info])]), +- ct_test_support:init_per_suite([{path_dirs,[DataDir]}, +- {start_sasl,true} | Config]). ++ TTInfo = {_T,{_Scaled,ScaleVal}} = ct:get_timetrap_info(), ++ ct:pal("Timetrap info = ~w", [TTInfo]), ++ if ScaleVal > 1 -> ++ {skip,"Skip on systems running e.g. cover or debug!"}; ++ ScaleVal =< 1 -> ++ DataDir = ?config(data_dir, Config), ++ CTH = filename:join(DataDir, "cth_ctrl.erl"), ++ ct:pal("Compiling ~p: ~p", ++ [CTH,compile:file(CTH,[{outdir,DataDir}, ++ debug_info])]), ++ ct_test_support:init_per_suite([{path_dirs,[DataDir]}, ++ {start_sasl,true} | Config]) ++ end. + + end_per_suite(Config) -> + ct_test_support:end_per_suite(Config). +@@ -61,13 +77,6 @@ init_per_testcase(TestCase, Config) -> + end_per_testcase(TestCase, Config) -> + ct_test_support:end_per_testcase(TestCase, Config). + +-suite() -> [{ct_hooks,[ts_install_cth]}]. +- +-all() -> +- [ +- pre_post_io +- ]. +- + %%-------------------------------------------------------------------- + %% TEST CASES + %%-------------------------------------------------------------------- +@@ -90,31 +99,50 @@ pre_post_io(Config) -> + %%!-------------------------------------------------------------------- + + spawn(fun() -> +- ct:pal("CONTROLLER: Started!", []), ++ ct:pal("CONTROLLER: Starting test run #1...", []), + %% --- test run 1 --- +- ct:sleep(3000), +- ct:pal("CONTROLLER: Handle remote events = true", []), +- ok = ct_test_support:ct_rpc({cth_log_redirect, +- handle_remote_events, +- [true]}, Config), +- ct:sleep(2000), +- ct:pal("CONTROLLER: Proceeding with test run #1!", []), ++ try_loop(ct_test_support, ct_rpc, [{cth_log_redirect, ++ handle_remote_events, ++ [true]}, Config], 3000), ++ CTLoggerPid1 = ct_test_support:ct_rpc({erlang,whereis, ++ [ct_logs]}, Config), ++ ct:pal("CONTROLLER: Logger = ~w~nHandle remote events = true", ++ [CTLoggerPid1]), ++ ct:sleep(5000), ++ ct:pal("CONTROLLER: Proceeding with test run #1...", []), + ok = ct_test_support:ct_rpc({cth_ctrl,proceed,[]}, Config), + ct:sleep(6000), +- ct:pal("CONTROLLER: Proceeding with shutdown #1!", []), ++ ct:pal("CONTROLLER: Proceeding with shutdown #1...", []), + ok = ct_test_support:ct_rpc({cth_ctrl,proceed,[]}, Config), ++ try_loop(fun() -> ++ false = ct_test_support:ct_rpc({erlang, ++ is_process_alive, ++ [CTLoggerPid1]}, ++ Config) ++ end, 3000), ++ ct:pal("CONTROLLER: Shutdown #1 complete!", []), ++ ct:pal("CONTROLLER: Starting test run #2...", []), + %% --- test run 2 --- +- ct:sleep(3000), +- ct:pal("CONTROLLER: Handle remote events = true", []), +- ok = ct_test_support:ct_rpc({cth_log_redirect, +- handle_remote_events, +- [true]}, Config), +- ct:sleep(2000), +- ct:pal("CONTROLLER: Proceeding with test run #2!", []), ++ try_loop(ct_test_support, ct_rpc, [{cth_log_redirect, ++ handle_remote_events, ++ [true]}, Config], 3000), ++ CTLoggerPid2 = ct_test_support:ct_rpc({erlang,whereis, ++ [ct_logs]}, Config), ++ ct:pal("CONTROLLER: Logger = ~w~nHandle remote events = true", ++ [CTLoggerPid2]), ++ ct:sleep(5000), ++ ct:pal("CONTROLLER: Proceeding with test run #2...", []), + ok = ct_test_support:ct_rpc({cth_ctrl,proceed,[]}, Config), + ct:sleep(6000), +- ct:pal("CONTROLLER: Proceeding with shutdown #2!", []), +- ok = ct_test_support:ct_rpc({cth_ctrl,proceed,[]}, Config) ++ ct:pal("CONTROLLER: Proceeding with shutdown #2...", []), ++ ok = ct_test_support:ct_rpc({cth_ctrl,proceed,[]}, Config), ++ try_loop(fun() -> ++ false = ct_test_support:ct_rpc({erlang, ++ is_process_alive, ++ [CTLoggerPid2]}, ++ Config) ++ end, 3000), ++ ct:pal("CONTROLLER: Shutdown #2 complete!", []) + end), + ct_test_support:run(Opts, Config), + Events = ct_test_support:get_events(ERPid, Config), +@@ -157,7 +185,7 @@ pre_post_io(Config) -> + Counters + end, {pre,0,0,0,0}, Ts), + [_|Counters] = tuple_to_list(PrePostIOEntries), +- ct:log("Entries in the Pre/Post Test IO Log: ~p", [Counters]), ++ ct:pal("Entries in the Pre/Post Test IO Log: ~w", [Counters]), + case [C || C <- Counters, C < 2] of + [] -> + ok; +@@ -183,7 +211,7 @@ pre_post_io(Config) -> + [LogN,ErrN+1]; + (_, Counters) -> Counters + end, [0,0], Ts), +- ct:log("Entries in the Unexpected IO Log: ~p", [UnexpIOEntries]), ++ ct:log("Entries in the Unexpected IO Log: ~w", [UnexpIOEntries]), + case [N || N <- UnexpIOEntries, N < 2] of + [] -> + ok; +@@ -208,6 +236,38 @@ setup(Test, Config) -> + reformat(Events, EH) -> + ct_test_support:reformat(Events, EH). + ++try_loop(_Fun, 0) -> ++ ct:pal("WARNING! Fun never succeeded!", []), ++ gave_up; ++try_loop(Fun, N) -> ++ try Fun() of ++ {error,_} -> ++ timer:sleep(10), ++ try_loop(Fun, N-1); ++ Result -> ++ Result ++ catch ++ _:_What -> ++ timer:sleep(10), ++ try_loop(Fun, N-1) ++ end. ++ ++try_loop(M, F, _A, 0) -> ++ ct:pal("WARNING! ~w:~w never succeeded!", [M,F]), ++ gave_up; ++try_loop(M, F, A, N) -> ++ try apply(M, F, A) of ++ {error,_} -> ++ timer:sleep(10), ++ try_loop(M, F, A, N-1); ++ Result -> ++ Result ++ catch ++ _:_ -> ++ timer:sleep(10), ++ try_loop(M, F, A, N-1) ++ end. ++ + %%%----------------------------------------------------------------- + %%% TEST EVENTS + %%%----------------------------------------------------------------- +--- a/lib/common_test/test/ct_pre_post_test_io_SUITE_data/cth_ctrl.erl ++++ b/lib/common_test/test/ct_pre_post_test_io_SUITE_data/cth_ctrl.erl +@@ -53,8 +53,7 @@ init(_Id, _Opts) -> + receive + {?MODULE,proceed} -> ok + after +- 10000 -> +- ok ++ 10000 -> ok + end, + {ok,[],ct_last}. + +@@ -66,8 +65,7 @@ terminate(_State) -> + receive + {?MODULE,proceed} -> ok + after +- 10000 -> +- ok ++ 10000 -> ok + end, + stop_external_logger(cth_logger), + stop_dispatcher(), +@@ -94,7 +92,7 @@ init_logger(Name) -> + logger_loop(N) -> + ct:log("Logger iteration: ~p", [N]), + error_logger:error_report(N), +- timer:sleep(250), ++ timer:sleep(100), + logger_loop(N+1). + + %%%----------------------------------------------------------------- +--- a/lib/common_test/test/ct_surefire_SUITE.erl ++++ b/lib/common_test/test/ct_surefire_SUITE.erl +@@ -49,8 +49,11 @@ + %% there will be clashes with logging processes etc). + %%-------------------------------------------------------------------- + init_per_suite(Config) -> +- Config1 = ct_test_support:init_per_suite(Config), +- Config1. ++ DataDir = ?config(data_dir,Config), ++ Hook = "fail_pre_init_per_suite.erl", ++ io:format("Compiling ~p: ~p~n", ++ [Hook, compile:file(Hook,[{outdir,DataDir},debug_info])]), ++ ct_test_support:init_per_suite([{path_dirs,[DataDir]}|Config]). + + end_per_suite(Config) -> + ct_test_support:end_per_suite(Config). +@@ -69,7 +72,8 @@ all() -> + absolute_path, + relative_path, + url, +- logdir ++ logdir, ++ fail_pre_init_per_suite + ]. + + %%-------------------------------------------------------------------- +@@ -107,6 +111,14 @@ logdir(Config) when is_list(Config) -> + Path = "logdir.xml", + run(logdir,[{cth_surefire,[{path,Path}]}],Path,Config,[{logdir,MyLogDir}]). + ++fail_pre_init_per_suite(Config) when is_list(Config) -> ++ DataDir = ?config(data_dir,Config), ++ Suites = [filename:join(DataDir,"pass_SUITE"), ++ filename:join(DataDir,"fail_SUITE")], ++ Path = "fail_pre_init_per_suite.xml", ++ run(fail_pre_init_per_suite,[fail_pre_init_per_suite, ++ {cth_surefire,[{path,Path}]}],Path,Config,[],Suites). ++ + %%%----------------------------------------------------------------- + %%% HELP FUNCTIONS + %%%----------------------------------------------------------------- +@@ -115,6 +127,8 @@ run(Case,CTHs,Report,Config) -> + run(Case,CTHs,Report,Config,ExtraOpts) -> + DataDir = ?config(data_dir, Config), + Suite = filename:join(DataDir, "surefire_SUITE"), ++ run(Case,CTHs,Report,Config,ExtraOpts,Suite). ++run(Case,CTHs,Report,Config,ExtraOpts,Suite) -> + {Opts,ERPid} = setup([{suite,Suite},{ct_hooks,CTHs},{label,Case}|ExtraOpts], + Config), + ok = execute(Case, Opts, ERPid, Config), +@@ -142,7 +156,6 @@ setup(Test, Config) -> + execute(Name, Opts, ERPid, Config) -> + ok = ct_test_support:run(Opts, Config), + Events = ct_test_support:get_events(ERPid, Config), +- + ct_test_support:log_events(Name, + reformat(Events, ?eh), + ?config(priv_dir, Config), +@@ -166,10 +179,30 @@ events_to_check(_, 0) -> + events_to_check(Test, N) -> + test_events(Test) ++ events_to_check(Test, N-1). + +-test_events(_) -> +- [{?eh,start_logging,'_'}, +- {?eh,start_info,{1,1,9}}, +- {?eh,tc_start,{surefire_SUITE,init_per_suite}}, ++test_suite_events(fail_SUITE, TestStat) -> ++ [{?eh,tc_start,{ct_framework,init_per_suite}}, ++ {?eh,tc_done,{ct_framework,init_per_suite, ++ {failed,{error,pre_init_per_suite}}}}, ++ {?eh,tc_auto_skip, ++ {fail_SUITE,test_case, ++ {failed,{ct_framework,init_per_suite,{failed,pre_init_per_suite}}}}}, ++ {?eh,test_stats,TestStat}, ++ {?eh,tc_auto_skip, ++ {ct_framework,end_per_suite, ++ {failed,{ct_framework,init_per_suite,{failed,pre_init_per_suite}}}}}]. ++ ++test_suite_events(fail_SUITE) -> ++ test_suite_events(fail_SUITE, {0,0,{0,1}}); ++test_suite_events(pass_SUITE) -> ++ [{?eh,tc_start,{ct_framework,init_per_suite}}, ++ {?eh,tc_done,{ct_framework,init_per_suite,ok}}, ++ {?eh,tc_start,{pass_SUITE,test_case}}, ++ {?eh,tc_done,{pass_SUITE,test_case,ok}}, ++ {?eh,test_stats,{1,0,{0,0}}}, ++ {?eh,tc_start,{ct_framework,end_per_suite}}, ++ {?eh,tc_done,{ct_framework,end_per_suite,ok}}]; ++test_suite_events(_) -> ++ [{?eh,tc_start,{surefire_SUITE,init_per_suite}}, + {?eh,tc_done,{surefire_SUITE,init_per_suite,ok}}, + {?eh,tc_start,{surefire_SUITE,tc_ok}}, + {?eh,tc_done,{surefire_SUITE,tc_ok,ok}}, +@@ -216,9 +249,18 @@ test_events(_) -> + {surefire_SUITE,init_per_group, + {'EXIT',all_cases_should_be_skipped}}}}}], + {?eh,tc_start,{surefire_SUITE,end_per_suite}}, +- {?eh,tc_done,{surefire_SUITE,end_per_suite,ok}}, +- {?eh,stop_logging,[]}]. +- ++ {?eh,tc_done,{surefire_SUITE,end_per_suite,ok}}]. ++ ++test_events(fail_pre_init_per_suite) -> ++ [{?eh,start_logging,{'DEF','RUNDIR'}}, ++ {?eh,start_info,{2,2,2}}] ++ ++ test_suite_events(pass_SUITE) ++ ++ test_suite_events(fail_SUITE, {1,0,{0,1}}) ++ ++ [{?eh,stop_logging,[]}]; ++test_events(Test) -> ++ [{?eh,start_logging,'_'}, {?eh,start_info,{1,1,9}}] ++ ++ test_suite_events(Test) ++ ++ [{?eh,stop_logging,[]}]. + + %%%----------------------------------------------------------------- + %%% Check generated xml log files +@@ -251,9 +293,9 @@ do_check_xml(Case,[Xml|Xmls]) -> + {E,_} = xmerl_scan:file(Xml), + Expected = events_to_result(lists:flatten(test_events(Case))), + ParseResult = testsuites(Case,E), +- ct:log("Expecting: ~p~n",[[Expected]]), ++ ct:log("Expecting: ~p~n",[Expected]), + ct:log("Actual : ~p~n",[ParseResult]), +- [Expected] = ParseResult, ++ Expected = ParseResult, + do_check_xml(Case,Xmls); + do_check_xml(_,[]) -> + ok. +@@ -265,7 +307,8 @@ testsuites(Case,#xmlElement{name=testsuites,content=TS}) -> + testsuite(Case,TS). + + testsuite(Case,[#xmlElement{name=testsuite,content=TC,attributes=A}|TS]) -> +- {ET,EF,ES} = events_to_numbers(lists:flatten(test_events(Case))), ++ TestSuiteEvents = test_suite_events(get_ts_name(A)), ++ {ET,EF,ES} = events_to_numbers(lists:flatten(TestSuiteEvents)), + {T,E,F,S} = get_numbers_from_attrs(A,false,false,false,false), + ct:log("Expecting total:~p, error:~p, failure:~p, skipped:~p~n",[ET,0,EF,ES]), + ct:log("Actual total:~p, error:~p, failure:~p, skipped:~p~n",[T,E,F,S]), +@@ -318,14 +361,32 @@ failed_or_skipped([]) -> + %% Testsuites = [Testsuite] + %% Testsuite = [Testcase] + %% Testcase = [] | [f] | [s], indicating ok, failed and skipped respectively +-events_to_result([{?eh,tc_done,{_Suite,_Case,R}}|E]) -> +- [result(R)|events_to_result(E)]; +-events_to_result([{?eh,tc_auto_skip,_}|E]) -> +- [[s]|events_to_result(E)]; +-events_to_result([_|E]) -> +- events_to_result(E); +-events_to_result([]) -> +- []. ++events_to_result(E) -> ++ events_to_result(E, []). ++ ++events_to_result([{?eh,tc_auto_skip,{_Suite,init_per_suite,_}}|E], Result) -> ++ {Suite,Rest} = events_to_result1(E), ++ events_to_result(Rest, [[[s]|Suite]|Result]); ++events_to_result([{?eh,tc_done,{_Suite,init_per_suite,R}}|E], Result) -> ++ {Suite,Rest} = events_to_result1(E), ++ events_to_result(Rest, [[result(R)|Suite]|Result]); ++events_to_result([_|E], Result) -> ++ events_to_result(E, Result); ++events_to_result([], Result) -> ++ Result. ++ ++events_to_result1([{?eh,tc_auto_skip,{_Suite, end_per_suite,_}}|E]) -> ++ {[[s]],E}; ++events_to_result1([{?eh,tc_done,{_Suite, end_per_suite,R}}|E]) -> ++ {[result(R)],E}; ++events_to_result1([{?eh,tc_done,{_Suite,_Case,R}}|E]) -> ++ {Suite,Rest} = events_to_result1(E), ++ {[result(R)|Suite],Rest}; ++events_to_result1([{?eh,tc_auto_skip,_}|E]) -> ++ {Suite,Rest} = events_to_result1(E), ++ {[[s]|Suite],Rest}; ++events_to_result1([_|E]) -> ++ events_to_result1(E). + + result(ok) ->[]; + result({skipped,_}) -> [s]; +@@ -374,3 +435,7 @@ del_files(Dir,[F0|Fs] ) -> + end; + del_files(_,[]) -> + ok. ++ ++get_ts_name(Attributes) -> ++ {_,name,_,_,_,_,_,_,Name,_} = lists:keyfind(name, 2, Attributes), ++ list_to_atom(Name). +--- /dev/null ++++ b/lib/common_test/test/ct_surefire_SUITE_data/fail_SUITE.erl +@@ -0,0 +1,28 @@ ++%% %CopyrightBegin% ++%% ++%% Copyright Ericsson AB 2016. All Rights Reserved. ++%% ++%% Licensed under the Apache License, Version 2.0 (the "License"); ++%% you may not use this file except in compliance with the License. ++%% You may obtain a copy of the License at ++%% ++%% http://www.apache.org/licenses/LICENSE-2.0 ++%% ++%% Unless required by applicable law or agreed to in writing, software ++%% distributed under the License is distributed on an "AS IS" BASIS, ++%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++%% See the License for the specific language governing permissions and ++%% limitations under the License. ++%% ++%% %CopyrightEnd% ++%% ++-module(fail_SUITE). ++-include_lib("common_test/include/ct.hrl"). ++ ++-export([all/0, test_case/1]). ++ ++all() -> ++ [test_case]. ++ ++test_case(_Config) -> ++ ok. +--- /dev/null ++++ b/lib/common_test/test/ct_surefire_SUITE_data/fail_pre_init_per_suite.erl +@@ -0,0 +1,47 @@ ++%% ++%% %CopyrightBegin% ++%% ++%% Copyright Ericsson AB 2016. All Rights Reserved. ++%% ++%% Licensed under the Apache License, Version 2.0 (the "License"); ++%% you may not use this file except in compliance with the License. ++%% You may obtain a copy of the License at ++%% ++%% http://www.apache.org/licenses/LICENSE-2.0 ++%% ++%% Unless required by applicable law or agreed to in writing, software ++%% distributed under the License is distributed on an "AS IS" BASIS, ++%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++%% See the License for the specific language governing permissions and ++%% limitations under the License. ++%% ++%% %CopyrightEnd% ++%% ++ ++%%% This tests that the correct XML is produced when pre_init_per_suite ++%%% fails in a hook ++-module(fail_pre_init_per_suite). ++ ++%% CT Hooks ++-export([init/2, pre_init_per_suite/3]). ++ ++-type config() :: proplists:proplist(). ++-type reason() :: term(). ++-type skip_or_fail() :: skip | auto_skip | fail | 'EXIT'. ++ ++-record(state, {}). ++ ++-spec init(Id :: term(), Opts :: proplists:proplist()) -> ++ {ok, proplists:proplist()}. ++init(_Id, Opts) -> ++ {ok, Opts}. ++ ++-spec pre_init_per_suite(Suite :: atom(), ++ Config :: config(), ++ State :: #state{}) -> ++ {config() | {skip_or_fail(), reason()}, NewState :: #state{}}. ++pre_init_per_suite(fail_SUITE, _Config, State) -> ++ {{fail, pre_init_per_suite}, State}; ++pre_init_per_suite(_Suite, Config, State) -> ++ {Config, State}. ++ +--- /dev/null ++++ b/lib/common_test/test/ct_surefire_SUITE_data/pass_SUITE.erl +@@ -0,0 +1,28 @@ ++%% %CopyrightBegin% ++%% ++%% Copyright Ericsson AB 2016. All Rights Reserved. ++%% ++%% Licensed under the Apache License, Version 2.0 (the "License"); ++%% you may not use this file except in compliance with the License. ++%% You may obtain a copy of the License at ++%% ++%% http://www.apache.org/licenses/LICENSE-2.0 ++%% ++%% Unless required by applicable law or agreed to in writing, software ++%% distributed under the License is distributed on an "AS IS" BASIS, ++%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++%% See the License for the specific language governing permissions and ++%% limitations under the License. ++%% ++%% %CopyrightEnd% ++%% ++-module(pass_SUITE). ++-include_lib("common_test/include/ct.hrl"). ++ ++-export([all/0, test_case/1]). ++ ++all() -> ++ [test_case]. ++ ++test_case(_Config) -> ++ ok. +--- a/lib/common_test/test/ct_test_support.erl ++++ b/lib/common_test/test/ct_test_support.erl +@@ -43,6 +43,8 @@ + + -export([random_error/1]). + ++-export([unique_timestamp/0]). ++ + -include_lib("kernel/include/file.hrl"). + + %%%----------------------------------------------------------------- +@@ -110,7 +112,8 @@ start_slave(NodeName, Config, Level) -> + undefined -> []; + Ds -> Ds + end, +- PathDirs = [PrivDir,TSDir | AddPathDirs], ++ TestSupDir = filename:dirname(code:which(?MODULE)), ++ PathDirs = [PrivDir,TSDir,TestSupDir | AddPathDirs], + [true = rpc:call(CTNode, code, add_patha, [D]) || D <- PathDirs], + test_server:format(Level, "Dirs added to code path (on ~w):~n", + [CTNode]), +@@ -1430,7 +1433,21 @@ rm_files([F | Fs]) -> + end; + rm_files([]) -> + ok. +- ++ ++unique_timestamp() -> ++ unique_timestamp(os:timestamp(), 100000). ++ ++unique_timestamp(TS, 0) -> ++ TS; ++unique_timestamp(TS0, N) -> ++ case os:timestamp() of ++ TS0 -> ++ timer:sleep(1), ++ unique_timestamp(TS0, N-1); ++ TS1 -> ++ TS1 ++ end. ++ + %%%----------------------------------------------------------------- + %%% + slave_stop(Node) -> +--- a/lib/common_test/vsn.mk ++++ b/lib/common_test/vsn.mk +@@ -1 +1 @@ +-COMMON_TEST_VSN = 1.12 ++COMMON_TEST_VSN = 1.12.1 +--- a/lib/inets/doc/src/notes.xml ++++ b/lib/inets/doc/src/notes.xml +@@ -33,7 +33,40 @@ + notes.xml + + +-
Inets 6.2.2 ++
Inets 6.2.4 ++ ++
Improvements and New Features ++ ++ ++

++ Handle multiple \t in mime types file

++

++ Own Id: OTP-13663 Aux Id: seq13132

++
++
++
++ ++
++ ++
Inets 6.2.3 ++ ++
Improvements and New Features ++ ++ ++

++ Put back unused module inets_regexp and remove it in OTP ++ 19 instead as it is an incompatibility, although it is an ++ undocumented module and should not affect other ++ applications.

++

++ Own Id: OTP-13533

++
++
++
++ ++
++ ++
Inets 6.2.2 + +
Improvements and New Features + +--- a/lib/inets/src/http_server/httpd_conf.erl ++++ b/lib/inets/src/http_server/httpd_conf.erl +@@ -1004,7 +1004,8 @@ read_config_file(Stream, SoFar) -> + %% Ignore commented lines for efficiency later .. + read_config_file(Stream, SoFar); + Line -> +- NewLine = re:replace(clean(Line),"[\t\r\f ]"," ", [{return,list}]), ++ NewLine = re:replace(white_space_clean(Line), ++ "[\t\r\f ]"," ", [{return,list}, global]), + case NewLine of + [] -> + %% Also ignore empty lines .. +@@ -1020,7 +1021,7 @@ parse_mime_types(Stream,MimeTypesList) -> + eof -> + eof; + String -> +- white_space_clean(String) ++ re:replace(white_space_clean(String), "[\t\r\f ]"," ", [{return,list}, global]) + end, + parse_mime_types(Stream, MimeTypesList, Line). + parse_mime_types(Stream, MimeTypesList, eof) -> +@@ -1042,6 +1043,8 @@ parse_mime_types(Stream, MimeTypesList, Line) -> + + suffixes(_MimeType,[]) -> + []; ++suffixes(MimeType,[""|Rest]) -> ++ suffixes(MimeType, Rest); + suffixes(MimeType,[Suffix|Rest]) -> + [{Suffix,MimeType}|suffixes(MimeType,Rest)]. + +--- a/lib/inets/src/inets_app/Makefile ++++ b/lib/inets/src/inets_app/Makefile +@@ -49,7 +49,8 @@ MODULES = \ + inets_sup \ + inets_trace \ + inets_lib \ +- inets_time_compat ++ inets_time_compat \ ++ inets_regexp + + INTERNAL_HRL_FILES = inets_internal.hrl + EXTERNAL_HRL_FILES = ../../include/httpd.hrl \ +--- a/lib/inets/src/inets_app/inets.app.src ++++ b/lib/inets/src/inets_app/inets.app.src +@@ -29,6 +29,7 @@ + inets_trace, + inets_lib, + inets_time_compat, ++ inets_regexp, + + %% FTP + ftp, +--- a/lib/inets/src/inets_app/inets.appup.src ++++ b/lib/inets/src/inets_app/inets.appup.src +@@ -18,16 +18,10 @@ + %% %CopyrightEnd% + {"%VSN%", + [ +- {<<"6.2.1">>, [{load_module, httpd_script_env, soft_purge, soft_purge, []}]}, +- {<<"6.2">>, [{load_module, httpd_script_env, soft_purge, soft_purge, []}, +- {load_module, httpc, soft_purge, soft_purge, []}]}, + {<<"6\\..*">>,[{restart_application, inets}]}, + {<<"5\\..*">>,[{restart_application, inets}]} + ], + [ +- {<<"6.2.1">>, [{load_module, httpd_script_env, soft_purge, soft_purge, []}]}, +- {<<"6.2">>, [{load_module, httpd_script_env, soft_purge, soft_purge, []}, +- {load_module, httpc, soft_purge, soft_purge, []}]}, + {<<"6\\..*">>,[{restart_application, inets}]}, + {<<"5\\..*">>,[{restart_application, inets}]} + ] +--- /dev/null ++++ b/lib/inets/src/inets_app/inets_regexp.erl +@@ -0,0 +1,414 @@ ++%% ++%% %CopyrightBegin% ++%% ++%% Copyright Ericsson AB 2009. All Rights Reserved. ++%% ++%% Licensed under the Apache License, Version 2.0 (the "License"); ++%% you may not use this file except in compliance with the License. ++%% You may obtain a copy of the License at ++%% ++%% http://www.apache.org/licenses/LICENSE-2.0 ++%% ++%% Unless required by applicable law or agreed to in writing, software ++%% distributed under the License is distributed on an "AS IS" BASIS, ++%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++%% See the License for the specific language governing permissions and ++%% limitations under the License. ++%% ++%% %CopyrightEnd% ++%% ++ ++-module(inets_regexp). ++ ++-export([parse/1, match/2, first_match/2, split/2, sub/3, gsub/3]). ++ ++ ++%%%========================================================================= ++%%% API ++%%%========================================================================= ++ ++%% parse(RegExp) -> {ok, RE} | {error, E}. ++%% Parse the regexp described in the string RegExp. ++ ++parse(S) -> ++ case (catch reg(S)) of ++ {R, []} -> ++ {ok, R}; ++ {_R, [C|_]} -> ++ {error, {illegal, [C]}}; ++ {error, E} -> ++ {error, E} ++ end. ++ ++ ++%% Find the longest match of RegExp in String. ++ ++match(S, RegExp) when is_list(RegExp) -> ++ case parse(RegExp) of ++ {ok,RE} -> match(S, RE); ++ {error,E} -> {error,E} ++ end; ++match(S, RE) -> ++ case match(RE, S, 1, 0, -1) of ++ {Start,Len} when Len >= 0 -> ++ {match, Start, Len}; ++ {_Start,_Len} -> ++ nomatch ++ end. ++ ++%% Find the first match of RegExp in String. ++ ++first_match(S, RegExp) when is_list(RegExp) -> ++ case parse(RegExp) of ++ {ok, RE} -> ++ first_match(S, RE); ++ {error, E} -> ++ {error, E} ++ end; ++first_match(S, RE) -> ++ case first_match(RE, S, 1) of ++ {Start,Len} when Len >= 0 -> ++ {match, Start,Len}; ++ nomatch -> ++ nomatch ++ end. ++ ++first_match(RE, S, St) when S =/= [] -> ++ case re_apply(S, St, RE) of ++ {match, P, _Rest} -> ++ {St, P-St}; ++ nomatch -> ++ first_match(RE, tl(S), St+1) ++ end; ++first_match(_RE, [], _St) -> ++ nomatch. ++ ++ ++match(RE, S, St, Pos, L) -> ++ case first_match(RE, S, St) of ++ {St1, L1} -> ++ Nst = St1 + 1, ++ if L1 > L -> ++ match(RE, lists:nthtail(Nst-St, S), Nst, St1, L1); ++ true -> ++ match(RE, lists:nthtail(Nst-St, S), Nst, Pos, L) ++ end; ++ nomatch -> ++ {Pos, L} ++ end. ++ ++ ++%% Split a string into substrings where the RegExp describes the ++%% field seperator. The RegExp " " is specially treated. ++ ++split(String, " ") -> %This is really special ++ {ok, RE} = parse("[ \t]+"), ++ case split_apply(String, RE, true) of ++ [[]|Ss] -> ++ {ok,Ss}; ++ Ss -> ++ {ok,Ss} ++ end; ++split(String, RegExp) when is_list(RegExp) -> ++ case parse(RegExp) of ++ {ok, RE} -> ++ {ok, split_apply(String, RE, false)}; ++ {error, E} -> ++ {error,E} ++ end; ++split(String, RE) -> ++ {ok, split_apply(String, RE, false)}. ++ ++ ++%% Substitute the first match of the regular expression RegExp ++%% with the string Replace in String. Accept pre-parsed regular ++%% expressions. ++ ++sub(String, RegExp, Rep) when is_list(RegExp) -> ++ case parse(RegExp) of ++ {ok, RE} -> ++ sub(String, RE, Rep); ++ {error, E} -> ++ {error, E} ++ end; ++sub(String, RE, Rep) -> ++ Ss = sub_match(String, RE, 1), ++ {ok, sub_repl(Ss, Rep, String, 1), length(Ss)}. ++ ++ ++%% Substitute every match of the regular expression RegExp with ++%% the string New in String. Accept pre-parsed regular expressions. ++ ++gsub(String, RegExp, Rep) when is_list(RegExp) -> ++ case parse(RegExp) of ++ {ok, RE} -> ++ gsub(String, RE, Rep); ++ {error, E} -> ++ {error, E} ++ end; ++gsub(String, RE, Rep) -> ++ Ss = matches(String, RE, 1), ++ {ok, sub_repl(Ss, Rep, String, 1), length(Ss)}. ++ ++ ++%%%======================================================================== ++%%% Internal functions ++%%%======================================================================== ++ ++%% This is the regular expression grammar used. It is equivalent to the ++%% one used in AWK, except that we allow ^ $ to be used anywhere and fail ++%% in the matching. ++%% ++%% reg -> reg1 : '$1'. ++%% reg1 -> reg1 "|" reg2 : {'or','$1','$2'}. ++%% reg1 -> reg2 : '$1'. ++%% reg2 -> reg2 reg3 : {concat,'$1','$2'}. ++%% reg2 -> reg3 : '$1'. ++%% reg3 -> reg3 "*" : {kclosure,'$1'}. ++%% reg3 -> reg3 "+" : {pclosure,'$1'}. ++%% reg3 -> reg3 "?" : {optional,'$1'}. ++%% reg3 -> reg4 : '$1'. ++%% reg4 -> "(" reg ")" : '$2'. ++%% reg4 -> "\\" char : '$2'. ++%% reg4 -> "^" : bos. ++%% reg4 -> "$" : eos. ++%% reg4 -> "." : char. ++%% reg4 -> "[" class "]" : {char_class,char_class('$2')} ++%% reg4 -> "[" "^" class "]" : {comp_class,char_class('$3')} ++%% reg4 -> "\"" chars "\"" : char_string('$2') ++%% reg4 -> char : '$1'. ++%% reg4 -> empty : epsilon. ++%% The grammar of the current regular expressions. The actual parser ++%% is a recursive descent implementation of the grammar. ++ ++reg(S) -> reg1(S). ++ ++%% reg1 -> reg2 reg1' ++%% reg1' -> "|" reg2 ++%% reg1' -> empty ++ ++reg1(S0) -> ++ {L,S1} = reg2(S0), ++ reg1p(S1, L). ++ ++reg1p([$||S0], L) -> ++ {R,S1} = reg2(S0), ++ reg1p(S1, {'or',L,R}); ++reg1p(S, L) -> {L,S}. ++ ++%% reg2 -> reg3 reg2' ++%% reg2' -> reg3 ++%% reg2' -> empty ++ ++reg2(S0) -> ++ {L,S1} = reg3(S0), ++ reg2p(S1, L). ++ ++reg2p([C|S0], L) when (C =/= $|) andalso (C =/= $)) -> ++ {R,S1} = reg3([C|S0]), ++ reg2p(S1, {concat,L,R}); ++reg2p(S, L) -> {L,S}. ++ ++%% reg3 -> reg4 reg3' ++%% reg3' -> "*" reg3' ++%% reg3' -> "+" reg3' ++%% reg3' -> "?" reg3' ++%% reg3' -> empty ++ ++reg3(S0) -> ++ {L,S1} = reg4(S0), ++ reg3p(S1, L). ++ ++reg3p([$*|S], L) -> reg3p(S, {kclosure,L}); ++reg3p([$+|S], L) -> reg3p(S, {pclosure,L}); ++reg3p([$?|S], L) -> reg3p(S, {optional,L}); ++reg3p(S, L) -> {L,S}. ++ ++reg4([$(|S0]) -> ++ case reg(S0) of ++ {R,[$)|S1]} -> {R,S1}; ++ {_R,_S} -> throw({error,{unterminated,"("}}) ++ end; ++reg4([$\\,O1,O2,O3|S]) ++ when ((O1 >= $0) andalso ++ (O1 =< $7) andalso ++ (O2 >= $0) andalso ++ (O2 =< $7) andalso ++ (O3 >= $0) andalso ++ (O3 =< $7)) -> ++ {(O1*8 + O2)*8 + O3 - 73*$0,S}; ++reg4([$\\,C|S]) -> ++ {escape_char(C),S}; ++reg4([$\\]) -> ++ throw({error, {unterminated,"\\"}}); ++reg4([$^|S]) -> ++ {bos,S}; ++reg4([$$|S]) -> ++ {eos,S}; ++reg4([$.|S]) -> ++ {{comp_class,"\n"},S}; ++reg4("[^" ++ S0) -> ++ case char_class(S0) of ++ {Cc,[$]|S1]} -> {{comp_class,Cc},S1}; ++ {_Cc,_S} -> throw({error,{unterminated,"["}}) ++ end; ++reg4([$[|S0]) -> ++ case char_class(S0) of ++ {Cc,[$]|S1]} -> {{char_class,Cc},S1}; ++ {_Cc,_S1} -> throw({error,{unterminated,"["}}) ++ end; ++reg4([C|S]) ++ when (C =/= $*) andalso (C =/= $+) andalso (C =/= $?) andalso (C =/= $]) -> ++ {C, S}; ++reg4([C|_S]) -> ++ throw({error,{illegal,[C]}}); ++reg4([]) -> ++ {epsilon,[]}. ++ ++escape_char($n) -> $\n; %\n = LF ++escape_char($r) -> $\r; %\r = CR ++escape_char($t) -> $\t; %\t = TAB ++escape_char($v) -> $\v; %\v = VT ++escape_char($b) -> $\b; %\b = BS ++escape_char($f) -> $\f; %\f = FF ++escape_char($e) -> $\e; %\e = ESC ++escape_char($s) -> $\s; %\s = SPACE ++escape_char($d) -> $\d; %\d = DEL ++escape_char(C) -> C. ++ ++char_class([$]|S]) -> char_class(S, [$]]); ++char_class(S) -> char_class(S, []). ++ ++char($\\, [O1,O2,O3|S]) when ++ O1 >= $0, O1 =< $7, O2 >= $0, O2 =< $7, O3 >= $0, O3 =< $7 -> ++ {(O1*8 + O2)*8 + O3 - 73*$0,S}; ++char($\\, [C|S]) -> {escape_char(C),S}; ++char(C, S) -> {C,S}. ++ ++char_class([C1|S0], Cc) when C1 =/= $] -> ++ case char(C1, S0) of ++ {Cf,[$-,C2|S1]} when C2 =/= $] -> ++ case char(C2, S1) of ++ {Cl,S2} when Cf < Cl -> char_class(S2, [{Cf,Cl}|Cc]); ++ {Cl,_S2} -> throw({error,{char_class,[Cf,$-,Cl]}}) ++ end; ++ {C,S1} -> char_class(S1, [C|Cc]) ++ end; ++char_class(S, Cc) -> {Cc,S}. ++ ++ ++%% re_apply(String, StartPos, RegExp) -> re_app_res(). ++%% ++%% Apply the (parse of the) regular expression RegExp to String. If ++%% there is a match return the position of the remaining string and ++%% the string if else return 'nomatch'. BestMatch specifies if we want ++%% the longest match, or just a match. ++%% ++%% StartPos should be the real start position as it is used to decide ++%% if we ae at the beginning of the string. ++%% ++%% Pass two functions to re_apply_or so it can decide, on the basis ++%% of BestMatch, whether to just any take any match or try both to ++%% find the longest. This is slower but saves duplicatng code. ++ ++re_apply(S, St, RE) -> re_apply(RE, [], S, St). ++ ++re_apply(epsilon, More, S, P) -> %This always matches ++ re_apply_more(More, S, P); ++re_apply({'or',RE1,RE2}, More, S, P) -> ++ re_apply_or(re_apply(RE1, More, S, P), ++ re_apply(RE2, More, S, P)); ++re_apply({concat,RE1,RE2}, More, S0, P) -> ++ re_apply(RE1, [RE2|More], S0, P); ++re_apply({kclosure,CE}, More, S, P) -> ++ %% Be careful with the recursion, explicitly do one call before ++ %% looping. ++ re_apply_or(re_apply_more(More, S, P), ++ re_apply(CE, [{kclosure,CE}|More], S, P)); ++re_apply({pclosure,CE}, More, S, P) -> ++ re_apply(CE, [{kclosure,CE}|More], S, P); ++re_apply({optional,CE}, More, S, P) -> ++ re_apply_or(re_apply_more(More, S, P), ++ re_apply(CE, More, S, P)); ++re_apply(bos, More, S, 1) -> re_apply_more(More, S, 1); ++re_apply(eos, More, [$\n|S], P) -> re_apply_more(More, S, P); ++re_apply(eos, More, [], P) -> re_apply_more(More, [], P); ++re_apply({char_class,Cc}, More, [C|S], P) -> ++ case in_char_class(C, Cc) of ++ true -> re_apply_more(More, S, P+1); ++ false -> nomatch ++ end; ++re_apply({comp_class,Cc}, More, [C|S], P) -> ++ case in_char_class(C, Cc) of ++ true -> nomatch; ++ false -> re_apply_more(More, S, P+1) ++ end; ++re_apply(C, More, [C|S], P) when is_integer(C) -> ++ re_apply_more(More, S, P+1); ++re_apply(_RE, _More, _S, _P) -> nomatch. ++ ++%% re_apply_more([RegExp], String, Length) -> re_app_res(). ++ ++re_apply_more([RE|More], S, P) -> re_apply(RE, More, S, P); ++re_apply_more([], S, P) -> {match,P,S}. ++ ++%% in_char_class(Char, Class) -> bool(). ++ ++in_char_class(C, [{C1,C2}|_Cc]) when C >= C1, C =< C2 -> true; ++in_char_class(C, [C|_Cc]) -> true; ++in_char_class(C, [_|Cc]) -> in_char_class(C, Cc); ++in_char_class(_C, []) -> false. ++ ++%% re_apply_or(Match1, Match2) -> re_app_res(). ++%% If we want the best match then choose the longest match, else just ++%% choose one by trying sequentially. ++ ++re_apply_or({match,P1,S1}, {match,P2,_S2}) when P1 >= P2 -> {match,P1,S1}; ++re_apply_or({match,_P1,_S1}, {match,P2,S2}) -> {match,P2,S2}; ++re_apply_or(nomatch, R2) -> R2; ++re_apply_or(R1, nomatch) -> R1. ++ ++ ++matches(S, RE, St) -> ++ case first_match(RE, S, St) of ++ {St1,0} -> ++ [{St1,0}|matches(string:substr(S, St1+2-St), RE, St1+1)]; ++ {St1,L1} -> ++ [{St1,L1}|matches(string:substr(S, St1+L1+1-St), RE, St1+L1)]; ++ nomatch -> ++ [] ++ end. ++ ++sub_match(S, RE, St) -> ++ case first_match(RE, S, St) of ++ {St1,L1} -> [{St1,L1}]; ++ nomatch -> [] ++ end. ++ ++sub_repl([{St,L}|Ss], Rep, S, Pos) -> ++ Rs = sub_repl(Ss, Rep, S, St+L), ++ string:substr(S, Pos, St-Pos) ++ ++ sub_repl(Rep, string:substr(S, St, L), Rs); ++sub_repl([], _Rep, S, Pos) -> ++ string:substr(S, Pos). ++ ++sub_repl([$&|Rep], M, Rest) -> M ++ sub_repl(Rep, M, Rest); ++sub_repl("\\&" ++ Rep, M, Rest) -> [$&|sub_repl(Rep, M, Rest)]; ++sub_repl([C|Rep], M, Rest) -> [C|sub_repl(Rep, M, Rest)]; ++sub_repl([], _M, Rest) -> Rest. ++ ++split_apply(S, RE, Trim) -> split_apply(S, 1, RE, Trim, []). ++ ++split_apply([], _P, _RE, true, []) -> ++ []; ++split_apply([], _P, _RE, _T, Sub) -> ++ [lists:reverse(Sub)]; ++split_apply(S, P, RE, T, Sub) -> ++ case re_apply(S, P, RE) of ++ {match,P,_Rest} -> ++ split_apply(tl(S), P+1, RE, T, [hd(S)|Sub]); ++ {match,P1,Rest} -> ++ [lists:reverse(Sub)|split_apply(Rest, P1, RE, T, [])]; ++ nomatch -> ++ split_apply(tl(S), P+1, RE, T, [hd(S)|Sub]) ++ end. +--- a/lib/inets/test/httpd_SUITE.erl ++++ b/lib/inets/test/httpd_SUITE.erl +@@ -70,7 +70,8 @@ all() -> + {group, https_security}, + {group, http_reload}, + {group, https_reload}, +- {group, http_mime_types} ++ {group, http_mime_types}, ++ mime_types_format + ]. + + groups() -> +@@ -1291,6 +1292,115 @@ non_disturbing(Config) when is_list(Config)-> + inets_test_lib:close(Type, Socket), + [{server_name, "httpd_non_disturbing_" ++ Version}] = httpd:info(Server, [server_name]). + ++%%------------------------------------------------------------------------- ++mime_types_format(Config) when is_list(Config) -> ++ DataDir = proplists:get_value(data_dir, Config), ++ MimeTypes = filename:join(DataDir, "mime_types.txt"), ++ {ok,[{"wrl","x-world/x-vrml"}, ++ {"vrml","x-world/x-vrml"}, ++ {"ice","x-conference/x-cooltalk"}, ++ {"movie","video/x-sgi-movie"}, ++ {"avi","video/x-msvideo"}, ++ {"qt","video/quicktime"}, ++ {"mov","video/quicktime"}, ++ {"mpeg","video/mpeg"}, ++ {"mpg","video/mpeg"}, ++ {"mpe","video/mpeg"}, ++ {"sgml","text/x-sgml"}, ++ {"sgm","text/x-sgml"}, ++ {"etx","text/x-setext"}, ++ {"tsv","text/tab-separated-values"}, ++ {"rtx","text/richtext"}, ++ {"txt","text/plain"}, ++ {"html","text/html"}, ++ {"htm","text/html"}, ++ {"css","text/css"}, ++ {"xwd","image/x-xwindowdump"}, ++ {"xpm","image/x-xpixmap"}, ++ {"xbm","image/x-xbitmap"}, ++ {"rgb","image/x-rgb"}, ++ {"ppm","image/x-portable-pixmap"}, ++ {"pgm","image/x-portable-graymap"}, ++ {"pbm","image/x-portable-bitmap"}, ++ {"pnm","image/x-portable-anymap"}, ++ {"ras","image/x-cmu-raster"}, ++ {"tiff","image/tiff"}, ++ {"tif","image/tiff"}, ++ {"png","image/png"}, ++ {"jpeg","image/jpeg"}, ++ {"jpg","image/jpeg"}, ++ {"jpe","image/jpeg"}, ++ {"ief","image/ief"}, ++ {"gif","image/gif"}, ++ {"pdb","chemical/x-pdb"}, ++ {"xyz","chemical/x-pdb"}, ++ {"wav","audio/x-wav"}, ++ {"ra","audio/x-realaudio"}, ++ {"rpm","audio/x-pn-realaudio-plugin"}, ++ {"ram","audio/x-pn-realaudio"}, ++ {"aif","audio/x-aiff"}, ++ {"aiff","audio/x-aiff"}, ++ {"aifc","audio/x-aiff"}, ++ {"mpga","audio/mpeg"}, ++ {"mp2","audio/mpeg"}, ++ {"au","audio/basic"}, ++ {"snd","audio/basic"}, ++ {"zip","application/zip"}, ++ {"src","application/x-wais-source"}, ++ {"ustar","application/x-ustar"}, ++ {"ms","application/x-troff-ms"}, ++ {"me","application/x-troff-me"}, ++ {"man","application/x-troff-man"}, ++ {"t","application/x-troff"}, ++ {"tr","application/x-troff"}, ++ {"roff","application/x-troff"}, ++ {"texinfo","application/x-texinfo"}, ++ {"texi","application/x-texinfo"}, ++ {"tex","application/x-tex"}, ++ {"tcl","application/x-tcl"}, ++ {"tar","application/x-tar"}, ++ {"sv4crc","application/x-sv4crc"}, ++ {"sv4cpio","application/x-sv4cpio"}, ++ {"sit","application/x-stuffit"}, ++ {"shar","application/x-shar"}, ++ {"sh","application/x-sh"}, ++ {"nc","application/x-netcdf"}, ++ {"cdf","application/x-netcdf"}, ++ {"mif","application/x-mif"}, ++ {"latex","application/x-latex"}, ++ {"skp","application/x-koan"}, ++ {"skd","application/x-koan"}, ++ {"skt","application/x-koan"}, ++ {"skm","application/x-koan"}, ++ {"cgi","application/x-httpd-cgi"}, ++ {"hdf","application/x-hdf"}, ++ {"gz","application/x-gzip"}, ++ {"gtar","application/x-gtar"}, ++ {"dvi","application/x-dvi"}, ++ {"dcr","application/x-director"}, ++ {"dir","application/x-director"}, ++ {"dxr","application/x-director"}, ++ {"csh","application/x-csh"}, ++ {"cpio","application/x-cpio"}, ++ {"Z","application/x-compress"}, ++ {"vcd","application/x-cdlink"}, ++ {"bcpio","application/x-bcpio"}, ++ {"rtf","application/rtf"}, ++ {"ppt","application/powerpoint"}, ++ {"ai","application/postscript"}, ++ {"eps","application/postscript"}, ++ {"ps","application/postscript"}, ++ {"pdf","application/pdf"}, ++ {"oda","application/oda"}, ++ {"bin","application/octet-stream"}, ++ {"dms","application/octet-stream"}, ++ {"lha","application/octet-stream"}, ++ {"lzh","application/octet-stream"}, ++ {"exe","application/octet-stream"}, ++ {"class","application/octet-stream"}, ++ {"doc","application/msword"}, ++ {"cpt","application/mac-compactpro"}, ++ {"hqx","application/mac-binhex40"}]} = httpd_conf:load_mime_types(MimeTypes). + + %%-------------------------------------------------------------------- + %% Internal functions ----------------------------------- +--- /dev/null ++++ b/lib/inets/test/httpd_SUITE_data/mime_types.txt +@@ -0,0 +1,100 @@ ++# This is a comment. I love comments. ++ ++ ++application/activemessage ++application/andrew-inset ++application/applefile ++application/atomicmail ++application/dca-rft ++application/dec-dx ++application/mac-binhex40 hqx ++application/mac-compactpro cpt ++application/macwriteii ++application/msword doc ++application/news-message-id ++application/news-transmission ++application/octet-stream bin dms lha lzh exe class ++application/oda oda ++application/pdf pdf ++application/postscript ai eps ps ++application/powerpoint ppt ++application/remote-printing ++application/rtf rtf ++application/slate ++application/wita ++application/wordperfect5.1 ++application/x-bcpio bcpio ++application/x-cdlink vcd ++application/x-compress Z ++application/x-cpio cpio ++application/x-csh csh ++application/x-director dcr dir dxr ++application/x-dvi dvi ++application/x-gtar gtar ++application/x-gzip gz ++application/x-hdf hdf ++application/x-httpd-cgi cgi ++application/x-koan skp skd skt skm ++application/x-latex latex ++application/x-mif mif ++application/x-netcdf nc cdf ++application/x-sh sh ++application/x-shar shar ++application/x-stuffit sit ++application/x-sv4cpio sv4cpio ++application/x-sv4crc sv4crc ++application/x-tar tar ++application/x-tcl tcl ++application/x-tex tex ++application/x-texinfo texinfo texi ++application/x-troff t tr roff ++application/x-troff-man man ++application/x-troff-me me ++application/x-troff-ms ms ++application/x-ustar ustar ++application/x-wais-source src ++application/zip zip ++audio/basic au snd ++audio/mpeg mpga mp2 ++audio/x-aiff aif aiff aifc ++audio/x-pn-realaudio ram ++audio/x-pn-realaudio-plugin rpm ++audio/x-realaudio ra ++audio/x-wav wav ++chemical/x-pdb pdb xyz ++image/gif gif ++image/ief ief ++image/jpeg jpeg jpg jpe ++image/png png ++image/tiff tiff tif ++image/x-cmu-raster ras ++image/x-portable-anymap pnm ++image/x-portable-bitmap pbm ++image/x-portable-graymap pgm ++image/x-portable-pixmap ppm ++image/x-rgb rgb ++image/x-xbitmap xbm ++image/x-xpixmap xpm ++image/x-xwindowdump xwd ++message/external-body ++message/news ++message/partial ++message/rfc822 ++multipart/alternative ++multipart/appledouble ++multipart/digest ++multipart/mixed ++multipart/parallel ++text/css css ++text/html html htm ++text/plain txt ++text/richtext rtx ++text/tab-separated-values tsv ++text/x-setext etx ++text/x-sgml sgml sgm ++video/mpeg mpeg mpg mpe ++video/quicktime qt mov ++video/x-msvideo avi ++video/x-sgi-movie movie ++x-conference/x-cooltalk ice ++x-world/x-vrml wrl vrml +--- a/lib/inets/vsn.mk ++++ b/lib/inets/vsn.mk +@@ -19,6 +19,6 @@ + # %CopyrightEnd% + + APPLICATION = inets +-INETS_VSN = 6.2.2 ++INETS_VSN = 6.2.4 + PRE_VSN = + APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)" +--- a/lib/ssl/doc/src/notes.xml ++++ b/lib/ssl/doc/src/notes.xml +@@ -28,6 +28,68 @@ +

This document describes the changes made to the SSL application.

+ + ++
SSL 7.3.3 ++ ++
Fixed Bugs and Malfunctions ++ ++ ++

++ Correct ssl:prf/5 to use the negotiated cipher suite's ++ prf function in ssl:prf/5 instead of the default prf.

++

++ Own Id: OTP-13546

++
++ ++

++ Timeouts may have the value 0, guards have been corrected ++ to allow this

++

++ Own Id: OTP-13635

++
++ ++

++ Change of internal handling of hash sign pairs as the ++ used one enforced to much restrictions making some valid ++ combinations unavailable.

++

++ Own Id: OTP-13670

++
++
++
++ ++ ++
Improvements and New Features ++ ++ ++

++ Create a little randomness in sending of session ++ invalidation messages, to mitigate load when whole table ++ is invalidated.

++

++ Own Id: OTP-13490

++
++
++
++ ++
++ ++
SSL 7.3.2 ++ ++
Fixed Bugs and Malfunctions ++ ++ ++

++ Correct cipher suites conversion and gaurd expression. ++ Caused problems with GCM cipher suites and client side ++ option to set signature_algorithms extention values.

++

++ Own Id: OTP-13525

++
++
++
++ ++
++ +
SSL 7.3.1 + +
Fixed Bugs and Malfunctions +--- a/lib/ssl/src/ssl.erl ++++ b/lib/ssl/src/ssl.erl +@@ -97,7 +97,7 @@ connect(Socket, SslOptions) when is_port(Socket) -> + connect(Socket, SslOptions, infinity). + + connect(Socket, SslOptions0, Timeout) when is_port(Socket), +- (is_integer(Timeout) andalso Timeout > 0) or (Timeout == infinity) -> ++ (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) -> + {Transport,_,_,_} = proplists:get_value(cb_info, SslOptions0, + {gen_tcp, tcp, tcp_closed, tcp_error}), + EmulatedOptions = ssl_socket:emulated_options(), +@@ -123,7 +123,7 @@ connect(Socket, SslOptions0, Timeout) when is_port(Socket), + connect(Host, Port, Options) -> + connect(Host, Port, Options, infinity). + +-connect(Host, Port, Options, Timeout) when (is_integer(Timeout) andalso Timeout > 0) or (Timeout == infinity) -> ++connect(Host, Port, Options, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) -> + try handle_options(Options, client) of + {ok, Config} -> + do_connect(Host,Port,Config,Timeout) +@@ -173,7 +173,7 @@ transport_accept(#sslsocket{pid = {ListenSocket, + #config{transport_info = {Transport,_,_, _} =CbInfo, + connection_cb = ConnectionCb, + ssl = SslOpts, +- emulated = Tracker}}}, Timeout) when (is_integer(Timeout) andalso Timeout > 0) or (Timeout == infinity) -> ++ emulated = Tracker}}}, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) -> + case Transport:accept(ListenSocket, Timeout) of + {ok, Socket} -> + {ok, EmOpts} = ssl_socket:get_emulated_opts(Tracker), +@@ -206,25 +206,25 @@ transport_accept(#sslsocket{pid = {ListenSocket, + ssl_accept(ListenSocket) -> + ssl_accept(ListenSocket, infinity). + +-ssl_accept(#sslsocket{} = Socket, Timeout) when (is_integer(Timeout) andalso Timeout > 0) or (Timeout == infinity) -> ++ssl_accept(#sslsocket{} = Socket, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) -> + ssl_connection:handshake(Socket, Timeout); +- +-ssl_accept(ListenSocket, SslOptions) when is_port(ListenSocket) -> ++ ++ssl_accept(ListenSocket, SslOptions) when is_port(ListenSocket) -> + ssl_accept(ListenSocket, SslOptions, infinity). + +-ssl_accept(#sslsocket{} = Socket, [], Timeout) when (is_integer(Timeout) andalso Timeout > 0) or (Timeout == infinity)-> ++ssl_accept(#sslsocket{} = Socket, [], Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)-> + ssl_accept(#sslsocket{} = Socket, Timeout); +-ssl_accept(#sslsocket{fd = {_, _, _, Tracker}} = Socket, SslOpts0, Timeout) when +- (is_integer(Timeout) andalso Timeout > 0) or (Timeout == infinity)-> +- try +- {ok, EmOpts, InheritedSslOpts} = ssl_socket:get_all_opts(Tracker), ++ssl_accept(#sslsocket{fd = {_, _, _, Tracker}} = Socket, SslOpts0, Timeout) when ++ (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)-> ++ try ++ {ok, EmOpts, InheritedSslOpts} = ssl_socket:get_all_opts(Tracker), + SslOpts = handle_options(SslOpts0, InheritedSslOpts), + ssl_connection:handshake(Socket, {SslOpts, emulated_socket_options(EmOpts, #socket_options{})}, Timeout) + catch + Error = {error, _Reason} -> Error + end; + ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket), +- (is_integer(Timeout) andalso Timeout > 0) or (Timeout == infinity) -> ++ (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) -> + {Transport,_,_,_} = + proplists:get_value(cb_info, SslOptions, {gen_tcp, tcp, tcp_closed, tcp_error}), + EmulatedOptions = ssl_socket:emulated_options(), +@@ -252,17 +252,17 @@ close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_, _, _} + Transport:close(ListenSocket). + + %%-------------------------------------------------------------------- +--spec close(#sslsocket{}, integer() | {pid(), integer()}) -> term(). ++-spec close(#sslsocket{}, timeout() | {pid(), integer()}) -> term(). + %% + %% Description: Close an ssl connection + %%-------------------------------------------------------------------- +-close(#sslsocket{pid = TLSPid}, +- {Pid, Timeout} = DownGrade) when is_pid(TLSPid), +- is_pid(Pid), +- (is_integer(Timeout) andalso Timeout > 0) or (Timeout == infinity) -> ++close(#sslsocket{pid = TLSPid}, ++ {Pid, Timeout} = DownGrade) when is_pid(TLSPid), ++ is_pid(Pid), ++ (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) -> + ssl_connection:close(TLSPid, {close, DownGrade}); +-close(#sslsocket{pid = TLSPid}, Timeout) when is_pid(TLSPid), +- (is_integer(Timeout) andalso Timeout > 0) or (Timeout == infinity) -> ++close(#sslsocket{pid = TLSPid}, Timeout) when is_pid(TLSPid), ++ (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) -> + ssl_connection:close(TLSPid, {close, Timeout}); + close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_, _, _}}}}, _) -> + Transport:close(ListenSocket). +@@ -286,7 +286,7 @@ send(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport, _, _, _} + recv(Socket, Length) -> + recv(Socket, Length, infinity). + recv(#sslsocket{pid = Pid}, Length, Timeout) when is_pid(Pid), +- (is_integer(Timeout) andalso Timeout > 0) or (Timeout == infinity)-> ++ (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)-> + ssl_connection:recv(Pid, Length, Timeout); + recv(#sslsocket{pid = {Listen, + #config{transport_info = {Transport, _, _, _}}}}, _,_) when is_port(Listen)-> +--- a/lib/ssl/src/ssl_cipher.erl ++++ b/lib/ssl/src/ssl_cipher.erl +@@ -979,21 +979,21 @@ suite({ecdh_rsa, aes_256_cbc, sha384, sha384}) -> + %% RFC 5288 AES-GCM Cipher Suites + suite({rsa, aes_128_gcm, null, sha256}) -> + ?TLS_RSA_WITH_AES_128_GCM_SHA256; +-suite({rsa, aes_256_gcm, null}) -> ++suite({rsa, aes_256_gcm, null, sha384}) -> + ?TLS_RSA_WITH_AES_256_GCM_SHA384; +-suite({dhe_rsa, aes_128_gcm, null, sha384}) -> ++suite({dhe_rsa, aes_128_gcm, null, sha256}) -> + ?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256; +-suite({dhe_rsa, aes_256_gcm, null, sha256}) -> ++suite({dhe_rsa, aes_256_gcm, null, sha384}) -> + ?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384; +-suite({dh_rsa, aes_128_gcm, null, sha384}) -> ++suite({dh_rsa, aes_128_gcm, null, sha256}) -> + ?TLS_DH_RSA_WITH_AES_128_GCM_SHA256; +-suite({dh_rsa, aes_256_gcm, null, sha256}) -> ++suite({dh_rsa, aes_256_gcm, null, sha384}) -> + ?TLS_DH_RSA_WITH_AES_256_GCM_SHA384; +-suite({dhe_dss, aes_128_gcm, null, sha384}) -> ++suite({dhe_dss, aes_128_gcm, null, sha256}) -> + ?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256; +-suite({dhe_dss, aes_256_gcm, null, sha256}) -> ++suite({dhe_dss, aes_256_gcm, null, sha384}) -> + ?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384; +-suite({dh_dss, aes_128_gcm, null, sha384}) -> ++suite({dh_dss, aes_128_gcm, null, sha256}) -> + ?TLS_DH_DSS_WITH_AES_128_GCM_SHA256; + suite({dh_dss, aes_256_gcm, null, sha384}) -> + ?TLS_DH_DSS_WITH_AES_256_GCM_SHA384; +--- a/lib/ssl/src/ssl_connection.erl ++++ b/lib/ssl/src/ssl_connection.erl +@@ -821,7 +821,8 @@ handle_sync_event({prf, Secret, Label, Seed, WantedLength}, _, StateName, + SecParams = ConnectionState#connection_state.security_parameters, + #security_parameters{master_secret = MasterSecret, + client_random = ClientRandom, +- server_random = ServerRandom} = SecParams, ++ server_random = ServerRandom, ++ prf_algorithm = PRFAlgorithm} = SecParams, + Reply = try + SecretToUse = case Secret of + _ when is_binary(Secret) -> Secret; +@@ -832,7 +833,7 @@ handle_sync_event({prf, Secret, Label, Seed, WantedLength}, _, StateName, + (client_random, Acc) -> [ClientRandom|Acc]; + (server_random, Acc) -> [ServerRandom|Acc] + end, [], Seed)), +- ssl_handshake:prf(Version, SecretToUse, Label, SeedToUse, WantedLength) ++ ssl_handshake:prf(Version, PRFAlgorithm, SecretToUse, Label, SeedToUse, WantedLength) + catch + exit:_ -> {error, badarg}; + error:Reason -> {error, Reason} +--- a/lib/ssl/src/ssl_handshake.erl ++++ b/lib/ssl/src/ssl_handshake.erl +@@ -74,7 +74,7 @@ + ]). + + %% MISC +--export([select_version/3, prf/5, select_hashsign/5, ++-export([select_version/3, prf/6, select_hashsign/5, + select_hashsign_algs/3, + premaster_secret/2, premaster_secret/3, premaster_secret/4]). + +@@ -564,17 +564,15 @@ server_key_exchange_hash(md5sha, Value) -> + server_key_exchange_hash(Hash, Value) -> + crypto:hash(Hash, Value). + %%-------------------------------------------------------------------- +--spec prf(ssl_record:ssl_version(), binary(), binary(), [binary()], non_neg_integer()) -> ++-spec prf(ssl_record:ssl_version(), non_neg_integer(), binary(), binary(), [binary()], non_neg_integer()) -> + {ok, binary()} | {error, undefined}. + %% + %% Description: use the TLS PRF to generate key material + %%-------------------------------------------------------------------- +-prf({3,0}, _, _, _, _) -> ++prf({3,0}, _, _, _, _, _) -> + {error, undefined}; +-prf({3,1}, Secret, Label, Seed, WantedLength) -> +- {ok, tls_v1:prf(?MD5SHA, Secret, Label, Seed, WantedLength)}; +-prf({3,_N}, Secret, Label, Seed, WantedLength) -> +- {ok, tls_v1:prf(?SHA256, Secret, Label, Seed, WantedLength)}. ++prf({3,_N}, PRFAlgo, Secret, Label, Seed, WantedLength) -> ++ {ok, tls_v1:prf(PRFAlgo, Secret, Label, Seed, WantedLength)}. + + + %%-------------------------------------------------------------------- +--- a/lib/ssl/src/ssl_manager.erl ++++ b/lib/ssl/src/ssl_manager.erl +@@ -67,6 +67,7 @@ + -define(CLEAN_SESSION_DB, 60000). + -define(CLEAN_CERT_DB, 500). + -define(DEFAULT_MAX_SESSION_CACHE, 1000). ++-define(LOAD_MITIGATION, 10). + + %%==================================================================== + %% API +@@ -196,10 +197,12 @@ register_session(Port, Session) -> + %%-------------------------------------------------------------------- + -spec invalidate_session(host(), inet:port_number(), #session{}) -> ok. + invalidate_session(Host, Port, Session) -> ++ load_mitigation(), + cast({invalidate_session, Host, Port, Session}). + + -spec invalidate_session(inet:port_number(), #session{}) -> ok. + invalidate_session(Port, Session) -> ++ load_mitigation(), + cast({invalidate_session, Port, Session}). + + -spec invalidate_pem(File::binary()) -> ok. +@@ -719,3 +722,11 @@ invalidate_session_cache(undefined, CacheCb, Cache) -> + start_session_validator(Cache, CacheCb, {invalidate_before, erlang:monotonic_time()}, undefined); + invalidate_session_cache(Pid, _CacheCb, _Cache) -> + Pid. ++ ++load_mitigation() -> ++ MSec = rand:uniform(?LOAD_MITIGATION), ++ receive ++ after ++ MSec -> ++ continue ++ end. +--- a/lib/ssl/src/tls_handshake.erl ++++ b/lib/ssl/src/tls_handshake.erl +@@ -278,11 +278,13 @@ handle_server_hello_extensions(Version, SessionId, Random, CipherSuite, + {Version, SessionId, ConnectionStates, ProtoExt, Protocol} + end. + +-available_signature_algs(undefined, SupportedHashSigns, _, {Major, Minor}) when (Major < 3) andalso (Minor < 3) -> ++available_signature_algs(undefined, SupportedHashSigns, _, {Major, Minor}) when ++ (Major >= 3) andalso (Minor >= 3) -> + SupportedHashSigns; + available_signature_algs(#hash_sign_algos{hash_sign_algos = ClientHashSigns}, SupportedHashSigns, +- _, {Major, Minor}) when (Major < 3) andalso (Minor < 3) -> +- ordsets:intersection(ClientHashSigns, SupportedHashSigns); ++ _, {Major, Minor}) when (Major >= 3) andalso (Minor >= 3) -> ++ sets:to_list(sets:intersection(sets:from_list(ClientHashSigns), ++ sets:from_list(SupportedHashSigns))); + available_signature_algs(_, _, _, _) -> + undefined. + +--- a/lib/ssl/test/ssl_basic_SUITE.erl ++++ b/lib/ssl/test/ssl_basic_SUITE.erl +@@ -88,7 +88,8 @@ basic_tests() -> + connect_dist, + clear_pem_cache, + defaults, +- fallback ++ fallback, ++ cipher_format + ]. + + options_tests() -> +@@ -144,7 +145,8 @@ api_tests() -> + versions_option, + server_name_indication_option, + accept_pool, +- new_options_in_accept ++ new_options_in_accept, ++ prf + ]. + + session_tests() -> +@@ -323,6 +325,31 @@ init_per_testcase(rizzo, Config) -> + ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]), + ct:timetrap({seconds, 40}), + Config; ++init_per_testcase(prf, Config) -> ++ ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]), ++ ct:timetrap({seconds, 40}), ++ case ?config(tc_group_path, Config) of ++ [] -> Prop = []; ++ [Prop] -> Prop ++ end, ++ case ?config(name, Prop) of ++ undefined -> TlsVersions = [sslv3, tlsv1, 'tlsv1.1', 'tlsv1.2']; ++ TlsVersion when is_atom(TlsVersion) -> ++ TlsVersions = [TlsVersion] ++ end, ++ PRFS=[md5, sha, sha256, sha384, sha512], ++ %All are the result of running tls_v1:prf(PrfAlgo, <<>>, <<>>, <<>>, 16) ++ %with the specified PRF algorithm ++ ExpectedPrfResults= ++ [{md5, <<96,139,180,171,236,210,13,10,28,32,2,23,88,224,235,199>>}, ++ {sha, <<95,3,183,114,33,169,197,187,231,243,19,242,220,228,70,151>>}, ++ {sha256, <<166,249,145,171,43,95,158,232,6,60,17,90,183,180,0,155>>}, ++ {sha384, <<153,182,217,96,186,130,105,85,65,103,123,247,146,91,47,106>>}, ++ {sha512, <<145,8,98,38,243,96,42,94,163,33,53,49,241,4,127,28>>}, ++ %TLS 1.0 and 1.1 PRF: ++ {md5sha, <<63,136,3,217,205,123,200,177,251,211,17,229,132,4,173,80>>}], ++ TestPlan = prf_create_plan(TlsVersions, PRFS, ExpectedPrfResults), ++ [{prf_test_plan, TestPlan} | Config]; + + init_per_testcase(TestCase, Config) when TestCase == ssl_accept_timeout; + TestCase == client_closes_socket; +@@ -428,6 +455,25 @@ new_options_in_accept(Config) when is_list(Config) -> + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + %%-------------------------------------------------------------------- ++prf() -> ++ [{doc,"Test that ssl:prf/5 uses the negotiated PRF."}]. ++prf(Config) when is_list(Config) -> ++ TestPlan = ?config(prf_test_plan, Config), ++ case TestPlan of ++ [] -> ct:fail({error, empty_prf_test_plan}); ++ _ -> lists:foreach(fun(Suite) -> ++ lists:foreach( ++ fun(Test) -> ++ V = ?config(tls_ver, Test), ++ C = ?config(ciphers, Test), ++ E = ?config(expected, Test), ++ P = ?config(prf, Test), ++ prf_run_test(Config, V, C, E, P) ++ end, Suite) ++ end, TestPlan) ++ end. ++ ++%%-------------------------------------------------------------------- + + connection_info() -> + [{doc,"Test the API function ssl:connection_information/1"}]. +@@ -762,6 +808,14 @@ fallback(Config) when is_list(Config) -> + Client, {error,{tls_alert,"inappropriate fallback"}}). + + %%-------------------------------------------------------------------- ++cipher_format() -> ++ [{doc, "Test that cipher conversion from tuples to binarys works"}]. ++cipher_format(Config) when is_list(Config) -> ++ {ok, Socket} = ssl:listen(0, [{ciphers, ssl:cipher_suites()}]), ++ ssl:close(Socket). ++ ++%%-------------------------------------------------------------------- ++ + peername() -> + [{doc,"Test API function peername/1"}]. + +@@ -3653,8 +3707,84 @@ basic_test(Config) -> + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + ++prf_create_plan(TlsVersions, PRFs, Results) -> ++ lists:foldl(fun(Ver, Acc) -> ++ A = prf_ciphers_and_expected(Ver, PRFs, Results), ++ [A|Acc] ++ end, [], TlsVersions). ++prf_ciphers_and_expected(TlsVer, PRFs, Results) -> ++ case TlsVer of ++ TlsVer when TlsVer == sslv3 orelse TlsVer == tlsv1 ++ orelse TlsVer == 'tlsv1.1' -> ++ Ciphers = ssl:cipher_suites(), ++ {_, Expected} = lists:keyfind(md5sha, 1, Results), ++ [[{tls_ver, TlsVer}, {ciphers, Ciphers}, {expected, Expected}, {prf, md5sha}]]; ++ 'tlsv1.2' -> ++ lists:foldl( ++ fun(PRF, Acc) -> ++ Ciphers = prf_get_ciphers(TlsVer, PRF), ++ case Ciphers of ++ [] -> ++ ct:log("No ciphers for PRF algorithm ~p. Skipping.", [PRF]), ++ Acc; ++ Ciphers -> ++ {_, Expected} = lists:keyfind(PRF, 1, Results), ++ [[{tls_ver, TlsVer}, {ciphers, Ciphers}, {expected, Expected}, ++ {prf, PRF}] | Acc] ++ end ++ end, [], PRFs) ++ end. ++prf_get_ciphers(TlsVer, PRF) -> ++ case TlsVer of ++ 'tlsv1.2' -> ++ lists:filter( ++ fun(C) when tuple_size(C) == 4 andalso ++ element(4, C) == PRF -> ++ true; ++ (_) -> false ++ end, ssl:cipher_suites()) ++ end. ++prf_run_test(_, TlsVer, [], _, Prf) -> ++ ct:fail({error, cipher_list_empty, TlsVer, Prf}); ++prf_run_test(Config, TlsVer, Ciphers, Expected, Prf) -> ++ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), ++ BaseOpts = [{active, true}, {versions, [TlsVer]}, {ciphers, Ciphers}], ++ ServerOpts = BaseOpts ++ ?config(server_opts, Config), ++ ClientOpts = BaseOpts ++ ?config(client_opts, Config), ++ Server = ssl_test_lib:start_server( ++ [{node, ServerNode}, {port, 0}, {from, self()}, ++ {mfa, {?MODULE, prf_verify_value, [TlsVer, Expected, Prf]}}, ++ {options, ServerOpts}]), ++ Port = ssl_test_lib:inet_port(Server), ++ Client = ssl_test_lib:start_client( ++ [{node, ClientNode}, {port, Port}, ++ {host, Hostname}, {from, self()}, ++ {mfa, {?MODULE, prf_verify_value, [TlsVer, Expected, Prf]}}, ++ {options, ClientOpts}]), ++ ssl_test_lib:check_result(Server, ok, Client, ok), ++ ssl_test_lib:close(Server), ++ ssl_test_lib:close(Client). ++prf_verify_value(Socket, TlsVer, Expected, Algo) -> ++ Ret = ssl:prf(Socket, <<>>, <<>>, [<<>>], 16), ++ case TlsVer of ++ sslv3 -> ++ case Ret of ++ {error, undefined} -> ok; ++ _ -> ++ {error, {expected, {error, undefined}, ++ got, Ret, tls_ver, TlsVer, prf_algorithm, Algo}} ++ end; ++ _ -> ++ case Ret of ++ {ok, Expected} -> ok; ++ {ok, Val} -> {error, {expected, Expected, got, Val, tls_ver, TlsVer, ++ prf_algorithm, Algo}} ++ end ++ end. ++ + send_recv_result_timeout_client(Socket) -> + {error, timeout} = ssl:recv(Socket, 11, 500), ++ {error, timeout} = ssl:recv(Socket, 11, 0), + ssl:send(Socket, "Hello world"), + receive + Msg -> +--- a/lib/ssl/vsn.mk ++++ b/lib/ssl/vsn.mk +@@ -1 +1 @@ +-SSL_VSN = 7.3.1 ++SSL_VSN = 7.3.3 +--- a/lib/test_server/src/test_server.erl ++++ b/lib/test_server/src/test_server.erl +@@ -2165,10 +2165,19 @@ get_timetrap_info(TCPid, SendToServer) -> + Timers -> + case [Info || {Handle,Pid,Info} <- Timers, + Pid == TCPid, Handle /= infinity] of +- [I|_] -> +- I; ++ [{TVal,true}|_] -> ++ {TVal,{true,test_server:timetrap_scale_factor()}}; ++ [{TVal,false}|_] -> ++ {TVal,{false,1}}; + [] when SendToServer == true -> +- tc_supervisor_req({get_timetrap_info,TCPid}); ++ case tc_supervisor_req({get_timetrap_info,TCPid}) of ++ {TVal,true} -> ++ {TVal,{true,test_server:timetrap_scale_factor()}}; ++ {TVal,false} -> ++ {TVal,{false,1}}; ++ Error -> ++ Error ++ end; + [] -> + undefined + end +--- a/lib/test_server/src/test_server_gl.erl ++++ b/lib/test_server/src/test_server_gl.erl +@@ -131,6 +131,10 @@ set_props(GL, PropList) -> + %%% Internal functions. + + init([]) -> ++ EscChars = case application:get_env(test_server, esc_chars) of ++ {ok,ECBool} -> ECBool; ++ _ -> true ++ end, + {ok,#st{tc_supervisor=none, + minor=none, + minor_monitor=none, +@@ -139,7 +143,7 @@ init([]) -> + permit_io=gb_sets:empty(), + auto_nl=true, + levels={1,19,10}, +- escape_chars=true ++ escape_chars=EscChars + }}. + + req(GL, Req) -> +--- a/otp_versions.table ++++ b/otp_versions.table +@@ -1,3 +1,5 @@ ++OTP-18.3.4 : inets-6.2.4 ssl-7.3.3 # asn1-4.0.2 common_test-1.12.1 compiler-6.0.3 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2.1 cosProperty-1.2 cosTime-1.2.1 cosTransactions-1.3.1 crypto-3.6.3 debugger-4.1.2 dialyzer-2.9 diameter-1.11.2 edoc-0.7.18 eldap-1.2.1 erl_docgen-0.4.2 erl_interface-3.8.2 erts-7.3.1 et-1.5.1 eunit-2.2.13 gs-1.6 hipe-3.15 ic-4.4 jinterface-1.6.1 kernel-4.2 megaco-3.18 mnesia-4.13.4 observer-2.1.2 odbc-2.11.1 orber-3.8.1 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1.1 reltool-0.7 runtime_tools-1.9.3 sasl-2.7 snmp-5.2.2 ssh-4.2.2 stdlib-2.8 syntax_tools-1.7 test_server-3.10 tools-2.8.3 typer-0.9.10 webtool-0.9.1 wx-1.6.1 xmerl-1.3.10 : ++OTP-18.3.3 : common_test-1.12.1 inets-6.2.3 ssl-7.3.2 # asn1-4.0.2 compiler-6.0.3 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2.1 cosProperty-1.2 cosTime-1.2.1 cosTransactions-1.3.1 crypto-3.6.3 debugger-4.1.2 dialyzer-2.9 diameter-1.11.2 edoc-0.7.18 eldap-1.2.1 erl_docgen-0.4.2 erl_interface-3.8.2 erts-7.3.1 et-1.5.1 eunit-2.2.13 gs-1.6 hipe-3.15 ic-4.4 jinterface-1.6.1 kernel-4.2 megaco-3.18 mnesia-4.13.4 observer-2.1.2 odbc-2.11.1 orber-3.8.1 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1.1 reltool-0.7 runtime_tools-1.9.3 sasl-2.7 snmp-5.2.2 ssh-4.2.2 stdlib-2.8 syntax_tools-1.7 test_server-3.10 tools-2.8.3 typer-0.9.10 webtool-0.9.1 wx-1.6.1 xmerl-1.3.10 : + OTP-18.3.2 : inets-6.2.2 ssl-7.3.1 # asn1-4.0.2 common_test-1.12 compiler-6.0.3 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2.1 cosProperty-1.2 cosTime-1.2.1 cosTransactions-1.3.1 crypto-3.6.3 debugger-4.1.2 dialyzer-2.9 diameter-1.11.2 edoc-0.7.18 eldap-1.2.1 erl_docgen-0.4.2 erl_interface-3.8.2 erts-7.3.1 et-1.5.1 eunit-2.2.13 gs-1.6 hipe-3.15 ic-4.4 jinterface-1.6.1 kernel-4.2 megaco-3.18 mnesia-4.13.4 observer-2.1.2 odbc-2.11.1 orber-3.8.1 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1.1 reltool-0.7 runtime_tools-1.9.3 sasl-2.7 snmp-5.2.2 ssh-4.2.2 stdlib-2.8 syntax_tools-1.7 test_server-3.10 tools-2.8.3 typer-0.9.10 webtool-0.9.1 wx-1.6.1 xmerl-1.3.10 : + OTP-18.3.1 : erts-7.3.1 inets-6.2.1 mnesia-4.13.4 # asn1-4.0.2 common_test-1.12 compiler-6.0.3 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2.1 cosProperty-1.2 cosTime-1.2.1 cosTransactions-1.3.1 crypto-3.6.3 debugger-4.1.2 dialyzer-2.9 diameter-1.11.2 edoc-0.7.18 eldap-1.2.1 erl_docgen-0.4.2 erl_interface-3.8.2 et-1.5.1 eunit-2.2.13 gs-1.6 hipe-3.15 ic-4.4 jinterface-1.6.1 kernel-4.2 megaco-3.18 observer-2.1.2 odbc-2.11.1 orber-3.8.1 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1.1 reltool-0.7 runtime_tools-1.9.3 sasl-2.7 snmp-5.2.2 ssh-4.2.2 ssl-7.3 stdlib-2.8 syntax_tools-1.7 test_server-3.10 tools-2.8.3 typer-0.9.10 webtool-0.9.1 wx-1.6.1 xmerl-1.3.10 : + OTP-18.3 : asn1-4.0.2 common_test-1.12 compiler-6.0.3 cosNotification-1.2.1 cosTime-1.2.1 cosTransactions-1.3.1 crypto-3.6.3 debugger-4.1.2 dialyzer-2.9 diameter-1.11.2 edoc-0.7.18 eldap-1.2.1 erl_docgen-0.4.2 erl_interface-3.8.2 erts-7.3 eunit-2.2.13 hipe-3.15 inets-6.2 kernel-4.2 mnesia-4.13.3 observer-2.1.2 orber-3.8.1 public_key-1.1.1 runtime_tools-1.9.3 sasl-2.7 snmp-5.2.2 ssh-4.2.2 ssl-7.3 stdlib-2.8 test_server-3.10 tools-2.8.3 webtool-0.9.1 wx-1.6.1 xmerl-1.3.10 # cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosProperty-1.2 et-1.5.1 gs-1.6 ic-4.4 jinterface-1.6.1 megaco-3.18 odbc-2.11.1 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 reltool-0.7 syntax_tools-1.7 typer-0.9.10 : diff --git a/community/erlang/APKBUILD b/community/erlang/APKBUILD index 34424f4..57fc384 100644 --- a/community/erlang/APKBUILD +++ b/community/erlang/APKBUILD @@ -2,7 +2,7 @@ # Maintainer: Marlus Saraiva pkgname=erlang -pkgver=18.3.2 +pkgver=18.3.4 _srcver=18.3 pkgrel=0 pkgdesc="General-purpose programming language and runtime environment" @@ -75,7 +75,8 @@ source="http://www.erlang.org/download/otp_src_$_srcver.tar.gz 0007-Split-off-webtool-dependency-from-tools.patch 0010-fix-nteventlog-remove.patch 0060-set-disksup_posix_only-to-true.patch - 0070-otp-update-version-18.3.2.patch" + 0070-otp-update-version-18.3.2.patch + 0080-otp-update-version-18.3.4.patch" _builddir="$srcdir"/otp_src_$_srcver @@ -219,7 +220,8 @@ a8e9e58c2444ac3994a6b418fd387369 0006-Do-not-install-erlang-sources.patch b438c37818b5c82443682c3693dd7e53 0007-Split-off-webtool-dependency-from-tools.patch 0dd300003ff68fc46dc3c839c2541d53 0010-fix-nteventlog-remove.patch d17fbaafa9f7820ade09b239c00aede6 0060-set-disksup_posix_only-to-true.patch -b0d5cf3bac335964a1c8ffd98d9f105d 0070-otp-update-version-18.3.2.patch" +b0d5cf3bac335964a1c8ffd98d9f105d 0070-otp-update-version-18.3.2.patch +96d85db0efbac64be3ca3f9158766e59 0080-otp-update-version-18.3.4.patch" sha256sums="fdab8129a1cb935db09f1832e3a7d511a4aeb2b9bb3602ca6a7ccb9730d5c9c3 otp_src_18.3.tar.gz 536e78192f915733cbbb264883af6d9b11c9e70c2c4d3d825b58c4dbec36db86 0001-Do-not-format-man-pages-and-do-not-install-miscellan.patch b2e5844215d7f5f5026a77342dd698d16103cc726d23f8265bcc8399d1a82bb9 0002-Remove-rpath.patch @@ -230,7 +232,8 @@ fcf2c37b3eaddd3e1bea2880c1b80f010623743ab2f43e144e0ecc7be874d4ff 0006-Do-not-in 9704a53bc4bd6f5624f9ce3f201128204011f4579f19b547df74d92ae22777cf 0007-Split-off-webtool-dependency-from-tools.patch 019c62ea3fee60068caa8c3152d7f96e76591fc5dc096abfcea48ec1593eb758 0010-fix-nteventlog-remove.patch 3ffda0b3acbde755b496c1a974c20e1ca580432c403944c1c16836f48e248429 0060-set-disksup_posix_only-to-true.patch -ec32540b798d2b3a7b8271cf95c63423dda864b24c8765368835295bf4575c61 0070-otp-update-version-18.3.2.patch" +ec32540b798d2b3a7b8271cf95c63423dda864b24c8765368835295bf4575c61 0070-otp-update-version-18.3.2.patch +9f9091b9eaa84e0b07b0f849e6311720b4cf2fed2ea1314e1470e5e65f8959a1 0080-otp-update-version-18.3.4.patch" sha512sums="f4a69bb14743d9f913d7060cfb6426f7c54693d07ed439506ede5160a0ba5a79a81cf08a56aaa02c68b3377cd22fed66a0fbeb216378330d7ad5c6348ed82014 otp_src_18.3.tar.gz 172f9b0f61748bf2f04737df0451bcc9c0812db0f365f0ef7c7c244fceb991987f79a5274eea578a89cc7d077f84645d1395d9dbcbf14010268b896a080c2ccf 0001-Do-not-format-man-pages-and-do-not-install-miscellan.patch 97c40c185b71b23ffcb924639af390b9a0be897070e396a9413e193e6d43048dfe3b86bcd0c5598b81a66ce1349de9e09f5228a452b51b6612cd947bbafb6377 0002-Remove-rpath.patch @@ -241,4 +244,5 @@ ef9045ec689e2a6517dba7626c1225a9a265f14675d704effd324529c3d5128260ba64cebfd41185 d65fcfc3a9441941c6292c33d354964a82da11cc7a411dd0440719e490075ed588c1e70690e80650561749010d737394567f12ff73bd460f0d00c792c77cfae3 0007-Split-off-webtool-dependency-from-tools.patch b7387f92f8c27a0565c7885bba4b357183c62d422616e073bc5ffad338a0e22cb5165dcb3b95bf0b920ba00831599f2216027883f4be255aa6f6150b68b7a37c 0010-fix-nteventlog-remove.patch f3c50f8610e08173c365a575737079b0259db6fc0dfa5b1be63c281b52358bbce9e2595132a8f6a06772785d7d38d108f8da8515e2f7706cd03b6585aab4d071 0060-set-disksup_posix_only-to-true.patch -e472bdb4b322d66b9c0ad9627abc469b8c648145ffad1dd7f645b38b2fad43492f475d2fd4d0bab159be6110db5043bb6d792d72e8276b3c3869be46129c6616 0070-otp-update-version-18.3.2.patch" +e472bdb4b322d66b9c0ad9627abc469b8c648145ffad1dd7f645b38b2fad43492f475d2fd4d0bab159be6110db5043bb6d792d72e8276b3c3869be46129c6616 0070-otp-update-version-18.3.2.patch +84ee0512b5abad52f102c9696dd9ceec344f50a395078684ba01adba4efb2b287fc0c1f5e982898b0aa29c77a789b06eace156e20e8774ce07e8297f85479cd3 0080-otp-update-version-18.3.4.patch" -- 2.9.0 --- Unsubscribe: alpine-aports+unsubscribe@lists.alpinelinux.org Help: alpine-aports+help@lists.alpinelinux.org ---