diff options
47 files changed, 830 insertions, 754 deletions
diff --git a/OTP_VERSION b/OTP_VERSION index 528f7b565a..93d4fc0a52 100644 --- a/OTP_VERSION +++ b/OTP_VERSION @@ -1 +1 @@ -18.2 +18.2.4 diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml index 5cb9bdb690..a726cc7b97 100644 --- a/erts/doc/src/notes.xml +++ b/erts/doc/src/notes.xml @@ -32,6 +32,27 @@ <p>This document describes the changes made to the ERTS application.</p> +<section><title>Erts 7.2.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Revert "Fix erroneous splitting of emulator path"</p> + <p> + Own Id: OTP-13202</p> + </item> + <item> + <p> + Fix HiPE enabled emulator for FreeBSD.</p> + <p> + Own Id: OTP-13204 Aux Id: pr926 </p> + </item> + </list> + </section> + +</section> + <section><title>Erts 7.2</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/erts/emulator/hipe/hipe_x86_signal.c b/erts/emulator/hipe/hipe_x86_signal.c index 69d4ea10c2..b7dae88417 100644 --- a/erts/emulator/hipe/hipe_x86_signal.c +++ b/erts/emulator/hipe/hipe_x86_signal.c @@ -234,7 +234,29 @@ static void do_init(void) #define INIT() do { if (!init_done()) do_init(); } while (0) #endif /* __sun__ */ -#if !(defined(__GLIBC__) || defined(__DARWIN__) || defined(__NetBSD__) || defined(__sun__)) +#if defined(__FreeBSD__) +/* + * This is a copy of Darwin code for FreeBSD. + * CAVEAT: detailed semantics are not verified yet. + */ +#include <dlfcn.h> +static int (*__next_sigaction)(int, const struct sigaction*, struct sigaction*); +#define init_done() (__next_sigaction != 0) +extern int _sigaction(int, const struct sigaction*, struct sigaction*); +#define __SIGACTION _sigaction +static void do_init(void) +{ + __next_sigaction = dlsym(RTLD_NEXT, "sigaction"); + if (__next_sigaction != 0) + return; + perror("dlsym_freebsd"); + abort(); +} +#define _NSIG NSIG +#define INIT() do { if (!init_done()) do_init(); } while (0) +#endif /* __FreeBSD__ */ + +#if !(defined(__GLIBC__) || defined(__DARWIN__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__sun__)) /* * Unknown libc -- assume musl. Note: musl deliberately does not provide a musl-specific * feature test macro, so we cannot check for it. @@ -259,7 +281,7 @@ static void do_init(void) #define _NSIG NSIG #endif #define INIT() do { if (!init_done()) do_init(); } while (0) -#endif /* !(__GLIBC__ || __DARWIN__ || __NetBSD__ || __sun__) */ +#endif /* !(__GLIBC__ || __DARWIN__ || __NetBSD__ || __FreeBSD__ || __sun__) */ #if !defined(__NetBSD__) /* @@ -299,7 +321,7 @@ int __SIGACTION(int signum, const struct sigaction *act, struct sigaction *oldac /* * This catches the application's own sigaction() calls. */ -#if !defined(__DARWIN__) && !defined(__NetBSD__) +#if !defined(__DARWIN__) && !defined(__NetBSD__) && !defined(__FreeBSD__) int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) { return my_sigaction(signum, act, oldact); diff --git a/erts/etc/common/ct_run.c b/erts/etc/common/ct_run.c index 11cec26264..548514ee6c 100644 --- a/erts/etc/common/ct_run.c +++ b/erts/etc/common/ct_run.c @@ -83,6 +83,7 @@ static int eargc; /* Number of arguments in eargv. */ static void error(char* format, ...); static char* emalloc(size_t size); static char* strsave(char* string); +static void push_words(char* src); static int run_erlang(char* name, char** argv); static char* get_default_emulator(char* progname); #ifdef __WIN32__ @@ -151,8 +152,6 @@ int main(int argc, char** argv) argv0 = argv; emulator = get_default_emulator(argv[0]); - if (strlen(emulator) >= MAXPATHLEN) - error("Emulator path length is too large"); /* * Allocate the argv vector to be used for arguments to Erlang. @@ -164,7 +163,7 @@ int main(int argc, char** argv) eargv_base = (char **) emalloc(eargv_size*sizeof(char*)); eargv = eargv_base; eargc = 0; - PUSH(strsave(emulator)); + push_words(emulator); eargc_base = eargc; eargv = eargv + eargv_size/2; eargc = 0; @@ -295,6 +294,26 @@ int main(int argc, char** argv) return run_erlang(eargv[0], eargv); } +static void +push_words(char* src) +{ + char sbuf[MAXPATHLEN]; + char* dst; + + dst = sbuf; + while ((*dst++ = *src++) != '\0') { + if (isspace((int)*src)) { + *dst = '\0'; + PUSH(strsave(sbuf)); + dst = sbuf; + do { + src++; + } while (isspace((int)*src)); + } + } + if (sbuf[0]) + PUSH(strsave(sbuf)); +} #ifdef __WIN32__ wchar_t *make_commandline(char **argv) { diff --git a/erts/etc/common/dialyzer.c b/erts/etc/common/dialyzer.c index cac1464bf6..c45626606c 100644 --- a/erts/etc/common/dialyzer.c +++ b/erts/etc/common/dialyzer.c @@ -65,6 +65,7 @@ static int eargc; /* Number of arguments in eargv. */ static void error(char* format, ...); static char* emalloc(size_t size); static char* strsave(char* string); +static void push_words(char* src); static int run_erlang(char* name, char** argv); static char* get_default_emulator(char* progname); #ifdef __WIN32__ @@ -188,7 +189,7 @@ int main(int argc, char** argv) eargv_base = (char **) emalloc(eargv_size*sizeof(char*)); eargv = eargv_base; eargc = 0; - PUSH(strsave(emulator)); + push_words(emulator); eargc_base = eargc; eargv = eargv + eargv_size/2; eargc = 0; @@ -268,6 +269,27 @@ int main(int argc, char** argv) return run_erlang(eargv[0], eargv); } +static void +push_words(char* src) +{ + char sbuf[MAXPATHLEN]; + char* dst; + + dst = sbuf; + while ((*dst++ = *src++) != '\0') { + if (isspace((int)*src)) { + *dst = '\0'; + PUSH(strsave(sbuf)); + dst = sbuf; + do { + src++; + } while (isspace((int)*src)); + } + } + if (sbuf[0]) + PUSH(strsave(sbuf)); +} + #ifdef __WIN32__ wchar_t *make_commandline(char **argv) { diff --git a/erts/etc/common/erlc.c b/erts/etc/common/erlc.c index 049afc526a..f9d909e01c 100644 --- a/erts/etc/common/erlc.c +++ b/erts/etc/common/erlc.c @@ -200,7 +200,7 @@ int main(int argc, char** argv) eargv_base = (char **) emalloc(eargv_size*sizeof(char*)); eargv = eargv_base; eargc = 0; - PUSH(strsave(emulator)); + push_words(emulator); eargc_base = eargc; eargv = eargv + eargv_size/2; eargc = 0; @@ -330,6 +330,26 @@ process_opt(int* pArgc, char*** pArgv, int offset) return argv[1]; } +static void +push_words(char* src) +{ + char sbuf[MAXPATHLEN]; + char* dst; + + dst = sbuf; + while ((*dst++ = *src++) != '\0') { + if (isspace((int)*src)) { + *dst = '\0'; + PUSH(strsave(sbuf)); + dst = sbuf; + do { + src++; + } while (isspace((int)*src)); + } + } + if (sbuf[0]) + PUSH(strsave(sbuf)); +} #ifdef __WIN32__ wchar_t *make_commandline(char **argv) { diff --git a/erts/etc/common/escript.c b/erts/etc/common/escript.c index a5c6d0d40b..7fd02ed436 100644 --- a/erts/etc/common/escript.c +++ b/erts/etc/common/escript.c @@ -74,6 +74,7 @@ static void error(char* format, ...); static char* emalloc(size_t size); static void efree(void *p); static char* strsave(char* string); +static void push_words(char* src); static int run_erlang(char* name, char** argv); static char* get_default_emulator(char* progname); #ifdef __WIN32__ @@ -431,7 +432,7 @@ main(int argc, char** argv) emulator = get_default_emulator(argv[0]); } - if (strlen(emulator) >= MAXPATHLEN) + if (strlen(emulator) >= PMAX) error("Value of environment variable ESCRIPT_EMULATOR is too large"); /* @@ -444,7 +445,7 @@ main(int argc, char** argv) eargv_base = (char **) emalloc(eargv_size*sizeof(char*)); eargv = eargv_base; eargc = 0; - PUSH(strsave(emulator)); + push_words(emulator); eargc_base = eargc; eargv = eargv + eargv_size/2; eargc = 0; @@ -553,6 +554,26 @@ main(int argc, char** argv) return run_erlang(eargv[0], eargv); } +static void +push_words(char* src) +{ + char sbuf[PMAX]; + char* dst; + + dst = sbuf; + while ((*dst++ = *src++) != '\0') { + if (isspace((int)*src)) { + *dst = '\0'; + PUSH(strsave(sbuf)); + dst = sbuf; + do { + src++; + } while (isspace((int)*src)); + } + } + if (sbuf[0]) + PUSH(strsave(sbuf)); +} #ifdef __WIN32__ wchar_t *make_commandline(char **argv) { diff --git a/erts/etc/common/typer.c b/erts/etc/common/typer.c index 7ff8aa76e2..0aa0996808 100644 --- a/erts/etc/common/typer.c +++ b/erts/etc/common/typer.c @@ -65,6 +65,7 @@ static int eargc; /* Number of arguments in eargv. */ static void error(char* format, ...); static char* emalloc(size_t size); static char* strsave(char* string); +static void push_words(char* src); static int run_erlang(char* name, char** argv); static char* get_default_emulator(char* progname); #ifdef __WIN32__ @@ -128,9 +129,6 @@ main(int argc, char** argv) emulator = get_default_emulator(argv[0]); - if (strlen(emulator) >= MAXPATHLEN) - error("Emulator path length is too large"); - /* * Allocate the argv vector to be used for arguments to Erlang. * Arrange for starting to pushing information in the middle of @@ -141,7 +139,7 @@ main(int argc, char** argv) eargv_base = (char **) emalloc(eargv_size*sizeof(char*)); eargv = eargv_base; eargc = 0; - PUSH(strsave(emulator)); + push_words(emulator); eargc_base = eargc; eargv = eargv + eargv_size/2; eargc = 0; @@ -194,6 +192,26 @@ main(int argc, char** argv) return run_erlang(eargv[0], eargv); } +static void +push_words(char* src) +{ + char sbuf[MAXPATHLEN]; + char* dst; + + dst = sbuf; + while ((*dst++ = *src++) != '\0') { + if (isspace((int)*src)) { + *dst = '\0'; + PUSH(strsave(sbuf)); + dst = sbuf; + do { + src++; + } while (isspace((int)*src)); + } + } + if (sbuf[0]) + PUSH(strsave(sbuf)); +} #ifdef __WIN32__ wchar_t *make_commandline(char **argv) { diff --git a/erts/vsn.mk b/erts/vsn.mk index be6cf2e376..94b5d0b169 100644 --- a/erts/vsn.mk +++ b/erts/vsn.mk @@ -18,7 +18,7 @@ # %CopyrightEnd% # -VSN = 7.2 +VSN = 7.2.1 # Port number 4365 in 4.2 # Port number 4366 in 4.3 diff --git a/lib/common_test/doc/src/notes.xml b/lib/common_test/doc/src/notes.xml index 9906db2c90..57a8c6c9e2 100644 --- a/lib/common_test/doc/src/notes.xml +++ b/lib/common_test/doc/src/notes.xml @@ -33,6 +33,26 @@ <file>notes.xml</file> </header> +<section><title>Common_Test 1.11.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + If a ssh package contained more than one netconf end tag, + then the second end tag was never detected in + ct_netconfc:handle_data. Instead it was included in the + XML data given to the xmerl parser, which then failed. + The problem was introduced by OTP-13007, and has now been + corrected.</p> + <p> + Own Id: OTP-13323</p> + </item> + </list> + </section> + +</section> + <section><title>Common_Test 1.11.1</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/common_test/src/ct_netconfc.erl b/lib/common_test/src/ct_netconfc.erl index 6e3d1ab1d8..3da1115c76 100644 --- a/lib/common_test/src/ct_netconfc.erl +++ b/lib/common_test/src/ct_netconfc.erl @@ -264,6 +264,7 @@ session_id, msg_id = 1, hello_status, + no_end_tag_buff = <<>>, buff = <<>>, pending = [], % [#pending] event_receiver}).% pid @@ -1170,7 +1171,7 @@ handle_msg({Ref,timeout},#state{pending=Pending} = State) -> end, %% Halfhearted try to get in correct state, this matches %% the implementation before this patch - {R,State#state{pending=Pending1, buff= <<>>}}. + {R,State#state{pending=Pending1, no_end_tag_buff= <<>>, buff= <<>>}}. %% @private %% Called by ct_util_server to close registered connections before terminate. @@ -1205,7 +1206,7 @@ call(Client, Msg, Timeout, WaitStop) -> {error,no_such_client}; {error,{process_down,Pid,normal}} when WaitStop -> %% This will happen when server closes connection - %% before clien received rpc-reply on + %% before client received rpc-reply on %% close-session. ok; {error,{process_down,Pid,normal}} -> @@ -1372,24 +1373,37 @@ to_xml_doc(Simple) -> %%%----------------------------------------------------------------- %%% Parse and handle received XML data -handle_data(NewData,#state{connection=Connection,buff=Buff0} = State0) -> +%%% Two buffers are used: +%%% * 'no_end_tag_buff' contains data that is checked and does not +%%% contain any (part of an) end tag. +%%% * 'buff' contains all other saved data - it may or may not +%%% include (a part of) an end tag. +%%% The reason for this is to avoid running binary:split/3 multiple +%%% times on the same data when it does not contain an end tag. This +%%% can be a considerable optimation in the case when a lot of data is +%%% received (e.g. when fetching all data from a node) and the data is +%%% sent in multiple ssh packages. +handle_data(NewData,#state{connection=Connection} = State0) -> log(Connection,recv,NewData), - {Start,AddSz} = - case byte_size(Buff0) of - BSz when BSz<5 -> {0,BSz}; - BSz -> {BSz-5,5} - end, - Length = byte_size(NewData) + AddSz, + NoEndTag0 = State0#state.no_end_tag_buff, + Buff0 = State0#state.buff, Data = <<Buff0/binary, NewData/binary>>, - case binary:split(Data,?END_TAG,[{scope,{Start,Length}}]) of + case binary:split(Data,?END_TAG,[]) of [_NoEndTagFound] -> - {noreply, State0#state{buff=Data}}; + NoEndTagSize = case byte_size(Data) of + Sz when Sz<5 -> 0; + Sz -> Sz-5 + end, + <<NoEndTag1:NoEndTagSize/binary,Buff/binary>> = Data, + NoEndTag = <<NoEndTag0/binary,NoEndTag1/binary>>, + {noreply, State0#state{no_end_tag_buff=NoEndTag, buff=Buff}}; [FirstMsg0,Buff1] -> - FirstMsg = remove_initial_nl(FirstMsg0), + FirstMsg = remove_initial_nl(<<NoEndTag0/binary,FirstMsg0/binary>>), SaxArgs = [{event_fun,fun sax_event/3}, {event_state,[]}], case xmerl_sax_parser:stream(FirstMsg, SaxArgs) of {ok, Simple, _Thrash} -> - case decode(Simple, State0#state{buff=Buff1}) of + case decode(Simple, State0#state{no_end_tag_buff= <<>>, + buff=Buff1}) of {noreply, #state{buff=Buff} = State} when Buff =/= <<>> -> %% Recurse if we have more data in buffer handle_data(<<>>, State); @@ -1401,10 +1415,12 @@ handle_data(NewData,#state{connection=Connection,buff=Buff0} = State0) -> [{parse_error,Reason}, {buffer, Buff0}, {new_data,NewData}]), - handle_error(Reason, State0#state{buff= <<>>}) + handle_error(Reason, State0#state{no_end_tag_buff= <<>>, + buff= <<>>}) end end. + %% xml does not accept a leading nl and some netconf server add a nl after %% each ?END_TAG, ignore them remove_initial_nl(<<"\n", Data/binary>>) -> diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl index ea49e36608..49b02d2bba 100644 --- a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl +++ b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl @@ -99,7 +99,10 @@ all() -> connection_crash, get_event_streams, create_subscription, - receive_event + receive_one_event, + receive_multiple_events, + receive_event_and_rpc, + receive_event_and_rpc_in_chunks ] end. @@ -354,7 +357,7 @@ get(Config) -> get_a_lot(Config) -> DataDir = ?config(data_dir,Config), {ok,Client} = open_success(DataDir), - Descr = lists:append(lists:duplicate(100,"Description of myserver! ")), + Descr = lists:append(lists:duplicate(1000,"Description of myserver! ")), Server = {server,[{xmlns,"myns"}],[{name,[],["myserver"]}, {description,[],[Descr]}]}, Data = lists:duplicate(100,Server), @@ -964,16 +967,16 @@ create_subscription(Config) -> ok. -receive_event(Config) -> +receive_one_event(Config) -> DataDir = ?config(data_dir,Config), {ok,Client} = open_success(DataDir), ?NS:expect_reply({'create-subscription',[stream]},ok), ?ok = ct_netconfc:create_subscription(Client), - ?NS:hupp(send_event), + ?NS:hupp({send_events,1}), receive - %% Matching ?NS:make_msg(event) + %% Matching ?NS:make_msg({event,_}) {notification,?NETCONF_NOTIF_NAMESPACE_ATTR, [{eventTime,[],[_Time]}, {event,[{xmlns,"http://my.namespaces.com/event"}], @@ -991,6 +994,187 @@ receive_event(Config) -> ok. +receive_multiple_events(Config) -> + DataDir = ?config(data_dir,Config), + {ok,Client} = open_success(DataDir), + ?NS:expect_reply({'create-subscription',[stream]},ok), + ?ok = ct_netconfc:create_subscription(Client), + + ?NS:hupp({send_events,3}), + + receive + %% Matching ?NS:make_msg({event,_}) + {notification,_,_} -> + ok; + Other1 -> + ct:fail({got_unexpected_while_waiting_for_event, Other1}) + after 3000 -> + ct:fail(timeout_waiting_for_event) + end, + receive + %% Matching ?NS:make_msg({event,_}) + {notification,_,_} -> + ok; + Other2 -> + ct:fail({got_unexpected_while_waiting_for_event, Other2}) + after 3000 -> + ct:fail(timeout_waiting_for_event) + end, + receive + %% Matching ?NS:make_msg({event,_}) + {notification,_,_} -> + ok; + Other3 -> + ct:fail({got_unexpected_while_waiting_for_event, Other3}) + after 3000 -> + ct:fail(timeout_waiting_for_event) + end, + + ?NS:expect_do_reply('close-session',close,ok), + ?ok = ct_netconfc:close_session(Client), + + ok. + +receive_event_and_rpc(Config) -> + DataDir = ?config(data_dir,Config), + {ok,Client} = open_success(DataDir), + + ?NS:expect_reply({'create-subscription',[stream]},ok), + ?ok = ct_netconfc:create_subscription(Client), + + %% Construct the data to return from netconf server - one + %% rpc-reply and one notification - to be sent in the same ssh + %% package. + Data = [{servers,[{xmlns,"myns"}],[{server,[],[{name,[],["myserver"]}]}]}], + Rpc = {'rpc-reply',?NETCONF_NAMESPACE_ATTR ++ [{'message-id',"2"}], + [{data,Data}]}, + RpcXml = list_to_binary(xmerl:export_simple_element(Rpc,xmerl_xml)), + + Notification = + {notification,?NETCONF_NOTIF_NAMESPACE_ATTR, + [{eventTime,["2012-06-14T14:50:54+02:00"]}, + {event,[{xmlns,"http://my.namespaces.com/event"}], + [{severity,["major"]}, + {description,["Something terrible happened"]}]}]}, + NotifXml = + list_to_binary(xmerl:export_simple_element(Notification,xmerl_xml)), + + ?NS:expect_reply('get',[RpcXml,NotifXml]), + {ok,Data} = ct_netconfc:get(Client,{server,[{xmlns,"myns"}],[]}), + + receive + {notification,_,_} -> + ok; + Other1 -> + ct:fail({got_unexpected_while_waiting_for_event, Other1}) + after 3000 -> + ct:fail(timeout_waiting_for_event) + end, + + + %% Then do the same again, but now send notification first then + %% the rpc-reply. + Rpc2 = {'rpc-reply',?NETCONF_NAMESPACE_ATTR ++ [{'message-id',"3"}], + [{data,Data}]}, + RpcXml2 = list_to_binary(xmerl:export_simple_element(Rpc2,xmerl_xml)), + ?NS:expect_reply('get',[NotifXml,RpcXml2]), + {ok,Data} = ct_netconfc:get(Client,{server,[{xmlns,"myns"}],[]}), + + receive + {notification,_,_} -> + ok; + Other2 -> + ct:fail({got_unexpected_while_waiting_for_event, Other2}) + after 3000 -> + ct:fail(timeout_waiting_for_event) + end, + + ?NS:expect_do_reply('close-session',close,ok), + ?ok = ct_netconfc:close_session(Client), + + ok. + + +receive_event_and_rpc_in_chunks(Config) -> + DataDir = ?config(data_dir,Config), + {ok,Client} = open_success(DataDir), + + ?NS:expect_reply({'create-subscription',[stream]},ok), + ?ok = ct_netconfc:create_subscription(Client), + + %% Construct the data to return from netconf server + Data = [{servers,[{xmlns,"myns"}], + [{server,[],[{name,[],["server0"]}]}, + {server,[],[{name,[],["server1"]}]}, + {server,[],[{name,[],["server2"]}]}, + {server,[],[{name,[],["server3"]}]}, + {server,[],[{name,[],["server4"]}]}, + {server,[],[{name,[],["server5"]}]}, + {server,[],[{name,[],["server6"]}]}, + {server,[],[{name,[],["server7"]}]}, + {server,[],[{name,[],["server8"]}]}, + {server,[],[{name,[],["server9"]}]}] + }], + Rpc = {'rpc-reply',?NETCONF_NAMESPACE_ATTR ++ [{'message-id',"2"}], + [{data,Data}]}, + RpcXml = list_to_binary(xmerl:export_simple_element(Rpc,xmerl_xml)), + + Notification = + {notification,?NETCONF_NOTIF_NAMESPACE_ATTR, + [{eventTime,["2012-06-14T14:50:54+02:00"]}, + {event,[{xmlns,"http://my.namespaces.com/event"}], + [{severity,["major"]}, + {description,["Something terrible happened"]}]}]}, + NotifXml = + list_to_binary(xmerl:export_simple_element(Notification,xmerl_xml)), + + + %% First part contains a notif, but only parts of the end tag + Part1 = + <<"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", + NotifXml/binary,"\n]]">>, + + %% Second part contains rest of end tag, full rpc-reply and full + %% notif except end tag + Part2 = + <<">]]>\n",RpcXml/binary,"\n",?END_TAG/binary,NotifXml/binary>>, + + %% Third part contains last end tag + Part3 = <<"\n",?END_TAG/binary,"\n">>, + + %% Spawn a process which will wait a bit for the client to send + %% the request (below), then order the server to the chunks of the + %% rpc-reply one by one. + spawn(fun() -> ct:sleep(500),?NS:hupp(send,Part1), + ct:sleep(100),?NS:hupp(send,Part2), + ct:sleep(100),?NS:hupp(send,Part3) + end), + + %% Order server to expect a get - then the process above will make + %% sure the rpc-reply is sent. + ?NS:expect('get'), + {ok,Data} = ct_netconfc:get(Client,{server,[{xmlns,"myns"}],[]}), + + receive + {notification,_,_} -> + ok; + Other1 -> + ct:fail({got_unexpected_while_waiting_for_event, Other1}) + after 3000 -> + ct:fail(timeout_waiting_for_event) + end, + receive + {notification,_,_} -> + ok; + Other2 -> + ct:fail({got_unexpected_while_waiting_for_event, Other2}) + after 3000 -> + ct:fail(timeout_waiting_for_event) + end, + ?NS:expect_do_reply('close-session',close,ok), + ?ok = ct_netconfc:close_session(Client), + ok. + %%%----------------------------------------------------------------- break(_Config) -> diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl b/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl index 07893faabc..67827a053f 100644 --- a/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl +++ b/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl @@ -144,8 +144,8 @@ expect_do_reply(SessionId,Expect,Do,Reply) -> %% Hupp the server - i.e. tell it to do something - %% e.g. hupp(send_event) will cause send_event(State) to be called on %% the session channel process. -hupp(send_event) -> - hupp(send,[make_msg(event)]); +hupp({send_events,N}) -> + hupp(send,[make_msg({event,N})]); hupp(kill) -> hupp(1,fun hupp_kill/1,[]). @@ -446,9 +446,12 @@ reply(ConnRef,Reply) -> from_simple(Simple) -> unicode_c2b(xmerl:export_simple_element(Simple,xmerl_xml)). -xml(Content) -> - <<"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", - Content/binary,"\n",?END_TAG/binary>>. +xml(Content) when is_binary(Content) -> + xml([Content]); +xml(Content) when is_list(Content) -> + Msgs = [<<Msg/binary,"\n",?END_TAG/binary>> || Msg <- Content], + MsgsBin = list_to_binary(Msgs), + <<"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", MsgsBin/binary>>. rpc_reply(Content) when is_binary(Content) -> MsgId = case erase(msg_id) of @@ -571,15 +574,17 @@ make_msg({ok,Data}) -> make_msg({data,Data}) -> xml(rpc_reply(from_simple({data,Data}))); -make_msg(event) -> - xml(<<"<notification xmlns=\"",?NETCONF_NOTIF_NAMESPACE,"\">" +make_msg({event,N}) -> + Notification = <<"<notification xmlns=\"",?NETCONF_NOTIF_NAMESPACE,"\">" "<eventTime>2012-06-14T14:50:54+02:00</eventTime>" "<event xmlns=\"http://my.namespaces.com/event\">" "<severity>major</severity>" "<description>Something terrible happened</description>" "</event>" - "</notification>">>); -make_msg(Xml) when is_binary(Xml) -> + "</notification>">>, + xml(lists:duplicate(N,Notification)); +make_msg(Xml) when is_binary(Xml) orelse + (is_list(Xml) andalso is_binary(hd(Xml))) -> xml(Xml); make_msg(Simple) when is_tuple(Simple) -> xml(from_simple(Simple)). diff --git a/lib/common_test/vsn.mk b/lib/common_test/vsn.mk index f33b705dcb..34ed657e01 100644 --- a/lib/common_test/vsn.mk +++ b/lib/common_test/vsn.mk @@ -1 +1 @@ -COMMON_TEST_VSN = 1.11.1 +COMMON_TEST_VSN = 1.11.2 diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml index c98ec1a9dc..44e1ea9abe 100644 --- a/lib/inets/doc/src/notes.xml +++ b/lib/inets/doc/src/notes.xml @@ -33,7 +33,23 @@ <file>notes.xml</file> </header> - <section><title>Inets 6.1</title> + <section><title>Inets 6.1.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + mod_alias now traverses all aliases picking the longest + match and not the first match.</p> + <p> + Own Id: OTP-13248</p> + </item> + </list> + </section> + +</section> + +<section><title>Inets 6.1</title> <section><title>Fixed Bugs and Malfunctions</title> <list> diff --git a/lib/inets/src/http_lib/http_uri.erl b/lib/inets/src/http_lib/http_uri.erl index 6fe8c1776d..9940136f5a 100644 --- a/lib/inets/src/http_lib/http_uri.erl +++ b/lib/inets/src/http_lib/http_uri.erl @@ -196,10 +196,10 @@ parse_host_port(_Scheme, DefaultPort, HostPort, _Opts) -> {Host, int_port(Port)}. split_uri(UriPart, SplitChar, NoMatchResult, SkipLeft, SkipRight) -> - case inets_regexp:first_match(UriPart, SplitChar) of - {match, Match, _} -> - {string:substr(UriPart, 1, Match - SkipLeft), - string:substr(UriPart, Match + SkipRight, length(UriPart))}; + case re:run(UriPart, SplitChar, [{capture, first}]) of + {match, [{Match, _}]} -> + {string:substr(UriPart, 1, Match + 1 - SkipLeft), + string:substr(UriPart, Match + 1 + SkipRight, length(UriPart))}; nomatch -> NoMatchResult end. diff --git a/lib/inets/src/http_server/httpd.erl b/lib/inets/src/http_server/httpd.erl index cf02c0e072..e6377b4882 100644 --- a/lib/inets/src/http_server/httpd.erl +++ b/lib/inets/src/http_server/httpd.erl @@ -43,7 +43,7 @@ %%%======================================================================== parse_query(String) -> - {ok, SplitString} = inets_regexp:split(String,"[&;]"), + SplitString = re:split(String,"[&;]", [{return, list}]), foreach(SplitString). reload_config(Config = [Value| _], Mode) when is_tuple(Value) -> @@ -239,14 +239,14 @@ unblock(Addr, Port, Profile) when is_integer(Port) -> foreach([]) -> []; foreach([KeyValue|Rest]) -> - {ok, Plus2Space, _} = inets_regexp:gsub(KeyValue,"[\+]"," "), - case inets_regexp:split(Plus2Space,"=") of - {ok,[Key|Value]} -> - [{http_uri:decode(Key), - http_uri:decode(lists:flatten(Value))}|foreach(Rest)]; - {ok,_} -> - foreach(Rest) - end. + Plus2Space = re:replace(KeyValue,"[\+]"," ", [{return,list}, global]), + case re:split(Plus2Space,"=", [{return, list}]) of + [Key|Value] -> + [{http_uri:decode(Key), + http_uri:decode(lists:flatten(Value))}|foreach(Rest)]; + _ -> + foreach(Rest) + end. make_name(Addr, Port, Profile) -> diff --git a/lib/inets/src/http_server/httpd_conf.erl b/lib/inets/src/http_server/httpd_conf.erl index 62e8a95b19..a7783bc1e9 100644 --- a/lib/inets/src/http_server/httpd_conf.erl +++ b/lib/inets/src/http_server/httpd_conf.erl @@ -232,7 +232,7 @@ load("KeepAliveTimeout " ++ Timeout, []) -> end; load("Modules " ++ Modules, []) -> - {ok, ModuleList} = inets_regexp:split(Modules," "), + ModuleList = re:split(Modules," ", [{return, list}]), {ok, [], {modules,[list_to_atom(X) || X <- ModuleList]}}; load("ServerAdmin " ++ ServerAdmin, []) -> @@ -879,7 +879,7 @@ bootstrap([]) -> bootstrap([Line|Config]) -> case Line of "Modules " ++ Modules -> - {ok, ModuleList} = inets_regexp:split(Modules," "), + ModuleList = re:split(Modules," ", [{return, list}]), TheMods = [list_to_atom(X) || X <- ModuleList], case verify_modules(TheMods) of ok -> @@ -1004,7 +1004,7 @@ read_config_file(Stream, SoFar) -> %% Ignore commented lines for efficiency later .. read_config_file(Stream, SoFar); Line -> - {ok, NewLine, _}=inets_regexp:sub(clean(Line),"[\t\r\f ]"," "), + NewLine = re:replace(clean(Line),"[\t\r\f ]"," ", [{return,list}]), case NewLine of [] -> %% Also ignore empty lines .. @@ -1031,12 +1031,12 @@ parse_mime_types(Stream, MimeTypesList, "") -> parse_mime_types(Stream, MimeTypesList, [$#|_]) -> parse_mime_types(Stream, MimeTypesList); parse_mime_types(Stream, MimeTypesList, Line) -> - case inets_regexp:split(Line, " ") of - {ok, [NewMimeType|Suffixes]} -> + case re:split(Line, " ", [{return, list}]) of + [NewMimeType|Suffixes] -> parse_mime_types(Stream, lists:append(suffixes(NewMimeType,Suffixes), MimeTypesList)); - {ok, _} -> + _ -> {error, ?NICE(Line)} end. @@ -1207,9 +1207,8 @@ error_report(Where,M,F,Error) -> error_logger:error_report([{?MODULE, Where}, {apply, {M, F, []}}, Error]). white_space_clean(String) -> - {ok,CleanedString,_} = - inets_regexp:gsub(String, "^[ \t\n\r\f]*|[ \t\n\r\f]*\$",""), - CleanedString. + re:replace(String, "^[ \t\n\r\f]*|[ \t\n\r\f]*\$","", + [{return,list}, global]). %%%========================================================================= @@ -1246,22 +1245,23 @@ is_file(_Type,_Access,FileInfo,_File) -> {error,FileInfo}. make_integer(String) -> - case inets_regexp:match(string:strip(String),"[0-9]+") of - {match, _, _} -> + case re:run(string:strip(String),"[0-9]+", [{capture, none}]) of + match -> {ok, list_to_integer(string:strip(String))}; nomatch -> {error, nomatch} end. clean(String) -> - {ok,CleanedString,_} = - inets_regexp:gsub(String, "^[ \t\n\r\f]*|[ \t\n\r\f]*\$",""), - CleanedString. + re:replace(String, "^[ \t\n\r\f]*|[ \t\n\r\f]*\$","", + [{return,list}, global]). custom_clean(String,MoreBefore,MoreAfter) -> - {ok,CleanedString,_} = inets_regexp:gsub(String,"^[ \t\n\r\f"++MoreBefore++ - "]*|[ \t\n\r\f"++MoreAfter++"]*\$",""), - CleanedString. + re:replace(String, + "^[ \t\n\r\f"++MoreBefore++ + "]*|[ \t\n\r\f"++MoreAfter++"]*\$","", + [{return,list}, global]). + check_enum(_Enum,[]) -> {error, not_valid}; diff --git a/lib/inets/src/http_server/httpd_script_env.erl b/lib/inets/src/http_server/httpd_script_env.erl index 21b22f4420..232bf96bd4 100644 --- a/lib/inets/src/http_server/httpd_script_env.erl +++ b/lib/inets/src/http_server/httpd_script_env.erl @@ -104,7 +104,7 @@ create_http_header_elements(ScriptType, [{Name, [Value | _] = Values } | create_http_header_elements(ScriptType, [{Name, Value} | Headers], Acc) when is_list(Value) -> - {ok, NewName, _} = inets_regexp:gsub(Name,"-","_"), + NewName = re:replace(Name,"-","_", [{return,list}, global]), Element = http_env_element(ScriptType, NewName, Value), create_http_header_elements(ScriptType, Headers, [Element | Acc]). diff --git a/lib/inets/src/http_server/httpd_util.erl b/lib/inets/src/http_server/httpd_util.erl index ab43f0b378..6dd6db6a0c 100644 --- a/lib/inets/src/http_server/httpd_util.erl +++ b/lib/inets/src/http_server/httpd_util.erl @@ -420,11 +420,11 @@ flatlength([],L) -> %% split_path split_path(Path) -> - case inets_regexp:match(Path,"[\?].*\$") of + case re:run(Path,"[\?].*\$", [{capture, first}]) of %% A QUERY_STRING exists! - {match,Start,Length} -> - {http_uri:decode(string:substr(Path,1,Start-1)), - string:substr(Path,Start,Length)}; + {match,[{Start,Length}]} -> + {http_uri:decode(string:substr(Path,1,Start)), + string:substr(Path,Start+1,Length)}; %% A possible PATH_INFO exists! nomatch -> split_path(Path,[]) @@ -522,25 +522,8 @@ remove_ws(Rest) -> %% split -split(String,RegExp,Limit) -> - case inets_regexp:parse(RegExp) of - {error,Reason} -> - {error,Reason}; - {ok,_} -> - {ok,do_split(String,RegExp,Limit)} - end. - -do_split(String, _RegExp, 1) -> - [String]; - -do_split(String,RegExp,Limit) -> - case inets_regexp:first_match(String,RegExp) of - {match,Start,Length} -> - [string:substr(String,1,Start-1)| - do_split(lists:nthtail(Start+Length-1,String),RegExp,Limit-1)]; - nomatch -> - [String] - end. +split(String,RegExp,N) -> + {ok, re:split(String, RegExp, [{parts, N}, {return, list}])}. %% make_name/2, make_name/3 %% Prefix -> string() diff --git a/lib/inets/src/http_server/mod_actions.erl b/lib/inets/src/http_server/mod_actions.erl index d879328876..154fde294e 100644 --- a/lib/inets/src/http_server/mod_actions.erl +++ b/lib/inets/src/http_server/mod_actions.erl @@ -81,18 +81,18 @@ script(RequestURI, Method, [_ | Rest]) -> %% load load("Action "++ Action, []) -> - case inets_regexp:split(Action, " ") of - {ok,[MimeType, CGIScript]} -> - {ok,[],{action, {MimeType, CGIScript}}}; - {ok,_} -> - {error,?NICE(string:strip(Action)++" is an invalid Action")} + case re:split(Action, " ", [{return, list}]) of + [MimeType, CGIScript] -> + {ok,[],{action, {MimeType, CGIScript}}}; + _ -> + {error,?NICE(string:strip(Action)++" is an invalid Action")} end; load("Script " ++ Script,[]) -> - case inets_regexp:split(Script, " ") of - {ok,[Method, CGIScript]} -> - {ok,[],{script, {Method, CGIScript}}}; - {ok,_} -> - {error,?NICE(string:strip(Script)++" is an invalid Script")} + case re:split(Script, " ", [{return, list}]) of + [Method, CGIScript] -> + {ok,[],{script, {Method, CGIScript}}}; + _ -> + {error,?NICE(string:strip(Script)++" is an invalid Script")} end. store({action, {MimeType, CGIScript}} = Conf, _) when is_list(MimeType), diff --git a/lib/inets/src/http_server/mod_alias.erl b/lib/inets/src/http_server/mod_alias.erl index 8dd4871821..727f6e0ce3 100644 --- a/lib/inets/src/http_server/mod_alias.erl +++ b/lib/inets/src/http_server/mod_alias.erl @@ -113,32 +113,52 @@ real_name(ConfigDB, RequestURI, []) -> httpd_util:split_path(default_index(ConfigDB, RealName)), {ShortPath, Path, AfterPath}; -real_name(ConfigDB, RequestURI, [{MP,Replacement}|Rest]) +real_name(ConfigDB, RequestURI, [{MP,Replacement}| _] = Aliases) when element(1, MP) =:= re_pattern -> - case re:run(RequestURI, MP, [{capture,[]}]) of - match -> + case longest_match(Aliases, RequestURI) of + {match, {MP, Replacement}} -> NewURI = re:replace(RequestURI, MP, Replacement, [{return,list}]), {ShortPath,_} = httpd_util:split_path(NewURI), {Path,AfterPath} = httpd_util:split_path(default_index(ConfigDB, NewURI)), {ShortPath, Path, AfterPath}; nomatch -> - real_name(ConfigDB, RequestURI, Rest) + real_name(ConfigDB, RequestURI, []) end; -real_name(ConfigDB, RequestURI, [{FakeName,RealName}|Rest]) -> - case inets_regexp:match(RequestURI, "^" ++ FakeName) of - {match, _, _} -> - {ok, ActualName, _} = inets_regexp:sub(RequestURI, - "^" ++ FakeName, RealName), +real_name(ConfigDB, RequestURI, [{_,_}|_] = Aliases) -> + case longest_match(Aliases, RequestURI) of + {match, {FakeName, RealName}} -> + ActualName = re:replace(RequestURI, + "^" ++ FakeName, RealName, [{return,list}]), {ShortPath, _AfterPath} = httpd_util:split_path(ActualName), {Path, AfterPath} = - httpd_util:split_path(default_index(ConfigDB, ActualName)), + httpd_util:split_path(default_index(ConfigDB, ActualName)), {ShortPath, Path, AfterPath}; - nomatch -> - real_name(ConfigDB, RequestURI, Rest) + nomatch -> + real_name(ConfigDB, RequestURI, []) end. +longest_match(Aliases, RequestURI) -> + longest_match(Aliases, RequestURI, _LongestNo = 0, _LongestAlias = undefined). + +longest_match([{FakeName, RealName} | Rest], RequestURI, LongestNo, LongestAlias) -> + case re:run(RequestURI, "^" ++ FakeName, [{capture, first}]) of + {match, [{_, Length}]} -> + if + Length > LongestNo -> + longest_match(Rest, RequestURI, Length, {FakeName, RealName}); + true -> + longest_match(Rest, RequestURI, LongestNo, LongestAlias) + end; + nomatch -> + longest_match(Rest, RequestURI, LongestNo, LongestAlias) + end; +longest_match([], _RequestURI, 0, _LongestAlias) -> + nomatch; +longest_match([], _RequestURI, _LongestNo, LongestAlias) -> + {match, LongestAlias}. + %% real_script_name real_script_name(_ConfigDB, _RequestURI, []) -> @@ -146,7 +166,7 @@ real_script_name(_ConfigDB, _RequestURI, []) -> real_script_name(ConfigDB, RequestURI, [{MP,Replacement} | Rest]) when element(1, MP) =:= re_pattern -> - case re:run(RequestURI, MP, [{capture,[]}]) of + case re:run(RequestURI, MP, [{capture, none}]) of match -> ActualName = re:replace(RequestURI, MP, Replacement, [{return,list}]), @@ -156,10 +176,10 @@ real_script_name(ConfigDB, RequestURI, [{MP,Replacement} | Rest]) end; real_script_name(ConfigDB, RequestURI, [{FakeName,RealName} | Rest]) -> - case inets_regexp:match(RequestURI, "^" ++ FakeName) of - {match,_,_} -> - {ok, ActualName, _} = - inets_regexp:sub(RequestURI, "^" ++ FakeName, RealName), + case re:run(RequestURI, "^" ++ FakeName, [{capture, none}]) of + match -> + ActualName = + re:replace(RequestURI, "^" ++ FakeName, RealName, [{return,list}]), httpd_util:split_script_path(default_index(ConfigDB, ActualName)); nomatch -> real_script_name(ConfigDB, RequestURI, Rest) @@ -206,26 +226,26 @@ path(Data, ConfigDB, RequestURI) -> %% load load("DirectoryIndex " ++ DirectoryIndex, []) -> - {ok, DirectoryIndexes} = inets_regexp:split(DirectoryIndex," "), + DirectoryIndexes = re:split(DirectoryIndex," ", [{return, list}]), {ok,[], {directory_index, DirectoryIndexes}}; load("Alias " ++ Alias, []) -> - case inets_regexp:split(Alias," ") of - {ok, [FakeName, RealName]} -> + case re:split(Alias," ", [{return, list}]) of + [FakeName, RealName] -> {ok,[],{alias,{FakeName,RealName}}}; - {ok, _} -> + _ -> {error,?NICE(string:strip(Alias)++" is an invalid Alias")} end; load("ReWrite " ++ Rule, Acc) -> load_re_write(Rule, Acc, "ReWrite", re_write); load("ScriptAlias " ++ ScriptAlias, []) -> - case inets_regexp:split(ScriptAlias, " ") of - {ok, [FakeName, RealName]} -> + case re:split(ScriptAlias, " ", [{return, list}]) of + [FakeName, RealName] -> %% Make sure the path always has a trailing slash.. RealName1 = filename:join(filename:split(RealName)), {ok, [], {script_alias, {FakeName, RealName1++"/"}}}; - {ok, _} -> + _ -> {error, ?NICE(string:strip(ScriptAlias)++ - " is an invalid ScriptAlias")} + " is an invalid ScriptAlias")} end; load("ScriptReWrite " ++ Rule, Acc) -> load_re_write(Rule, Acc, "ScriptReWrite", script_re_write). diff --git a/lib/inets/src/http_server/mod_auth.erl b/lib/inets/src/http_server/mod_auth.erl index 6195e1c69f..b03629cabe 100644 --- a/lib/inets/src/http_server/mod_auth.erl +++ b/lib/inets/src/http_server/mod_auth.erl @@ -168,38 +168,38 @@ load("AuthDBType " ++ Type, end; load("require " ++ Require,[{directory, {Directory, DirData}}|Rest]) -> - case inets_regexp:split(Require," ") of - {ok,["user"|Users]} -> + case re:split(Require," ", [{return, list}]) of + ["user" | Users] -> {ok,[{directory, {Directory, - [{require_user,Users}|DirData]}} | Rest]}; - {ok,["group"|Groups]} -> + [{require_user,Users}|DirData]}} | Rest]}; + ["group"|Groups] -> {ok,[{directory, {Directory, - [{require_group,Groups}|DirData]}} | Rest]}; - {ok,_} -> + [{require_group,Groups}|DirData]}} | Rest]}; + _ -> {error,?NICE(string:strip(Require) ++" is an invalid require")} end; load("allow " ++ Allow,[{directory, {Directory, DirData}}|Rest]) -> - case inets_regexp:split(Allow," ") of - {ok,["from","all"]} -> + case re:split(Allow," ", [{return, list}]) of + ["from","all"] -> {ok,[{directory, {Directory, [{allow_from,all}|DirData]}} | Rest]}; - {ok,["from"|Hosts]} -> + ["from"|Hosts] -> {ok,[{directory, {Directory, [{allow_from,Hosts}|DirData]}} | Rest]}; - {ok,_} -> + _ -> {error,?NICE(string:strip(Allow) ++" is an invalid allow")} end; load("deny " ++ Deny,[{directory, {Directory, DirData}}|Rest]) -> - case inets_regexp:split(Deny," ") of - {ok, ["from", "all"]} -> + case re:split(Deny," ", [{return, list}]) of + ["from", "all"] -> {ok,[{{directory, Directory, [{deny_from, all}|DirData]}} | Rest]}; - {ok, ["from"|Hosts]} -> + ["from"|Hosts] -> {ok,[{{directory, Directory, [{deny_from, Hosts}|DirData]}} | Rest]}; - {ok, _} -> + _ -> {error,?NICE(string:strip(Deny) ++" is an invalid deny")} end; @@ -561,12 +561,12 @@ secret_path(_Path, [], to_be_found) -> secret_path(_Path, [], Directory) -> {yes, Directory}; secret_path(Path, [[NewDirectory] | Rest], Directory) -> - case inets_regexp:match(Path, NewDirectory) of - {match, _, _} when Directory =:= to_be_found -> + case re:run(Path, NewDirectory, [{capture, first}]) of + {match, _} when Directory =:= to_be_found -> secret_path(Path, Rest, NewDirectory); - {match, _, Length} when Length > length(Directory)-> + {match, [{_, Length}]} when Length > length(Directory)-> secret_path(Path, Rest,NewDirectory); - {match, _, _Length} -> + {match, _} -> secret_path(Path, Rest, Directory); nomatch -> secret_path(Path, Rest, Directory) @@ -588,8 +588,8 @@ validate_addr(_RemoteAddr, none) -> % When called from 'deny' validate_addr(_RemoteAddr, []) -> false; validate_addr(RemoteAddr, [HostRegExp | Rest]) -> - case inets_regexp:match(RemoteAddr, HostRegExp) of - {match,_,_} -> + case re:run(RemoteAddr, HostRegExp, [{capture, none}]) of + match -> true; nomatch -> validate_addr(RemoteAddr,Rest) diff --git a/lib/inets/src/http_server/mod_auth_plain.erl b/lib/inets/src/http_server/mod_auth_plain.erl index e85d3b8776..1a3120e03c 100644 --- a/lib/inets/src/http_server/mod_auth_plain.erl +++ b/lib/inets/src/http_server/mod_auth_plain.erl @@ -244,11 +244,11 @@ parse_group(Stream, GroupList, "") -> parse_group(Stream, GroupList, [$#|_]) -> parse_group(Stream, GroupList); parse_group(Stream, GroupList, Line) -> - case inets_regexp:split(Line, ":") of - {ok, [Group,Users]} -> - {ok, UserList} = inets_regexp:split(Users," "), + case re:split(Line, ":", [{return, list}]) of + [Group,Users] -> + UserList = re:split(Users," ", [{return, list}]), parse_group(Stream, [{Group,UserList}|GroupList]); - {ok, _} -> + _ -> {error, ?NICE(Line)} end. @@ -278,10 +278,10 @@ parse_passwd(Stream, PasswdList, "") -> parse_passwd(Stream, PasswdList, [$#|_]) -> parse_passwd(Stream, PasswdList); parse_passwd(Stream, PasswdList, Line) -> - case inets_regexp:split(Line,":") of - {ok, [User,Password]} -> + case re:split(Line,":", [{return, list}]) of + [User,Password] -> parse_passwd(Stream, [{User,Password, []}|PasswdList]); - {ok,_} -> + _ -> {error, ?NICE(Line)} end. diff --git a/lib/inets/src/http_server/mod_browser.erl b/lib/inets/src/http_server/mod_browser.erl index ca643ab728..e3c41793ae 100644 --- a/lib/inets/src/http_server/mod_browser.erl +++ b/lib/inets/src/http_server/mod_browser.erl @@ -98,9 +98,9 @@ getBrowser1(Info) -> getBrowser(AgentString) -> LAgentString = http_util:to_lower(AgentString), - case inets_regexp:first_match(LAgentString,"^[^ ]*") of - {match,Start,Length} -> - Browser = lists:sublist(LAgentString,Start,Length), + case re:run(LAgentString,"^[^ ]*", [{capture, first}]) of + {match,[{Start,Length}]} -> + Browser = lists:sublist(LAgentString,Start+1,Length), case browserType(Browser) of {mozilla,Vsn} -> {getMozilla(LAgentString, @@ -164,8 +164,8 @@ operativeSystem(OpString,[{RetVal,RegExps}|Rest]) -> controlOperativeSystem(_OpString,[]) -> false; controlOperativeSystem(OpString,[Regexp|Regexps]) -> - case inets_regexp:match(OpString,Regexp) of - {match,_,_} -> + case re:run(OpString,Regexp, [{capture, none}]) of + match -> true; nomatch -> controlOperativeSystem(OpString,Regexps) @@ -182,18 +182,19 @@ controlOperativeSystem(OpString,[Regexp|Regexps]) -> getMozilla(_AgentString,[],Default) -> Default; getMozilla(AgentString,[{Agent,AgentRegExp}|Rest],Default) -> - case inets_regexp:match(AgentString,AgentRegExp) of - {match,_,_} -> + case re:run(AgentString,AgentRegExp, [{capture, none}]) of + match -> {Agent,getMozVersion(AgentString,AgentRegExp)}; nomatch -> getMozilla(AgentString,Rest,Default) end. getMozVersion(AgentString, AgentRegExp) -> - case inets_regexp:match(AgentString,AgentRegExp++"[0-9\.\ \/]*") of - {match,Start,Length} when length(AgentRegExp) < Length -> + case re:run(AgentString,AgentRegExp++"[0-9\.\ \/]*", + [{capture, first}]) of + {match, [{Start,Length}]} when length(AgentRegExp) < Length -> %% Ok we got the number split it out - RealStart = Start+length(AgentRegExp), + RealStart = Start+1+length(AgentRegExp), RealLength = Length-length(AgentRegExp), VsnString = string:substr(AgentString,RealStart,RealLength), %% case string:strip(VsnString,both,$\ ) of diff --git a/lib/inets/src/http_server/mod_dir.erl b/lib/inets/src/http_server/mod_dir.erl index 9d848ac013..2d8f27af3c 100644 --- a/lib/inets/src/http_server/mod_dir.erl +++ b/lib/inets/src/http_server/mod_dir.erl @@ -125,12 +125,13 @@ header(Path,RequestURI) -> RequestURI ++ "</H1>\n<PRE><IMG SRC=\"" ++ icon(blank) ++ "\" ALT=" "> Name Last modified " "Size Description <HR>\n", - case inets_regexp:sub(RequestURI,"[^/]*\$","") of - {ok,"/",_} -> + case re:replace(RequestURI,"[^/]*\$","", [{return,list}]) of + "/" -> Header; - {ok,ParentRequestURI,_} -> - {ok,ParentPath,_} = - inets_regexp:sub(string:strip(Path,right,$/),"[^/]*\$",""), + ParentRequestURI -> + ParentPath = + re:replace(string:strip(Path,right,$/),"[^/]*\$","", + [{return,list}]), Header++format(ParentPath,ParentRequestURI) end. diff --git a/lib/inets/src/http_server/mod_disk_log.erl b/lib/inets/src/http_server/mod_disk_log.erl index a0ff929a34..5e395a2118 100644 --- a/lib/inets/src/http_server/mod_disk_log.erl +++ b/lib/inets/src/http_server/mod_disk_log.erl @@ -138,8 +138,8 @@ do(Info) -> %% Description: See httpd(3) ESWAPI CALLBACK FUNCTIONS %%------------------------------------------------------------------------- load("TransferDiskLogSize " ++ TransferDiskLogSize, []) -> - case inets_regexp:split(TransferDiskLogSize," ") of - {ok,[MaxBytes,MaxFiles]} -> + try re:split(TransferDiskLogSize, " ", [{return, list}]) of + [MaxBytes, MaxFiles] -> case make_integer(MaxBytes) of {ok,MaxBytesInteger} -> case make_integer(MaxFiles) of @@ -151,17 +151,20 @@ load("TransferDiskLogSize " ++ TransferDiskLogSize, []) -> ?NICE(string:strip(TransferDiskLogSize)++ " is an invalid TransferDiskLogSize")} end; - {error,_} -> + _ -> {error,?NICE(string:strip(TransferDiskLogSize)++ - " is an invalid TransferDiskLogSize")} + " is an invalid TransferDiskLogSize")} end + catch _:_ -> + {error,?NICE(string:strip(TransferDiskLogSize) ++ + " is an invalid TransferDiskLogSize")} end; load("TransferDiskLog " ++ TransferDiskLog,[]) -> {ok,[],{transfer_disk_log,string:strip(TransferDiskLog)}}; load("ErrorDiskLogSize " ++ ErrorDiskLogSize, []) -> - case inets_regexp:split(ErrorDiskLogSize," ") of - {ok,[MaxBytes,MaxFiles]} -> + try re:split(ErrorDiskLogSize," ", [{return, list}]) of + [MaxBytes,MaxFiles] -> case make_integer(MaxBytes) of {ok,MaxBytesInteger} -> case make_integer(MaxFiles) of @@ -176,13 +179,16 @@ load("ErrorDiskLogSize " ++ ErrorDiskLogSize, []) -> {error,?NICE(string:strip(ErrorDiskLogSize)++ " is an invalid ErrorDiskLogSize")} end + catch _:_ -> + {error,?NICE(string:strip(ErrorDiskLogSize) ++ + " is an invalid TransferDiskLogSize")} end; load("ErrorDiskLog " ++ ErrorDiskLog, []) -> {ok, [], {error_disk_log, string:strip(ErrorDiskLog)}}; load("SecurityDiskLogSize " ++ SecurityDiskLogSize, []) -> - case inets_regexp:split(SecurityDiskLogSize, " ") of - {ok, [MaxBytes, MaxFiles]} -> + try re:split(SecurityDiskLogSize, " ", [{return, list}]) of + [MaxBytes, MaxFiles] -> case make_integer(MaxBytes) of {ok, MaxBytesInteger} -> case make_integer(MaxFiles) of @@ -198,6 +204,9 @@ load("SecurityDiskLogSize " ++ SecurityDiskLogSize, []) -> {error, ?NICE(string:strip(SecurityDiskLogSize) ++ " is an invalid SecurityDiskLogSize")} end + catch _:_ -> + {error,?NICE(string:strip(SecurityDiskLogSize) ++ + " is an invalid SecurityDiskLogSize")} end; load("SecurityDiskLog " ++ SecurityDiskLog, []) -> {ok, [], {security_disk_log, string:strip(SecurityDiskLog)}}; diff --git a/lib/inets/src/http_server/mod_esi.erl b/lib/inets/src/http_server/mod_esi.erl index 1923411449..967bd6bbf3 100644 --- a/lib/inets/src/http_server/mod_esi.erl +++ b/lib/inets/src/http_server/mod_esi.erl @@ -96,26 +96,27 @@ do(ModData) -> %% Description: See httpd(3) ESWAPI CALLBACK FUNCTIONS %%------------------------------------------------------------------------- load("ErlScriptAlias " ++ ErlScriptAlias, []) -> - case inets_regexp:split(ErlScriptAlias," ") of - {ok, [ErlName | StrModules]} -> + try re:split(ErlScriptAlias," ", [{return, list}]) of + [ErlName | StrModules] -> Modules = lists:map(fun(Str) -> list_to_atom(string:strip(Str)) end, StrModules), - {ok, [], {erl_script_alias, {ErlName, Modules}}}; - {ok, _} -> + {ok, [], {erl_script_alias, {ErlName, Modules}}} + catch _:_ -> {error, ?NICE(string:strip(ErlScriptAlias) ++ - " is an invalid ErlScriptAlias")} + " is an invalid ErlScriptAlias")} end; load("EvalScriptAlias " ++ EvalScriptAlias, []) -> - case inets_regexp:split(EvalScriptAlias, " ") of - {ok, [EvalName | StrModules]} -> + try re:split(EvalScriptAlias, " ", [{return, list}]) of + [EvalName | StrModules] -> Modules = lists:map(fun(Str) -> list_to_atom(string:strip(Str)) end, StrModules), - {ok, [], {eval_script_alias, {EvalName, Modules}}}; - {ok, _} -> + {ok, [], {eval_script_alias, {EvalName, Modules}}} + catch + _:_ -> {error, ?NICE(string:strip(EvalScriptAlias) ++ - " is an invalid EvalScriptAlias")} + " is an invalid EvalScriptAlias")} end; load("ErlScriptTimeout " ++ Timeout, [])-> case catch list_to_integer(string:strip(Timeout)) of @@ -224,8 +225,8 @@ match_esi_script(_, [], _) -> no_match; match_esi_script(RequestURI, [{Alias,Modules} | Rest], AliasType) -> AliasMatchStr = alias_match_str(Alias, AliasType), - case inets_regexp:first_match(RequestURI, AliasMatchStr) of - {match, 1, Length} -> + case re:run(RequestURI, AliasMatchStr, [{capture, first}]) of + {match, [{0, Length}]} -> {string:substr(RequestURI, Length + 1), Modules}; nomatch -> match_esi_script(RequestURI, Rest, AliasType) @@ -584,9 +585,9 @@ generate_webpage(ESIBody) -> is_authorized(_ESIBody, [all]) -> true; is_authorized(ESIBody, Modules) -> - case inets_regexp:match(ESIBody, "^[^\:(%3A)]*") of - {match, Start, Length} -> - lists:member(list_to_atom(string:substr(ESIBody, Start, Length)), + case re:run(ESIBody, "^[^\:(%3A)]*", [{capture, first}]) of + {match, [{Start, Length}]} -> + lists:member(list_to_atom(string:substr(ESIBody, Start+1, Length)), Modules); nomatch -> false diff --git a/lib/inets/src/http_server/mod_htaccess.erl b/lib/inets/src/http_server/mod_htaccess.erl index c6ae20ced7..f229c96f2d 100644 --- a/lib/inets/src/http_server/mod_htaccess.erl +++ b/lib/inets/src/http_server/mod_htaccess.erl @@ -327,9 +327,9 @@ memberNetwork(Networks,UserNetwork,IfTrue,IfFalse)-> %ipadresses or subnet addresses. memberNetwork(Networks,UserNetwork)-> case lists:filter(fun(Net)-> - case inets_regexp:match(UserNetwork, - formatRegexp(Net)) of - {match,1,_}-> + case re:run(UserNetwork, + formatRegexp(Net), [{capture, first}]) of + {match,[{0,_}]}-> true; _NotSubNet -> false @@ -638,13 +638,8 @@ getHtAccessFileNames(Info)-> %HtAccessFileNames=["accessfileName1",..."AccessFileName2"] %---------------------------------------------------------------------- getData(Path,Info,HtAccessFileNames)-> - case inets_regexp:split(Path,"/") of - {error,Error}-> - {error,Error}; - {ok,SplittedPath}-> - getData2(HtAccessFileNames,SplittedPath,Info) - end. - + SplittedPath = re:split(Path, "/", [{return, list}]), + getData2(HtAccessFileNames,SplittedPath,Info). %---------------------------------------------------------------------- %Add to together the data in the Splittedpath up to the path @@ -942,20 +937,16 @@ getAuthorizationType(AuthType)-> %Returns a list of the specified methods to limit or the atom all %---------------------------------------------------------------------- getLimits(Limits)-> - case inets_regexp:split(Limits,">")of - {ok,[_NoEndOnLimit]}-> + case re:split(Limits,">", [{return, list}])of + [_NoEndOnLimit]-> error; - {ok, [Methods | _Crap]}-> - case inets_regexp:split(Methods," ") of - {ok,[]}-> + [Methods | _Crap]-> + case re:split(Methods," ", [{return, list}]) of + [[]]-> all; - {ok,SplittedMethods}-> - SplittedMethods; - {error, _Error}-> - error - end; - {error,_Error}-> - error + SplittedMethods -> + SplittedMethods + end end. diff --git a/lib/inets/src/http_server/mod_security.erl b/lib/inets/src/http_server/mod_security.erl index 20f87619c1..1f936d598a 100644 --- a/lib/inets/src/http_server/mod_security.erl +++ b/lib/inets/src/http_server/mod_security.erl @@ -273,12 +273,12 @@ secret_path(_Path, [], to_be_found) -> secret_path(_Path, [], Dir) -> {yes, Dir}; secret_path(Path, [[NewDir]|Rest], Dir) -> - case inets_regexp:match(Path, NewDir) of - {match, _, _} when Dir =:= to_be_found -> + case re:run(Path, NewDir, [{capture, first}]) of + {match, _} when Dir =:= to_be_found -> secret_path(Path, Rest, NewDir); - {match, _, Length} when Length > length(Dir) -> + {match, [{_, Length}]} when Length > length(Dir) -> secret_path(Path, Rest, NewDir); - {match, _, _} -> + {match, _} -> secret_path(Path, Rest, Dir); nomatch -> secret_path(Path, Rest, Dir) diff --git a/lib/inets/src/inets_app/Makefile b/lib/inets/src/inets_app/Makefile index 82cda6aaf0..0a4b625b6a 100644 --- a/lib/inets/src/inets_app/Makefile +++ b/lib/inets/src/inets_app/Makefile @@ -47,7 +47,6 @@ MODULES = \ inets_service \ inets_app \ inets_sup \ - inets_regexp \ inets_trace \ inets_lib \ inets_time_compat diff --git a/lib/inets/src/inets_app/inets.app.src b/lib/inets/src/inets_app/inets.app.src index 883ba84e8e..2f213794a3 100644 --- a/lib/inets/src/inets_app/inets.app.src +++ b/lib/inets/src/inets_app/inets.app.src @@ -26,7 +26,6 @@ inets_sup, inets_app, inets_service, - inets_regexp, inets_trace, inets_lib, inets_time_compat, diff --git a/lib/inets/src/inets_app/inets_regexp.erl b/lib/inets/src/inets_app/inets_regexp.erl deleted file mode 100644 index fc1608bc5a..0000000000 --- a/lib/inets/src/inets_app/inets_regexp.erl +++ /dev/null @@ -1,414 +0,0 @@ -%% -%% %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. diff --git a/lib/inets/src/tftp/tftp_engine.erl b/lib/inets/src/tftp/tftp_engine.erl index d0510e795b..8d282a1e9d 100644 --- a/lib/inets/src/tftp/tftp_engine.erl +++ b/lib/inets/src/tftp/tftp_engine.erl @@ -1153,8 +1153,8 @@ match_callback(Filename, Callbacks) -> end. do_match_callback(Filename, [C | Tail]) when is_record(C, callback) -> - case catch inets_regexp:match(Filename, C#callback.internal) of - {match, _, _} -> + case catch re:run(Filename, C#callback.internal, [{capture, none}]) of + match -> {ok, C}; nomatch -> do_match_callback(Filename, Tail); diff --git a/lib/inets/src/tftp/tftp_lib.erl b/lib/inets/src/tftp/tftp_lib.erl index 71327f8023..01dea97d07 100644 --- a/lib/inets/src/tftp/tftp_lib.erl +++ b/lib/inets/src/tftp/tftp_lib.erl @@ -184,7 +184,7 @@ do_parse_config([{Key, Val} | Tail], Config) when is_record(Config, config) -> callback -> case Val of {RegExp, Mod, State} when is_list(RegExp), is_atom(Mod) -> - case inets_regexp:parse(RegExp) of + case re:compile(RegExp) of {ok, Internal} -> Callback = #callback{regexp = RegExp, internal = Internal, @@ -253,7 +253,7 @@ do_parse_config(Options, Config) when is_record(Config, config) -> add_default_callbacks(Callbacks) -> RegExp = "", - {ok, Internal} = inets_regexp:parse(RegExp), + {ok, Internal} = re:compile(RegExp), File = #callback{regexp = RegExp, internal = Internal, module = tftp_file, diff --git a/lib/inets/test/httpd_1_1.erl b/lib/inets/test/httpd_1_1.erl index db6def9d17..d3a1e3672a 100644 --- a/lib/inets/test/httpd_1_1.erl +++ b/lib/inets/test/httpd_1_1.erl @@ -370,18 +370,18 @@ validateRangeRequest2(Socket, Head, Body, ValidBody, BodySize) validateMultiPartRangeRequest(Body, ValidBody, Boundary)-> - case inets_regexp:split(Body,"--"++Boundary++"--") of + case re:split(Body,"--"++Boundary++"--", [{return, list}]) of %%Last is the epilogue and must be ignored - {ok,[First | _Last]}-> + [First | _Last]-> %%First is now the actuall http request body. - case inets_regexp:split(First, "--" ++ Boundary) of + case re:split(First, "--" ++ Boundary, [{return, list}]) of %%Parts is now a list of ranges and the heads for each range %%Gues we try to split out the body - {ok,Parts}-> + Parts-> case lists:flatten(lists:map(fun splitRange/1,Parts)) of ValidBody-> ok; - ParsedBody-> + ParsedBody-> error = ParsedBody end end; @@ -391,8 +391,8 @@ validateMultiPartRangeRequest(Body, ValidBody, Boundary)-> splitRange(Part)-> - case inets_regexp:split(Part, "\r\n\r\n") of - {ok,[_, Body]} -> + case re:split(Part, "\r\n\r\n", [{return, list}]) of + [_, Body] -> string:substr(Body, 1, length(Body) - 2); _ -> [] @@ -412,13 +412,13 @@ getRangeSize(Head)-> {multiPart, BoundaryString}-> {multiPart, BoundaryString}; _X1 -> - case inets_regexp:match(Head, ?CONTENT_RANGE "bytes=.*\r\n") of - {match, Start, Lenght} -> + case re:run(Head, ?CONTENT_RANGE "bytes=.*\r\n", [{capture, first}]) of + {match, [{Start, Lenght}]} -> %% Get the range data remove the fieldname and the %% end of line. - RangeInfo = string:substr(Head, Start + 20, - Lenght - (20 - 2)), - rangeSize(RangeInfo); + RangeInfo = string:substr(Head, Start + 1 + 20, + Lenght - (20 +2)), + rangeSize(string:strip(RangeInfo)); _X2 -> error end @@ -454,10 +454,10 @@ num(_CharVal, false) -> true. controlMimeType(Head)-> - case inets_regexp:match(Head,?CONTENT_TYPE "multipart/byteranges.*\r\n") of - {match,Start,Length}-> + case re:run(Head,?CONTENT_TYPE "multipart/byteranges.*\r\n", [{capture, first}]) of + {match, [{Start,Length}]}-> FieldNameLen = length(?CONTENT_TYPE "multipart/byteranges"), - case clearBoundary(string:substr(Head, Start + FieldNameLen, + case clearBoundary(string:substr(Head, Start + 1 + FieldNameLen, Length - (FieldNameLen+2))) of error -> error; @@ -471,10 +471,10 @@ controlMimeType(Head)-> end. clearBoundary(Boundary)-> - case inets_regexp:match(Boundary, "boundary=.*\$") of - {match, Start1, Length1}-> + case re:run(Boundary, "boundary=.*\$", [{capture, first}]) of + {match, [{Start1, Length1}]}-> BoundLen = length("boundary="), - string:substr(Boundary, Start1 + BoundLen, Length1 - BoundLen); + string:substr(Boundary, Start1 + 1 + BoundLen, Length1 - BoundLen); _ -> error end. @@ -489,12 +489,12 @@ end_of_header(HeaderPart) -> end. get_body_size(Head) -> - case inets_regexp:match(Head,?CONTENT_LENGTH ".*\r\n") of - {match, Start, Length} -> + case re:run(Head,?CONTENT_LENGTH ".*\r\n", [{capture, first}]) of + {match, [{Start, Length}]} -> %% 15 is length of Content-Length, %% 17 Is length of Content-Length and \r\ S = list_to_integer( - string:strip(string:substr(Head, Start + 15, Length-17))), + string:strip(string:substr(Head, Start +1 + 15, Length-17))), S; _-> 0 diff --git a/lib/inets/test/httpd_poll.erl b/lib/inets/test/httpd_poll.erl index aca7b70376..4a570fb512 100644 --- a/lib/inets/test/httpd_poll.erl +++ b/lib/inets/test/httpd_poll.erl @@ -259,11 +259,11 @@ validate(ExpStatusCode,Socket,Response) -> vtrace("validate -> Entry with ~p bytes response",[Sz]), Size = trash_the_rest(Socket,Sz), close(Socket), - case inets_regexp:split(Response," ") of - {ok,["HTTP/1.0",ExpStatusCode|_]} -> + case re:split(Response," ", [{return, list}]) of + ["HTTP/1.0",ExpStatusCode|_] -> vlog("response (~p bytes) was ok",[Size]), ok; - {ok,["HTTP/1.0",StatusCode|_]} -> + ["HTTP/1.0",StatusCode|_] -> verror("unexpected response status received: ~s => ~s", [StatusCode,status_to_message(StatusCode)]), log("unexpected result to GET of '~s': ~s => ~s", diff --git a/lib/inets/test/httpd_test_lib.erl b/lib/inets/test/httpd_test_lib.erl index c58966ce10..71e201f826 100644 --- a/lib/inets/test/httpd_test_lib.erl +++ b/lib/inets/test/httpd_test_lib.erl @@ -96,10 +96,10 @@ verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options, Ti try inets_test_lib:connect_bin(SocketType, Host, Port, TranspOpts) of {ok, Socket} -> ok = inets_test_lib:send(SocketType, Socket, RequestStr), - State = case inets_regexp:match(RequestStr, "printenv") of + State = case re:run(RequestStr, "printenv", [{capture, none}]) of nomatch -> #state{}; - _ -> + match -> #state{print = true} end, @@ -317,10 +317,10 @@ do_validate(Header, [_Unknown | Rest], N, P) -> do_validate(Header, Rest, N, P). is_expect(RequestStr) -> - case inets_regexp:match(RequestStr, "xpect:100-continue") of - {match, _, _}-> + case re:run(RequestStr, "xpect:100-continue", [{capture, none}]) of + match-> true; - _ -> + nomatch -> false end. diff --git a/lib/inets/test/httpd_time_test.erl b/lib/inets/test/httpd_time_test.erl index 7c0acb5a99..1b4d74b28e 100644 --- a/lib/inets/test/httpd_time_test.erl +++ b/lib/inets/test/httpd_time_test.erl @@ -386,31 +386,31 @@ validate(ExpStatusCode, _SocketType, _Socket, Response) -> %% Sz = sz(Response), %% trash_the_rest(Socket, Sz), %% inets_test_lib:close(SocketType, Socket), - case inets_regexp:split(Response," ") of - {ok, ["HTTP/1.0", ExpStatusCode|_]} -> + case re:split(Response," ", [{return, list}]) of + ["HTTP/1.0", ExpStatusCode|_] -> ok; - {ok, ["HTTP/1.0", StatusCode|_]} -> + ["HTTP/1.0", StatusCode|_] -> error_msg("Unexpected status code: ~p (~s). " "Expected status code: ~p (~s)", [StatusCode, status_to_message(StatusCode), ExpStatusCode, status_to_message(ExpStatusCode)]), exit({unexpected_response_code, StatusCode, ExpStatusCode}); - {ok, ["HTTP/1.1", ExpStatusCode|_]} -> + ["HTTP/1.1", ExpStatusCode|_] -> ok; - {ok, ["HTTP/1.1", StatusCode|_]} -> + ["HTTP/1.1", StatusCode|_] -> error_msg("Unexpected status code: ~p (~s). " "Expected status code: ~p (~s)", [StatusCode, status_to_message(StatusCode), ExpStatusCode, status_to_message(ExpStatusCode)]), exit({unexpected_response_code, StatusCode, ExpStatusCode}); - {ok, Unexpected} -> - error_msg("Unexpected response split: ~p (~s)", - [Unexpected, Response]), - exit({unexpected_response, Unexpected, Response}); - {error, Reason} -> + {error, Reason} -> error_msg("Failed processing response: ~p (~s)", [Reason, Response]), - exit({failed_response_processing, Reason, Response}) + exit({failed_response_processing, Reason, Response}); + Unexpected -> + error_msg("Unexpected response split: ~p (~s)", + [Unexpected, Response]), + exit({unexpected_response, Unexpected, Response}) end. diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk index 2717f5b110..ee5f41aaec 100644 --- a/lib/inets/vsn.mk +++ b/lib/inets/vsn.mk @@ -19,6 +19,6 @@ # %CopyrightEnd% APPLICATION = inets -INETS_VSN = 6.1 +INETS_VSN = 6.1.1 PRE_VSN = APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)" diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml index 8fb689fdd5..75e1615c09 100644 --- a/lib/ssh/doc/src/notes.xml +++ b/lib/ssh/doc/src/notes.xml @@ -30,6 +30,24 @@ <file>notes.xml</file> </header> +<section><title>Ssh 4.2.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The authentication method 'keyboard-interactive' failed + in the Erlang client when the server after successful + authentication continued by asking for zero more + passwords.</p> + <p> + Own Id: OTP-13225</p> + </item> + </list> + </section> + +</section> + <section><title>Ssh 4.2</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl index fdbb5c152a..b71bed033a 100644 --- a/lib/ssh/src/ssh_auth.erl +++ b/lib/ssh/src/ssh_auth.erl @@ -477,7 +477,7 @@ keyboard_interact_get_responses(_, undefined, Password, _, _, _, _, _, 1) when Password =/= undefined -> [Password]; %% Password auth implemented with keyboard-interaction and passwd is known keyboard_interact_get_responses(_, _, _, _, _, _, _, _, 0) -> - [""]; + []; keyboard_interact_get_responses(false, undefined, undefined, _, _, _, [Prompt|_], Opts, _) -> ssh_no_io:read_line(Prompt, Opts); %% Throws error as keyboard interaction is not allowed keyboard_interact_get_responses(true, undefined, _,IoCb, Name, Instr, PromptInfos, Opts, _) -> diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl index f082db136c..ce1931e4f4 100644 --- a/lib/ssh/src/ssh_connection_handler.erl +++ b/lib/ssh/src/ssh_connection_handler.erl @@ -648,10 +648,12 @@ userauth_keyboard_interactive(Msg = #ssh_msg_userauth_failure{}, userauth_keyboard_interactive_info_response(Msg=#ssh_msg_userauth_failure{}, #state{ssh_params = #ssh{role = client}} = State) -> userauth(Msg, State); - userauth_keyboard_interactive_info_response(Msg=#ssh_msg_userauth_success{}, #state{ssh_params = #ssh{role = client}} = State) -> - userauth(Msg, State). + userauth(Msg, State); +userauth_keyboard_interactive_info_response(Msg=#ssh_msg_userauth_info_request{}, + #state{ssh_params = #ssh{role = client}} = State) -> + userauth_keyboard_interactive(Msg, State). %%-------------------------------------------------------------------- -spec connected({#ssh_msg_kexinit{}, binary()}, %%| %% #ssh_msg_kexdh_init{}, diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl index 5af60adfae..98a196d705 100644 --- a/lib/ssh/test/ssh_protocol_SUITE.erl +++ b/lib/ssh/test/ssh_protocol_SUITE.erl @@ -48,6 +48,7 @@ all() -> [{group,tool_tests}, {group,kex}, {group,service_requests}, + {group,authentication}, {group,packet_size_error}, {group,field_size_error} ]. @@ -78,7 +79,9 @@ groups() -> bad_very_long_service_name, empty_service_name, bad_service_name_then_correct - ]} + ]}, + {authentication, [], [client_handles_keyboard_interactive_0_pwds + ]} ]. @@ -516,6 +519,82 @@ bad_service_name_length(Config, LengthExcess) -> receive_msg} ], InitialState). +%%%-------------------------------------------------------------------- +%%% This is due to a fault report (OTP-13255) with OpenSSH-6.6.1 +client_handles_keyboard_interactive_0_pwds(Config) -> + {User,_Pwd} = server_user_password(Config), + + %% Create a listening socket as server socket: + {ok,InitialState} = ssh_trpt_test_lib:exec(listen), + HostPort = ssh_trpt_test_lib:server_host_port(InitialState), + + %% Start a process handling one connection on the server side: + spawn_link( + fun() -> + {ok,_} = + ssh_trpt_test_lib:exec( + [{set_options, [print_ops, print_messages]}, + {accept, [{system_dir, system_dir(Config)}, + {user_dir, user_dir(Config)}]}, + receive_hello, + {send, hello}, + + {send, ssh_msg_kexinit}, + {match, #ssh_msg_kexinit{_='_'}, receive_msg}, + + {match, #ssh_msg_kexdh_init{_='_'}, receive_msg}, + {send, ssh_msg_kexdh_reply}, + + {send, #ssh_msg_newkeys{}}, + {match, #ssh_msg_newkeys{_='_'}, receive_msg}, + + {match, #ssh_msg_service_request{name="ssh-userauth"}, receive_msg}, + {send, #ssh_msg_service_accept{name="ssh-userauth"}}, + + {match, #ssh_msg_userauth_request{service="ssh-connection", + method="none", + user=User, + _='_'}, receive_msg}, + {send, #ssh_msg_userauth_failure{authentications = "keyboard-interactive", + partial_success = false}}, + + {match, #ssh_msg_userauth_request{service="ssh-connection", + method="keyboard-interactive", + user=User, + _='_'}, receive_msg}, + {send, #ssh_msg_userauth_info_request{name = "", + instruction = "", + language_tag = "", + num_prompts = 1, + data = <<0,0,0,10,80,97,115,115,119,111,114,100,58,32,0>> + }}, + {match, #ssh_msg_userauth_info_response{num_responses = 1, + _='_'}, receive_msg}, + + %% the next is strange, but openssh 6.6.1 does this and this is what this testcase is about + {send, #ssh_msg_userauth_info_request{name = "", + instruction = "", + language_tag = "", + num_prompts = 0, + data = <<>> + }}, + {match, #ssh_msg_userauth_info_response{num_responses = 0, + data = <<>>, + _='_'}, receive_msg}, + %% Here we know that the tested fault is fixed + {send, #ssh_msg_userauth_success{}}, + close_socket, + print_state + ], + InitialState) + end), + + %% and finally connect to it with a regular Erlang SSH client: + {ok,_} = std_connect(HostPort, Config, + [{preferred_algorithms,[{kex,['diffie-hellman-group1-sha1']}]}] + ). + + %%%================================================================ %%%==== Internal functions ======================================== %%%================================================================ diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk index 25b19133b1..55d12abffe 100644 --- a/lib/ssh/vsn.mk +++ b/lib/ssh/vsn.mk @@ -1,5 +1,5 @@ #-*-makefile-*- ; force emacs to enter makefile-mode -SSH_VSN = 4.2 +SSH_VSN = 4.2.1 APP_VSN = "ssh-$(SSH_VSN)" diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index 4441545257..13523730b0 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -754,11 +754,9 @@ erlang_server_openssl_client_client_cert(Config) when is_list(Config) -> "-CAfile", CaCertFile, "-key", KeyFile,"-connect", "localhost:" ++ integer_to_list(Port), ssl_test_lib:version_flag(Version)], - OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), - true = port_command(OpenSslPort, Data), - + true = port_command(OpenSslPort, Data), ssl_test_lib:check_result(Server, ok), %% Clean close down! Server needs to be closed first !! @@ -842,7 +840,6 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) -> Exe = "openssl", Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version), "-cert", CertFile, "-key", KeyFile], - OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), ssl_test_lib:wait_for_openssl_server(Port), @@ -1004,7 +1001,7 @@ erlang_client_alpn_openssl_server(Config) when is_list(Config) -> Data = "From openssl to erlang", start_erlang_client_and_openssl_server_with_opts(Config, [{alpn_advertised_protocols, [<<"spdy/2">>]}], - "", + [], Data, fun(Server, OpensslPort) -> true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Server, ok) @@ -1017,7 +1014,7 @@ erlang_client_openssl_server_alpn(Config) when is_list(Config) -> Data = "From openssl to erlang", start_erlang_client_and_openssl_server_with_opts(Config, [], - "-alpn spdy/2", + ["-alpn", "spdy/2"], Data, fun(Server, OpensslPort) -> true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Server, ok) @@ -1154,7 +1151,7 @@ erlang_server_openssl_client_npn_renegotiate(Config) when is_list(Config) -> erlang_client_openssl_server_npn_only_server(Config) when is_list(Config) -> Data = "From openssl to erlang", start_erlang_client_and_openssl_server_with_opts(Config, [], - "-nextprotoneg spdy/2", Data, fun(Server, OpensslPort) -> + ["-nextprotoneg", "spdy/2"], Data, fun(Server, OpensslPort) -> true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Server, ok) end), @@ -1166,7 +1163,7 @@ erlang_client_openssl_server_npn_only_client(Config) when is_list(Config) -> Data = "From openssl to erlang", start_erlang_client_and_openssl_server_with_opts(Config, [{client_preferred_next_protocols, - {client, [<<"spdy/2">>], <<"http/1.1">>}}], "", + {client, [<<"spdy/2">>], <<"http/1.1">>}}], [], Data, fun(Server, OpensslPort) -> true = port_command(OpensslPort, Data), ssl_test_lib:check_result(Server, ok) @@ -1277,14 +1274,14 @@ erlang_server_openssl_client_sni_test(Config, SNIHostname, ExpectedSNIHostname, {from, self()}, {mfa, {?MODULE, send_and_hostname, []}}, {options, ServerOptions}]), Port = ssl_test_lib:inet_port(Server), - ClientCommand = case SNIHostname of + Exe = "openssl", + ClientArgs = case SNIHostname of undefined -> - "openssl s_client -connect " ++ Hostname ++ ":" ++ integer_to_list(Port); + ["s_client", "-connect", Hostname ++ ":" ++ integer_to_list(Port)]; _ -> - "openssl s_client -connect " ++ Hostname ++ ":" ++ integer_to_list(Port) ++ " -servername " ++ SNIHostname - end, - ct:log("Options: ~p", [[ServerOptions, ClientCommand]]), - ClientPort = open_port({spawn, ClientCommand}, [stderr_to_stdout]), + ["s_client", "-connect", Hostname ++ ":" ++ integer_to_list(Port), "-servername", SNIHostname] + end, + ClientPort = ssl_test_lib:portable_open_port(Exe, ClientArgs), %% Client check needs to be done befor server check, %% or server check might consume client messages @@ -1306,14 +1303,14 @@ erlang_server_openssl_client_sni_test_sni_fun(Config, SNIHostname, ExpectedSNIHo {from, self()}, {mfa, {?MODULE, send_and_hostname, []}}, {options, ServerOptions}]), Port = ssl_test_lib:inet_port(Server), - ClientCommand = case SNIHostname of + Exe = "openssl", + ClientArgs = case SNIHostname of undefined -> - "openssl s_client -connect " ++ Hostname ++ ":" ++ integer_to_list(Port); + ["s_client", "-connect", Hostname ++ ":" ++ integer_to_list(Port)]; _ -> - "openssl s_client -connect " ++ Hostname ++ ":" ++ integer_to_list(Port) ++ " -servername " ++ SNIHostname + ["s_client", "-connect", Hostname ++ ":" ++ integer_to_list(Port), "-servername", SNIHostname] end, - ct:log("Options: ~p", [[ServerOptions, ClientCommand]]), - ClientPort = open_port({spawn, ClientCommand}, [stderr_to_stdout]), + ClientPort = ssl_test_lib:portable_open_port(Exe, ClientArgs), %% Client check needs to be done befor server check, %% or server check might consume client messages @@ -1333,12 +1330,11 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), - Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "", - - ct:log("openssl cmd: ~p~n", [Cmd]), + Exe = "openssl", + Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-cert", CertFile, "-key", KeyFile], - OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), ssl_test_lib:wait_for_openssl_server(Port), @@ -1396,13 +1392,19 @@ start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, Opens KeyFile = proplists:get_value(keyfile, ServerOpts), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_server " ++ OpensslServerOpts ++ " -accept " ++ - integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -cert " ++ CertFile ++ " -key " ++ KeyFile, - - ct:log("openssl cmd: ~p~n", [Cmd]), - - OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + Exe = "openssl", + Args = case OpensslServerOpts of + [] -> + ["s_server", "-accept", + integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-cert", CertFile,"-key", KeyFile]; + [Opt, Value] -> + ["s_server", Opt, Value, "-accept", + integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-cert", CertFile,"-key", KeyFile] + end, + + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), ssl_test_lib:wait_for_openssl_server(Port), @@ -1436,13 +1438,10 @@ start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, Callba KeyFile = proplists:get_value(keyfile, ServerOpts), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_server -msg -alpn http/1.1,spdy/2 -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -cert " ++ CertFile ++ " -key " ++ KeyFile, - - ct:log("openssl cmd: ~p~n", [Cmd]), - - OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), - + Exe = "openssl", + Args = ["s_server", "-msg", "-alpn", "http/1.1,spdy/2", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-cert", CertFile, "-key" ++ KeyFile], + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), ssl_test_lib:wait_for_openssl_server(Port), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, @@ -1474,12 +1473,13 @@ start_erlang_server_and_openssl_client_for_alpn_negotiation(Config, Data, Callba {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_client -alpn http/1.0,spdy/2 -msg -port " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -host localhost", - ct:log("openssl cmd: ~p~n", [Cmd]), + Exe = "openssl", + Args = ["s_client", "-alpn", "http/1.0,spdy/2" "-msg" "-port", + integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-host", "localhost"], - OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), Callback(Server, OpenSslPort), @@ -1504,12 +1504,12 @@ start_erlang_client_and_openssl_server_for_alpn_npn_negotiation(Config, Data, Ca KeyFile = proplists:get_value(keyfile, ServerOpts), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_server -msg -alpn http/1.1,spdy/2 -nextprotoneg spdy/3 -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -cert " ++ CertFile ++ " -key " ++ KeyFile, - - ct:log("openssl cmd: ~p~n", [Cmd]), + Exe = "openssl", + Args = ["s_server", "-msg", "-alpn", "http/1.1,spdy/2", "-nextprotoneg", + "spdy/3", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-cert" ++ CertFile ++ "-key" ++ KeyFile], - OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), ssl_test_lib:wait_for_openssl_server(Port), @@ -1543,17 +1543,15 @@ start_erlang_server_and_openssl_client_for_alpn_npn_negotiation(Config, Data, Ca {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - Cmd = "openssl s_client -alpn http/1.1,spdy/2 -nextprotoneg spdy/3 -msg -port " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -host localhost", - - ct:log("openssl cmd: ~p~n", [Cmd]), - - OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + Exe = "openssl", + Args = ["s_client", "-alpn", "http/1.1,spdy/2", "-nextprotoneg", "spdy/3", + "-msg", "-port", integer_to_list(Port), ssl_test_lib:version_flag(Version), + "-host", "localhost"], + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), Callback(Server, OpenSslPort), ssl_test_lib:close(Server), - ssl_test_lib:close_port(OpenSslPort), process_flag(trap_exit, false). @@ -1571,13 +1569,12 @@ start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callbac CertFile = proplists:get_value(certfile, ServerOpts), KeyFile = proplists:get_value(keyfile, ServerOpts), Version = tls_record:protocol_version(tls_record:highest_protocol_version([])), - - Cmd = "openssl s_server -msg -nextprotoneg http/1.1,spdy/2 -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++ - " -cert " ++ CertFile ++ " -key " ++ KeyFile, - - ct:log("openssl cmd: ~p~n", [Cmd]), - - OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + + Exe = "openssl", + Args = ["s_server", "-msg", "-nextprotoneg", "http/1.1,spdy/2", "-accept", integer_to_list(Port), + ssl_test_lib:version_flag(Version), + "-cert", CertFile, "-key", KeyFile], + OpensslPort = ssl_test_lib:portable_open_port(Exe, Args), ssl_test_lib:wait_for_openssl_server(Port), @@ -1760,7 +1757,9 @@ check_sane_openssl_renegotaite(Config) -> end. check_sane_openssl_sslv2(Config) -> - Port = open_port({spawn, "openssl s_client -ssl2 "}, [stderr_to_stdout]), + Exe = "openssl", + Args = ["s_client", "-ssl2"], + Port = ssl_test_lib:portable_open_port(Exe, Args), case supports_sslv2(Port) of true -> Config; diff --git a/otp_versions.table b/otp_versions.table index b0f8efeb4c..377e525448 100644 --- a/otp_versions.table +++ b/otp_versions.table @@ -1,3 +1,7 @@ +OTP-18.2.4 : common_test-1.11.2 # asn1-4.0.1 compiler-6.0.2 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6.2 debugger-4.1.1 dialyzer-2.8.2 diameter-1.11.1 edoc-0.7.17 eldap-1.2 erl_docgen-0.4.1 erl_interface-3.8.1 erts-7.2.1 et-1.5.1 eunit-2.2.12 gs-1.6 hipe-3.14 ic-4.4 inets-6.1.1 jinterface-1.6.1 kernel-4.1.1 megaco-3.18 mnesia-4.13.2 observer-2.1.1 odbc-2.11.1 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1 reltool-0.7 runtime_tools-1.9.2 sasl-2.6.1 snmp-5.2.1 ssh-4.2.1 ssl-7.2 stdlib-2.7 syntax_tools-1.7 test_server-3.9.1 tools-2.8.2 typer-0.9.10 webtool-0.9 wx-1.6 xmerl-1.3.9 : +OTP-18.2.3 : inets-6.1.1 # asn1-4.0.1 common_test-1.11.1 compiler-6.0.2 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6.2 debugger-4.1.1 dialyzer-2.8.2 diameter-1.11.1 edoc-0.7.17 eldap-1.2 erl_docgen-0.4.1 erl_interface-3.8.1 erts-7.2.1 et-1.5.1 eunit-2.2.12 gs-1.6 hipe-3.14 ic-4.4 jinterface-1.6.1 kernel-4.1.1 megaco-3.18 mnesia-4.13.2 observer-2.1.1 odbc-2.11.1 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1 reltool-0.7 runtime_tools-1.9.2 sasl-2.6.1 snmp-5.2.1 ssh-4.2.1 ssl-7.2 stdlib-2.7 syntax_tools-1.7 test_server-3.9.1 tools-2.8.2 typer-0.9.10 webtool-0.9 wx-1.6 xmerl-1.3.9 : +OTP-18.2.2 : ssh-4.2.1 # asn1-4.0.1 common_test-1.11.1 compiler-6.0.2 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6.2 debugger-4.1.1 dialyzer-2.8.2 diameter-1.11.1 edoc-0.7.17 eldap-1.2 erl_docgen-0.4.1 erl_interface-3.8.1 erts-7.2.1 et-1.5.1 eunit-2.2.12 gs-1.6 hipe-3.14 ic-4.4 inets-6.1 jinterface-1.6.1 kernel-4.1.1 megaco-3.18 mnesia-4.13.2 observer-2.1.1 odbc-2.11.1 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1 reltool-0.7 runtime_tools-1.9.2 sasl-2.6.1 snmp-5.2.1 ssl-7.2 stdlib-2.7 syntax_tools-1.7 test_server-3.9.1 tools-2.8.2 typer-0.9.10 webtool-0.9 wx-1.6 xmerl-1.3.9 : +OTP-18.2.1 : erts-7.2.1 # asn1-4.0.1 common_test-1.11.1 compiler-6.0.2 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6.2 debugger-4.1.1 dialyzer-2.8.2 diameter-1.11.1 edoc-0.7.17 eldap-1.2 erl_docgen-0.4.1 erl_interface-3.8.1 et-1.5.1 eunit-2.2.12 gs-1.6 hipe-3.14 ic-4.4 inets-6.1 jinterface-1.6.1 kernel-4.1.1 megaco-3.18 mnesia-4.13.2 observer-2.1.1 odbc-2.11.1 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1 reltool-0.7 runtime_tools-1.9.2 sasl-2.6.1 snmp-5.2.1 ssh-4.2 ssl-7.2 stdlib-2.7 syntax_tools-1.7 test_server-3.9.1 tools-2.8.2 typer-0.9.10 webtool-0.9 wx-1.6 xmerl-1.3.9 : OTP-18.2 : asn1-4.0.1 common_test-1.11.1 compiler-6.0.2 crypto-3.6.2 dialyzer-2.8.2 diameter-1.11.1 erl_docgen-0.4.1 erl_interface-3.8.1 erts-7.2 eunit-2.2.12 hipe-3.14 inets-6.1 jinterface-1.6.1 kernel-4.1.1 observer-2.1.1 parsetools-2.1.1 public_key-1.1 runtime_tools-1.9.2 sasl-2.6.1 snmp-5.2.1 ssh-4.2 ssl-7.2 stdlib-2.7 test_server-3.9.1 tools-2.8.2 typer-0.9.10 wx-1.6 xmerl-1.3.9 # cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 debugger-4.1.1 edoc-0.7.17 eldap-1.2 et-1.5.1 gs-1.6 ic-4.4 megaco-3.18 mnesia-4.13.2 odbc-2.11.1 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 percept-0.8.11 reltool-0.7 syntax_tools-1.7 webtool-0.9 : OTP-18.1.5 : ssh-4.1.3 # asn1-4.0 common_test-1.11 compiler-6.0.1 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6.1 debugger-4.1.1 dialyzer-2.8.1 diameter-1.11 edoc-0.7.17 eldap-1.2 erl_docgen-0.4 erl_interface-3.8 erts-7.1 et-1.5.1 eunit-2.2.11 gs-1.6 hipe-3.13 ic-4.4 inets-6.0.3 jinterface-1.6 kernel-4.1 megaco-3.18 mnesia-4.13.2 observer-2.1 odbc-2.11.1 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1 percept-0.8.11 public_key-1.0.1 reltool-0.7 runtime_tools-1.9.1 sasl-2.6 snmp-5.2 ssl-7.1 stdlib-2.6 syntax_tools-1.7 test_server-3.9 tools-2.8.1 typer-0.9.9 webtool-0.9 wx-1.5 xmerl-1.3.8 : OTP-18.1.4 : inets-6.0.3 # asn1-4.0 common_test-1.11 compiler-6.0.1 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6.1 debugger-4.1.1 dialyzer-2.8.1 diameter-1.11 edoc-0.7.17 eldap-1.2 erl_docgen-0.4 erl_interface-3.8 erts-7.1 et-1.5.1 eunit-2.2.11 gs-1.6 hipe-3.13 ic-4.4 jinterface-1.6 kernel-4.1 megaco-3.18 mnesia-4.13.2 observer-2.1 odbc-2.11.1 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1 percept-0.8.11 public_key-1.0.1 reltool-0.7 runtime_tools-1.9.1 sasl-2.6 snmp-5.2 ssh-4.1.2 ssl-7.1 stdlib-2.6 syntax_tools-1.7 test_server-3.9 tools-2.8.1 typer-0.9.9 webtool-0.9 wx-1.5 xmerl-1.3.8 : |