diff options
Diffstat (limited to 'lib')
118 files changed, 8254 insertions, 2053 deletions
diff --git a/lib/debugger/src/dbg_iload.erl b/lib/debugger/src/dbg_iload.erl index 1216338006..ec54c646c8 100644 --- a/lib/debugger/src/dbg_iload.erl +++ b/lib/debugger/src/dbg_iload.erl @@ -1,29 +1,25 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1998-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% -module(dbg_iload). -%% External exports -export([load_mod/4]). -%% Internal exports --export([load_mod1/4]). - %%==================================================================== %% External exports %%==================================================================== @@ -36,29 +32,29 @@ %% Db = ETS identifier %% Load a new module into the database. %% -%% We want the loading of a module to be syncronous so no other +%% We want the loading of a module to be synchronous so that no other %% process tries to interpret code in a module not being completely %% loaded. This is achieved as this function is called from %% dbg_iserver. We are suspended until the module has been loaded. %%-------------------------------------------------------------------- +-spec load_mod(Mod, file:filename(), binary(), ets:tid()) -> + {'ok', Mod} when is_subtype(Mod, atom()). + load_mod(Mod, File, Binary, Db) -> Flag = process_flag(trap_exit, true), - Pid = spawn_link(?MODULE, load_mod1, [Mod, File, Binary, Db]), + Pid = spawn_link(fun () -> load_mod1(Mod, File, Binary, Db) end), receive {'EXIT', Pid, What} -> process_flag(trap_exit, Flag), What end. -%%==================================================================== -%% Internal exports -%%==================================================================== +-spec load_mod1(atom(), file:filename(), binary(), ets:tid()) -> no_return(). load_mod1(Mod, File, Binary, Db) -> store_module(Mod, File, Binary, Db), exit({ok, Mod}). - %%==================================================================== %% Internal functions %%==================================================================== @@ -84,7 +80,7 @@ store_module(Mod, File, Binary, Db) -> Attr = store_forms(Forms, Mod, Db, Exp, []), erase(mod_md5), erase(current_function), -% store_funs(Db, Mod), + %% store_funs(Db, Mod), erase(vcount), erase(funs), erase(fun_count), diff --git a/lib/erl_interface/include/ei.h b/lib/erl_interface/include/ei.h index 03219c6d1b..729b9fc367 100644 --- a/lib/erl_interface/include/ei.h +++ b/lib/erl_interface/include/ei.h @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1998-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1998-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% */ #ifndef EI_H diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c index df3c08f412..b1b79aa0e5 100644 --- a/lib/erl_interface/src/connect/ei_connect.c +++ b/lib/erl_interface/src/connect/ei_connect.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2000-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2000-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% */ /* diff --git a/lib/erl_interface/src/connect/ei_connect_int.h b/lib/erl_interface/src/connect/ei_connect_int.h index 83ee18256f..3c42b49b82 100644 --- a/lib/erl_interface/src/connect/ei_connect_int.h +++ b/lib/erl_interface/src/connect/ei_connect_int.h @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2001-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2001-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% */ /* diff --git a/lib/erl_interface/src/decode/decode_double.c b/lib/erl_interface/src/decode/decode_double.c index 2462032eaa..ed6e39655e 100644 --- a/lib/erl_interface/src/decode/decode_double.c +++ b/lib/erl_interface/src/decode/decode_double.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1998-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1998-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% */ #include <stdio.h> diff --git a/lib/erl_interface/src/decode/decode_skip.c b/lib/erl_interface/src/decode/decode_skip.c index efe323d0d5..f6c5d861ab 100644 --- a/lib/erl_interface/src/decode/decode_skip.c +++ b/lib/erl_interface/src/decode/decode_skip.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2002-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2002-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% */ #include "eidef.h" diff --git a/lib/erl_interface/src/encode/encode_double.c b/lib/erl_interface/src/encode/encode_double.c index 1c8cb286f5..148a49f73a 100644 --- a/lib/erl_interface/src/encode/encode_double.c +++ b/lib/erl_interface/src/encode/encode_double.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1998-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1998-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% */ #include <stdio.h> diff --git a/lib/erl_interface/src/legacy/decode_term.c b/lib/erl_interface/src/legacy/decode_term.c index ddd1682f95..796cebdfef 100644 --- a/lib/erl_interface/src/legacy/decode_term.c +++ b/lib/erl_interface/src/legacy/decode_term.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1998-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1998-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% */ #include "eidef.h" diff --git a/lib/erl_interface/src/legacy/erl_marshal.c b/lib/erl_interface/src/legacy/erl_marshal.c index ad0cc5672c..c57c552b90 100644 --- a/lib/erl_interface/src/legacy/erl_marshal.c +++ b/lib/erl_interface/src/legacy/erl_marshal.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1996-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% */ /* diff --git a/lib/erl_interface/src/misc/ei_decode_term.c b/lib/erl_interface/src/misc/ei_decode_term.c index 32aec988e1..ddcbfa5a9a 100644 --- a/lib/erl_interface/src/misc/ei_decode_term.c +++ b/lib/erl_interface/src/misc/ei_decode_term.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2001-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2001-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% * diff --git a/lib/erl_interface/src/misc/ei_printterm.c b/lib/erl_interface/src/misc/ei_printterm.c index 00f98ba0a1..98473f780e 100644 --- a/lib/erl_interface/src/misc/ei_printterm.c +++ b/lib/erl_interface/src/misc/ei_printterm.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2001-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2001-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% * diff --git a/lib/erl_interface/src/misc/get_type.c b/lib/erl_interface/src/misc/get_type.c index 32daa264d0..2a680d0f94 100644 --- a/lib/erl_interface/src/misc/get_type.c +++ b/lib/erl_interface/src/misc/get_type.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1998-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1998-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% * diff --git a/lib/erl_interface/src/misc/putget.h b/lib/erl_interface/src/misc/putget.h index f0fbd9a211..7a43de324b 100644 --- a/lib/erl_interface/src/misc/putget.h +++ b/lib/erl_interface/src/misc/putget.h @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1998-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1998-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% * diff --git a/lib/erl_interface/src/misc/show_msg.c b/lib/erl_interface/src/misc/show_msg.c index 9ed27f49d5..14bea5e01f 100644 --- a/lib/erl_interface/src/misc/show_msg.c +++ b/lib/erl_interface/src/misc/show_msg.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1998-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1998-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% * diff --git a/lib/erl_interface/test/ei_decode_SUITE.erl b/lib/erl_interface/test/ei_decode_SUITE.erl index 0fd805255f..c6858b45ad 100644 --- a/lib/erl_interface/test/ei_decode_SUITE.erl +++ b/lib/erl_interface/test/ei_decode_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% diff --git a/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c b/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c index 38811c3c77..5447e2deb3 100644 --- a/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c +++ b/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2004-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2004-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% */ diff --git a/lib/erl_interface/test/ei_encode_SUITE.erl b/lib/erl_interface/test/ei_encode_SUITE.erl index dd6f37e453..6b9de4f093 100644 --- a/lib/erl_interface/test/ei_encode_SUITE.erl +++ b/lib/erl_interface/test/ei_encode_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% diff --git a/lib/erl_interface/test/ei_encode_SUITE_data/ei_encode_test.c b/lib/erl_interface/test/ei_encode_SUITE_data/ei_encode_test.c index 2d326757a1..c373658152 100644 --- a/lib/erl_interface/test/ei_encode_SUITE_data/ei_encode_test.c +++ b/lib/erl_interface/test/ei_encode_SUITE_data/ei_encode_test.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2004-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2004-2010. All Rights Reserved. + * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * %CopyrightEnd% */ diff --git a/lib/erl_interface/test/ei_tmo_SUITE.erl b/lib/erl_interface/test/ei_tmo_SUITE.erl index 4f863922e1..e7a2465421 100644 --- a/lib/erl_interface/test/ei_tmo_SUITE.erl +++ b/lib/erl_interface/test/ei_tmo_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2003-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% diff --git a/lib/gs/contribs/bonk/bonk.erl b/lib/gs/contribs/bonk/bonk.erl index 12d94f6c5e..79f01bf659 100644 --- a/lib/gs/contribs/bonk/bonk.erl +++ b/lib/gs/contribs/bonk/bonk.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -33,10 +33,10 @@ run() -> run([ColorMode]) -> % This is for the start script... run(ColorMode); -run(ColorMode) when atom(ColorMode) -> +run(ColorMode) when is_atom(ColorMode) -> GS = gs:start(), - SoundPid=spawn_link(bonk_sound,start,[]), - {H,M,S}=time(), + SoundPid = spawn_link(bonk_sound,start,[]), + {H,M,S} = time(), random:seed(H*13,M*7,S*3), {SqrPids, Bmps, Colors} = create_board(GS, ColorMode), {ScoreL,_File} = get_highscore(), @@ -96,7 +96,7 @@ init(SoundPid, SqrPids, Bmps, Colors) -> game(SoundPid, SqrPids, Bmps, Colors, Scores) -> receive - {gs, _Square, buttonpress, SqrPid, [1 | _Rest]} when pid(SqrPid) -> + {gs, _Square, buttonpress, SqrPid, [1 | _Rest]} when is_pid(SqrPid) -> SqrPid ! bonk, game(SoundPid, SqrPids, Bmps, Colors, Scores); {gs, _Id, buttonpress, _Data, [Butt | _Rest]} when Butt =/= 1 -> @@ -224,11 +224,9 @@ update_score(SoundPid, SqrPids, Scores) -> send_to_all([], _Msg) -> true; - -send_to_all([Pid|Rest],Msg) when pid(Pid) -> +send_to_all([Pid|Rest],Msg) when is_pid(Pid) -> Pid ! Msg, send_to_all(Rest,Msg); - send_to_all([_Else|Rest],Msg) -> send_to_all(Rest,Msg). @@ -460,7 +458,7 @@ update_scorelist(SoundPid, Scores) -> {ScoreL,FileName} = get_highscore(), New_scorelist=update_scorelist_2(ScoreL, Score, 0, SoundPid), display_highscore(New_scorelist), - case file:open(FileName, write) of + case file:open(FileName, [write]) of {error,_} -> true; {ok,FD} -> @@ -559,7 +557,7 @@ display_about() -> {activebg, BGColor}]), gs:create(text, aboutText, aboutCan, [{width, Wid-30}, {coords, [{15, 0}]}, {fg, TextColor}, {justify, center}]), - case file:open(lists:append(bonk_dir(),"bonk.txt"), read) of + case file:open(lists:append(bonk_dir(),"bonk.txt"), [read]) of {ok, Fd} -> write_text(Fd, "", io:get_line(Fd, "")), file:close(Fd); diff --git a/lib/gs/contribs/othello/othello_adt.erl b/lib/gs/contribs/othello/othello_adt.erl index d1d3ec950b..fb60c30b89 100644 --- a/lib/gs/contribs/othello/othello_adt.erl +++ b/lib/gs/contribs/othello/othello_adt.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -375,29 +375,29 @@ is_good(Colour,H,Board) -> false. is_good_0(_,_,false,_) -> false; -is_good_0(_,H,D,_) when integer(H), integer(D), H+D<0 -> false; -is_good_0(_,H,D,_) when integer(H), integer(D), H+D>63 -> false; -is_good_0(black,H,D,Board) when integer(H), integer(D) -> +is_good_0(_,H,D,_) when is_integer(H), is_integer(D), H+D<0 -> false; +is_good_0(_,H,D,_) when is_integer(H), is_integer(D), H+D>63 -> false; +is_good_0(black,H,D,Board) when is_integer(H), is_integer(D) -> case element((H+D)+1,Board) of white -> is_good_1(black,H+D,dir(H+D,D),Board); _ -> false end; -is_good_0(white,H,D,Board) when integer(H), integer(D) -> +is_good_0(white,H,D,Board) when is_integer(H), is_integer(D) -> case element((H+D)+1,Board) of black -> is_good_1(white,H+D,dir(H+D,D),Board); _ -> false end. is_good_1(_,_,false,_) -> false; -is_good_1(_,H,D,_) when integer(H), integer(D), H+D<0 -> false; -is_good_1(_,H,D,_) when integer(H), integer(D), H+D>63 -> false; -is_good_1(black,H,D,Board) when integer(H), integer(D) -> +is_good_1(_,H,D,_) when is_integer(H), is_integer(D), H+D<0 -> false; +is_good_1(_,H,D,_) when is_integer(H), is_integer(D), H+D>63 -> false; +is_good_1(black,H,D,Board) when is_integer(H), is_integer(D) -> case element((H+D)+1,Board) of white -> is_good_1(black,H+D,dir(H+D,D),Board); black -> throw(true); _ -> false end; -is_good_1(white,H,D,Board) when integer(H), integer(D) -> +is_good_1(white,H,D,Board) when is_integer(H), is_integer(D) -> case element((H+D)+1,Board) of black -> is_good_1(white,H+D,dir(H+D,D),Board); white -> throw(true); @@ -429,15 +429,15 @@ turn(Colour,H,D,Board) -> Board end. -turn_0(_,H,D,B) when integer(H), integer(D), H+D<0 -> B; -turn_0(_,H,D,B) when integer(H), integer(D), H+D>63 -> B; -turn_0(black,H,D,Board) when integer(H), integer(D) -> +turn_0(_,H,D,B) when is_integer(H), is_integer(D), H+D<0 -> B; +turn_0(_,H,D,B) when is_integer(H), is_integer(D), H+D>63 -> B; +turn_0(black,H,D,Board) when is_integer(H), is_integer(D) -> E = H+D, case element(E+1,Board) of white -> turn_0(black,H+D,D,swap(black,E,Board)); _ -> Board end; -turn_0(white,H,D,Board) when integer(H), integer(D) -> +turn_0(white,H,D,Board) when is_integer(H), is_integer(D) -> E = H+D, case element(E+1,Board) of black -> turn_0(white,H+D,D,swap(white,E,Board)); @@ -450,7 +450,7 @@ turn_0(white,H,D,Board) when integer(H), integer(D) -> %% Neighbours are not changed !! %%------------------------------------------------------- -swap(Colour,Pos,Board) when integer(Pos) -> +swap(Colour,Pos,Board) when is_integer(Pos) -> setelement(Pos+1,Board,Colour). score(Pos) -> score1({col(Pos),row(Pos)}). diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml index 7430a62b1b..9c8df28fec 100644 --- a/lib/inets/doc/src/httpc.xml +++ b/lib/inets/doc/src/httpc.xml @@ -167,6 +167,8 @@ ssl_options() = {verify, code()} | <v>http_option() = {timeout, timeout()} | {connect_timeout, timeout()} | {ssl, ssl_options()} | + {ossl, ssl_options()} | + {essl, ssl_options()} | {autoredirect, boolean()} | {proxy_auth, {userstring(), passwordstring()}} | {version, http_version()} | @@ -222,7 +224,22 @@ ssl_options() = {verify, code()} | <tag><c><![CDATA[ssl]]></c></tag> <item> - <p>If using SSL, these SSL-specific options are used. </p> + <p>This is the default ssl config option, currently defaults to + <c>ossl</c>, see below. </p> + <p>Defaults to <c>[]</c>. </p> + </item> + + <tag><c><![CDATA[ossl]]></c></tag> + <item> + <p>If using the OpenSSL based (old) implementation of SSL, + these SSL-specific options are used. </p> + <p>Defaults to <c>[]</c>. </p> + </item> + + <tag><c><![CDATA[essl]]></c></tag> + <item> + <p>If using the Erlang based (new) implementation of SSL, + these SSL-specific options are used. </p> <p>Defaults to <c>[]</c>. </p> </item> diff --git a/lib/inets/doc/src/httpd.xml b/lib/inets/doc/src/httpd.xml index 7dabeb33e9..847605fe93 100644 --- a/lib/inets/doc/src/httpd.xml +++ b/lib/inets/doc/src/httpd.xml @@ -148,8 +148,13 @@ in the apache like configuration file. </item> - <tag>{socket_type, ip_comm | ssl}</tag> + <tag>{socket_type, ip_comm | ssl | ossl | essl}</tag> <item> + <p>When using ssl, there are several alternatives. + <c>ossl</c> specifically uses the OpenSSL based (old) SSL. + <c>essl</c> specifically uses the Erlang based (new) SSL. + When using <c>ssl</c> it <em>currently</em> defaults to + <c>ossl</c>. </p> <p>Defaults to <c>ip_comm</c>. </p> </item> @@ -267,18 +272,22 @@ text/plain asc txt The <c>common</c> format is one line that looks like this: <c>remotehost rfc931 authuser [date] "request" status bytes</c></p> - <pre>remotehost + <pre> +remotehost Remote rfc931 The client's remote username (RFC 931). authuser - The username with which the user authenticated himself. + The username with which the user authenticated + himself. [date] Date and time of the request (RFC 1123). "request" - The request line exactly as it came from the client(RFC 1945). + The request line exactly as it came from the client + (RFC 1945). status - The HTTP status code returned to the client (RFC 1945). + The HTTP status code returned to the client + (RFC 1945). bytes The content-length of the document transferred. </pre> @@ -286,10 +295,11 @@ bytes <p>The <c>combined</c> format is on line that look like this: <c>remotehost rfc931 authuser [date] "request" status bytes "referer" "user_agent" </c></p> - <pre>"referer" + <pre> +"referer" The url the client was on before - requesting your url. (If it could not be determined a minus - sign will be placed in this field) + requesting your url. (If it could not be determined + a minus sign will be placed in this field) "user_agent" The software the client claims to be using. (If it could not be determined a minus sign will be placed in @@ -389,6 +399,31 @@ bytes and an access to http://your.server.org/image/foo.gif would refer to the file /ftp/pub/image/foo.gif.</item> + <tag>{re_write, {Re, Replacement}}</tag> + + <item> Where Re = string() and Replacement = string(). + The ReWrite property allows documents to be stored in the local file + system instead of the document_root location. URLs are rewritten + by re:replace/3 to produce a path in the local filesystem. + For example: + + <code>{re_write, {"^/[~]([^/]+)(.*)$", "/home/\\1/public\\2"}</code> + + and an access to http://your.server.org/~bob/foo.gif would refer to + the file /home/bob/public/foo.gif. + + In an Apache like configuration file the Re is separated + from Replacement with one single space, and as expected + backslashes do not need to be backslash escaped so the + same example would become: + + <code>ReWrite ^/[~]([^/]+)(.*)$ /home/\1/public\2</code> + + Beware of trailing space in Replacement that will be used. + If you must have a space in Re use e.g the character encoding + <code>\040</code> see <seealso marker="re">re(3)</seealso>. + </item> + <tag>{directory_index, [string()]}</tag> <item> @@ -408,7 +443,7 @@ bytes </taglist> <marker id="cgi_prop"></marker> - <p><em>CGI properties - requires mod_cgi</em></p> + <p><em>CGI properties - requires mod_cgi</em></p> <taglist> <tag>{script_alias, {Alias, RealName}}</tag> <item> Where Alias = string() and RealName = string(). @@ -423,6 +458,19 @@ bytes the server to run the script /web/cgi-bin/foo. </item> + <tag>{script_re_write, {Re, Replacement}}</tag> + <item> Where Re = string() and Replacement = string(). + Has the same behavior as the ReWrite property, except that + it also marks the target directory as containing CGI + scripts. URLs with a path beginning with url-path are mapped to + scripts beginning with directory-filename, for example: + + <code> {script_re_write, {"^/cgi-bin/(\\d+)/", "/web/\\1/cgi-bin/"}</code> + + and an access to http://your.server.org/cgi-bin/17/foo would cause + the server to run the script /web/17/cgi-bin/foo. + </item> + <tag>{script_nocache, boolean()}</tag> <item> diff --git a/lib/inets/doc/src/mod_esi.xml b/lib/inets/doc/src/mod_esi.xml index 6bad77dc0a..3c473d3f94 100644 --- a/lib/inets/doc/src/mod_esi.xml +++ b/lib/inets/doc/src/mod_esi.xml @@ -73,7 +73,8 @@ <v>SessionID = term()</v> <v>Env = [EnvironmentDirectives] ++ ParsedHeader</v> <v>EnvironmentDirectives = {Key,Value}</v> - <v>Key = query_string | content_length | server_software | gateway_interface | server_protocol | server_port | request_method | remote_addr | script_name. <v>Input = string()</v> + <v>Key = query_string | content_length | server_software | gateway_interface | server_protocol | server_port | request_method | remote_addr | script_name</v> + <v>Input = string()</v> </type> <desc> <p>The <c>Module</c> must be found in the code path and export diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml index fed42291ab..23ad5c0df0 100644 --- a/lib/inets/doc/src/notes.xml +++ b/lib/inets/doc/src/notes.xml @@ -32,6 +32,67 @@ <file>notes.xml</file> </header> + <section><title>Inets 5.4</title> + + <section><title>Improvements and New Features</title> +<!-- + <p>-</p> +--> + + <list> + <item> + <p>[httpc|httpd] - Now allow the use of the "new" ssl, by using + the <c>essl</c> tag instead. </p> + <p>See the <c>http_option</c> option in the + <seealso marker="httpc#request2">request/4,5</seealso> or + the <seealso marker="httpd#comm_prop">socket-type</seealso> + section of the Communication properties chapter for more info, </p> + <p>Own Id: OTP-7907</p> + </item> + + <item> + <p>Deprecated functions designated to be removed in R14 has been + removed. Also, some new functions has been marked as deprecated + (the old http client api module). </p> + <p>Own Id: OTP-8564</p> + <p>*** POTENTIAL INCOMPATIBILITY ***</p> + </item> + + <item> + <p>[httpd] - Improved mod_alias. + Now able to do better URL rewrites. </p> + <p>See + <seealso marker="httpd#alias_prop">URL aliasing properties</seealso> + and the + <seealso marker="httpd#cgi_prop">CGI properties</seealso> + section(s) for more info, </p> + <p>Own Id: OTP-8573</p> + </item> + + </list> + </section> + + <section><title>Fixed Bugs and Malfunctions</title> + + <p>-</p> + +<!-- + <list> + <item> + <p>[httpd] The server did not fully support the documented module + callback api. Specifically, the load function should be able to + return the atom <c>ok</c>, but this was not accepted. </p> + <p>Own Id: OTP-8359</p> + </item> + + </list> +--> + + </section> + + </section> <!-- 5.4 --> + + <section><title>Inets 5.3.3</title> <section><title>Improvements and New Features</title> @@ -304,6 +365,7 @@ <p>Own Id: OTP-8016</p> <p>*** POTENTIAL INCOMPATIBILITY ***</p> </item> + </list> </section> diff --git a/lib/inets/examples/Makefile b/lib/inets/examples/Makefile index a42b0e38b6..775c449062 100644 --- a/lib/inets/examples/Makefile +++ b/lib/inets/examples/Makefile @@ -1,19 +1,19 @@ # # %CopyrightBegin% -# -# Copyright Ericsson AB 1997-2009. All Rights Reserved. -# +# +# Copyright Ericsson AB 2010. All Rights Reserved. +# # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in # compliance with the License. You should have received a copy of the # Erlang Public License along with this software. If not, it can be # retrieved online at http://www.erlang.org/. -# +# # Software distributed under the License is distributed on an "AS IS" # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See # the License for the specific language governing rights and limitations # under the License. -# +# # %CopyrightEnd% # # @@ -21,189 +21,15 @@ include $(ERL_TOP)/make/target.mk include $(ERL_TOP)/make/$(TARGET)/otp.mk # ---------------------------------------------------- -# Application version -# ---------------------------------------------------- -include ../vsn.mk -VSN=$(INETS_VSN) - -# ---------------------------------------------------- -# Release directory specification -# ---------------------------------------------------- -RELSYSDIR = $(RELEASE_PATH)/lib/inets-$(VSN) - -# ---------------------------------------------------- -# Target Specs +# Common Macros # ---------------------------------------------------- -MODULE= -AUTH_FILES = server_root/auth/group \ - server_root/auth/passwd -CGI_FILES = server_root/cgi-bin/printenv.sh -CONF_FILES = server_root/conf/8080.conf \ - server_root/conf/8888.conf \ - server_root/conf/httpd.conf \ - server_root/conf/ssl.conf \ - server_root/conf/mime.types -OPEN_FILES = server_root/htdocs/open/dummy.html -MNESIA_OPEN_FILES = server_root/htdocs/mnesia_open/dummy.html -MISC_FILES = server_root/htdocs/misc/friedrich.html \ - server_root/htdocs/misc/oech.html -SECRET_FILES = server_root/htdocs/secret/dummy.html -MNESIA_SECRET_FILES = server_root/htdocs/mnesia_secret/dummy.html -HTDOCS_FILES = server_root/htdocs/index.html \ - server_root/htdocs/config.shtml \ - server_root/htdocs/echo.shtml \ - server_root/htdocs/exec.shtml \ - server_root/htdocs/flastmod.shtml \ - server_root/htdocs/fsize.shtml \ - server_root/htdocs/include.shtml -ICON_FILES = server_root/icons/README \ - server_root/icons/a.gif \ - server_root/icons/alert.black.gif \ - server_root/icons/alert.red.gif \ - server_root/icons/apache_pb.gif \ - server_root/icons/back.gif \ - server_root/icons/ball.gray.gif \ - server_root/icons/ball.red.gif \ - server_root/icons/binary.gif \ - server_root/icons/binhex.gif \ - server_root/icons/blank.gif \ - server_root/icons/bomb.gif \ - server_root/icons/box1.gif \ - server_root/icons/box2.gif \ - server_root/icons/broken.gif \ - server_root/icons/burst.gif \ - server_root/icons/button1.gif \ - server_root/icons/button10.gif \ - server_root/icons/button2.gif \ - server_root/icons/button3.gif \ - server_root/icons/button4.gif \ - server_root/icons/button5.gif \ - server_root/icons/button6.gif \ - server_root/icons/button7.gif \ - server_root/icons/button8.gif \ - server_root/icons/button9.gif \ - server_root/icons/buttonl.gif \ - server_root/icons/buttonr.gif \ - server_root/icons/c.gif \ - server_root/icons/comp.blue.gif \ - server_root/icons/comp.gray.gif \ - server_root/icons/compressed.gif \ - server_root/icons/continued.gif \ - server_root/icons/dir.gif \ - server_root/icons/down.gif \ - server_root/icons/dvi.gif \ - server_root/icons/f.gif \ - server_root/icons/folder.gif \ - server_root/icons/folder.open.gif \ - server_root/icons/folder.sec.gif \ - server_root/icons/forward.gif \ - server_root/icons/generic.gif \ - server_root/icons/generic.red.gif \ - server_root/icons/generic.sec.gif \ - server_root/icons/hand.right.gif \ - server_root/icons/hand.up.gif \ - server_root/icons/htdig.gif \ - server_root/icons/icon.sheet.gif \ - server_root/icons/image1.gif \ - server_root/icons/image2.gif \ - server_root/icons/image3.gif \ - server_root/icons/index.gif \ - server_root/icons/layout.gif \ - server_root/icons/left.gif \ - server_root/icons/link.gif \ - server_root/icons/movie.gif \ - server_root/icons/p.gif \ - server_root/icons/patch.gif \ - server_root/icons/pdf.gif \ - server_root/icons/pie0.gif \ - server_root/icons/pie1.gif \ - server_root/icons/pie2.gif \ - server_root/icons/pie3.gif \ - server_root/icons/pie4.gif \ - server_root/icons/pie5.gif \ - server_root/icons/pie6.gif \ - server_root/icons/pie7.gif \ - server_root/icons/pie8.gif \ - server_root/icons/portal.gif \ - server_root/icons/poweredby.gif \ - server_root/icons/ps.gif \ - server_root/icons/quill.gif \ - server_root/icons/right.gif \ - server_root/icons/screw1.gif \ - server_root/icons/screw2.gif \ - server_root/icons/script.gif \ - server_root/icons/sound1.gif \ - server_root/icons/sound2.gif \ - server_root/icons/sphere1.gif \ - server_root/icons/sphere2.gif \ - server_root/icons/star.gif \ - server_root/icons/star_blank.gif \ - server_root/icons/tar.gif \ - server_root/icons/tex.gif \ - server_root/icons/text.gif \ - server_root/icons/transfer.gif \ - server_root/icons/unknown.gif \ - server_root/icons/up.gif \ - server_root/icons/uu.gif \ - server_root/icons/uuencoded.gif \ - server_root/icons/world1.gif \ - server_root/icons/world2.gif +include subdirs.mk -SSL_FILES = server_root/ssl/ssl_client.pem \ - server_root/ssl/ssl_server.pem +SPECIAL_TARGETS = # ---------------------------------------------------- -# FLAGS +# Default Subdir Targets # ---------------------------------------------------- -ERL_COMPILE_FLAGS += - -# ---------------------------------------------------- -# Targets -# ---------------------------------------------------- - -debug opt: - -clean: - -docs: - -# ---------------------------------------------------- -# Release Target -# ---------------------------------------------------- -include $(ERL_TOP)/make/otp_release_targets.mk - -release_spec: opt - $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/auth - $(INSTALL_DATA) $(AUTH_FILES) $(RELSYSDIR)/examples/server_root/auth - $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/cgi-bin - $(INSTALL_SCRIPT) $(CGI_FILES) $(RELSYSDIR)/examples/server_root/cgi-bin - $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/conf - $(INSTALL_DATA) $(CONF_FILES) $(RELSYSDIR)/examples/server_root/conf - $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/htdocs/open - $(INSTALL_DATA) $(OPEN_FILES) \ - $(RELSYSDIR)/examples/server_root/htdocs/open - $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/htdocs/mnesia_open - $(INSTALL_DATA) $(MNESIA_OPEN_FILES) \ - $(RELSYSDIR)/examples/server_root/htdocs/mnesia_open - $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/htdocs/misc - $(INSTALL_DATA) $(MISC_FILES) \ - $(RELSYSDIR)/examples/server_root/htdocs/misc - $(INSTALL_DIR) \ - $(RELSYSDIR)/examples/server_root/htdocs/secret/top_secret - $(INSTALL_DIR) \ - $(RELSYSDIR)/examples/server_root/htdocs/mnesia_secret/top_secret - $(INSTALL_DATA) $(SECRET_FILES) \ - $(RELSYSDIR)/examples/server_root/htdocs/secret - $(INSTALL_DATA) $(MNESIA_SECRET_FILES) \ - $(RELSYSDIR)/examples/server_root/htdocs/mnesia_secret - $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/htdocs - $(INSTALL_DATA) $(HTDOCS_FILES) $(RELSYSDIR)/examples/server_root/htdocs - $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/icons - $(INSTALL_DATA) $(ICON_FILES) $(RELSYSDIR)/examples/server_root/icons - $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/ssl - $(INSTALL_DATA) $(SSL_FILES) $(RELSYSDIR)/examples/server_root/ssl - $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/logs - -release_docs_spec: +include $(ERL_TOP)/make/otp_subdir.mk diff --git a/lib/inets/examples/httpd_load_test/Makefile b/lib/inets/examples/httpd_load_test/Makefile new file mode 100644 index 0000000000..1cc61ad8ae --- /dev/null +++ b/lib/inets/examples/httpd_load_test/Makefile @@ -0,0 +1,123 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + +include $(ERL_TOP)/make/target.mk + +EBIN = . + +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk + +VSN=$(INETS_VSN) + + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/inets-$(VSN) +EXAMPLE_RELSYSDIR = $(RELSYSDIR)/examples +HDLT_RELSYSDIR = $(EXAMPLE_RELSYSDIR)/httpd_load_test + + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +include modules.mk + +ERL_FILES = $(MODULES:%=%.erl) + +SOURCE = $(ERL_FILES) $(INTERNAL_HRL_FILES) + +TARGET_FILES = \ + $(ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) + +ifeq ($(TYPE),debug) +ERL_COMPILE_FLAGS += -Ddebug -W +endif + + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- + +include ../../src/inets_app/inets.mk + +ERL_COMPILE_FLAGS += \ + $(INETS_FLAGS) \ + $(INETS_ERL_COMPILE_FLAGS) \ + -I../../include + + +# ---------------------------------------------------- +# Special Build Targets +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +debug: + @${MAKE} TYPE=debug opt + +opt: $(TARGET_FILES) + +clean: + rm -f $(TARGET_FILES) + rm -f errs core *~ + +docs: + + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + + +release_spec: opt + $(INSTALL_DIR) $(EXAMPLE_RELSYSDIR) + $(INSTALL_DIR) $(HDLT_RELSYSDIR) + $(INSTALL_DATA) $(SCRIPT_SKELETONS) $(HDLT_RELSYSDIR) + $(INSTALL_DATA) $(CONF_SKELETONS) $(HDLT_RELSYSDIR) + $(INSTALL_DATA) $(CERT_FILES) $(HDLT_RELSYSDIR) + $(INSTALL_DATA) $(TARGET_FILES) $(HDLT_RELSYSDIR) + $(INSTALL_DATA) $(ERL_FILES) $(HDLT_RELSYSDIR) + + +release_docs_spec: + + +# ---------------------------------------------------- +# Include dependencies +# ---------------------------------------------------- + +megaco_codec_transform.$(EMULATOR): megaco_codec_transform.erl + +megaco_codec_meas.$(EMULATOR): megaco_codec_meas.erl + +megaco_codec_mstone1.$(EMULATOR): megaco_codec_mstone1.erl + +megaco_codec_mstone2.$(EMULATOR): megaco_codec_mstone2.erl + +megaco_codec_mstone_lib.$(EMULATOR): megaco_codec_mstone_lib.erl + diff --git a/lib/inets/examples/httpd_load_test/hdlt.config.skel b/lib/inets/examples/httpd_load_test/hdlt.config.skel new file mode 100644 index 0000000000..640867ebac --- /dev/null +++ b/lib/inets/examples/httpd_load_test/hdlt.config.skel @@ -0,0 +1,20 @@ +%% Debug: silence | info | log | debug +{debug, [{ctrl, info}, {proxy, silence}, {slave, silence}, {client, silence}]}. +{server, {"/usr/local/bin", "fooserver"}}. +%% {port, 8888}. % integer() > 0 +{server_dir, "/tmp/hdlt"}. % Absolute path +{work_dir, "/tmp/hdlt"}. % Absolute path +{clients, + [ + {"/opt/local/bin", "foo"}, + {"/usr/local/bin", "bar"} + ] +}. +%% {send_rate, 80}. % Max number of outstanding requests, integer() > 0 +%% {test_time, 120}. % Number of seconds, +%% {max_nof_schedulers, 8}. % integer() >= 0 +%% {work_simulator, 10000}. % integer() > 0 +%% {data_size, {100, 500, 2}}. % {integer() > 0, integer() > 0, integer() > 0} +%% {socket_type, ip_comm}. % ip_comm | ssl | essl | ossl +%% {server_cert_file, "hdlt_ssl_server_cert.pem"}. +%% {client_cert_file, "hdlt_ssl_client_cert.pem"}.
\ No newline at end of file diff --git a/lib/inets/examples/httpd_load_test/hdlt.erl b/lib/inets/examples/httpd_load_test/hdlt.erl new file mode 100644 index 0000000000..18d8c34ccf --- /dev/null +++ b/lib/inets/examples/httpd_load_test/hdlt.erl @@ -0,0 +1,74 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% Purpose: Main API module for the httpd load test utility +%%---------------------------------------------------------------------- + +-module(hdlt). + + +%%----------------------------------------------------------------- +%% Public interface +%%----------------------------------------------------------------- + +-export([start/0, start/1, stop/0, help/0]). + + +%%----------------------------------------------------------------- +%% Start the HDLT utility +%%----------------------------------------------------------------- + +start() -> + ConfigFile = "hdlt.config", + case file:consult(ConfigFile) of + {ok, Config} when is_list(Config) -> + start(Config); + Error -> + Error + end. + +start(Config) -> + Flag = process_flag(trap_exit, true), + Result = + case hdlt_ctrl:start(Config) of + {ok, Pid} -> + receive + {'EXIT', Pid, normal} -> + ok; + {'EXIT', Pid, Reason} -> + io:format("HDLT failed: " + "~n ~p" + "~n", [Reason]), + {error, Reason} + end; + Error -> + Error + end, + process_flag(trap_exit, Flag), + Result. + + + +stop() -> + hdlt_ctrl:stop(). + + +help() -> + hdlt_ctrl:help(). diff --git a/lib/inets/examples/httpd_load_test/hdlt.sh.skel b/lib/inets/examples/httpd_load_test/hdlt.sh.skel new file mode 100644 index 0000000000..a250bad9c5 --- /dev/null +++ b/lib/inets/examples/httpd_load_test/hdlt.sh.skel @@ -0,0 +1,44 @@ +#!/bin/sh + +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + +# Skeleton for a script intended to run the hdlt(N) +# performance test. +# +# This test can be used for several things depending on the +# configuration: SMP or SocketType performance tests +# + +ERL_HOME=<path to otp top dir> +INETS_HOME=$ERL_HOME/lib/erlang/lib/<inets dir> +HDLT_HOME=$INETS_HOME/examples/httpd_load_test +PATH=$ERL_HOME/bin:$PATH + +HDLT="-s hdlt start" +STOP="-s init stop" + +ERL="erl \ + -noshell \ + -pa $HDLT_HOME \ + $HDLT \ + $STOP" + +echo $ERL +$ERL | tee hdlt.log + diff --git a/lib/inets/examples/httpd_load_test/hdlt_client.erl b/lib/inets/examples/httpd_load_test/hdlt_client.erl new file mode 100644 index 0000000000..d65ac5a885 --- /dev/null +++ b/lib/inets/examples/httpd_load_test/hdlt_client.erl @@ -0,0 +1,370 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% Purpose: The HDLT client module. +%% This is the traffic generator +%%---------------------------------------------------------------------- + +-module(hdlt_client). + +-export([ + start/1, + stop/0, + start_inets/0, + start_service/1, + release/0, + node_info/0 + ]). + +-export([ + proxy/1 + ]). + +-include("hdlt_logger.hrl"). + +-define(CTRL, hdlt_ctrl). +-define(PROXY, hdlt_proxy). + +-record(state, + { + mode = initial, + send_rate, + time, + stop_time, + url, + nof_reqs = 0, + nof_reps = 0, + last_req, + sizes, + socket_type, + cert_file + }). + + + +start(Debug) -> + proc_lib:start_link(?MODULE, proxy, [Debug]). + +stop() -> + (catch erlang:send(?PROXY, stop)), + ok. + +start_inets() -> + ?PROXY ! start_inets. + +start_service(Args) -> + ?PROXY ! {start_client, Args, self()}, + receive + client_started -> + %% ?LOG("client service started"), + ok + end. + +release() -> + ?PROXY ! release. + +node_info() -> + ?PROXY ! {node_info, self()}, + receive + {node_info, NodeInfo} -> + NodeInfo + end. + + +%% --------------------------------------------------------------------- +%% +%% The proxy process +%% + +proxy(Debug) -> + process_flag(trap_exit, true), + erlang:register(?PROXY, self()), + SName = lists:flatten( + io_lib:format("HDLT PROXY[~p,~p]", [self(), node()])), + ?SET_NAME(SName), + ?SET_LEVEL(Debug), + ?LOG("starting", []), + Ref = await_for_controller(10), + CtrlNode = node(Ref), + erlang:monitor_node(CtrlNode, true), + proc_lib:init_ack({ok, self()}), + ?DEBUG("started", []), + proxy_loop(Ref, CtrlNode, undefined). + +await_for_controller(N) when N > 0 -> + case global:whereis_name(hdlt_ctrl) of + Pid when is_pid(Pid) -> + erlang:monitor(process, Pid); + _ -> + timer:sleep(1000), + await_for_controller(N-1) + end; +await_for_controller(_) -> + proc_lib:init_ack({error, controller_not_found, nodes()}), + timer:sleep(500), + init:stop(). + + +proxy_loop(Ref, CtrlNode, Client) -> + ?DEBUG("await command", []), + receive + stop -> + ?LOG("stop", []), + timer:sleep(1000), + halt(); + + start_inets -> + ?LOG("start the inets service framework", []), + %% inets:enable_trace(max, "/tmp/inets-httpc-trace.log", all), + case (catch inets:start()) of + ok -> + ?LOG("framework started", []), + proxy_loop(Ref, CtrlNode, Client); + Error -> + ?LOG("failed starting inets service framework: " + "~n Error: ~p", [Error]), + timer:sleep(1000), + halt() + end; + + {start_client, Args, From} -> + ?LOG("start client with" + "~n Args: ~p", [Args]), + Client2 = spawn_link(fun() -> client(Args) end), + From ! client_started, + proxy_loop(Ref, CtrlNode, Client2); + + release -> + ?LOG("release", []), + Client ! go, + proxy_loop(Ref, CtrlNode, Client); + + {node_info, Pid} -> + ?LOG("received requets for node info", []), + NodeInfo = get_node_info(), + Pid ! {node_info, NodeInfo}, + proxy_loop(Ref, CtrlNode, Client); + + {'EXIT', Client, normal} -> + ?LOG("received normal exit message from client (~p)", + [Client]), + exit(normal); + + {'EXIT', Client, Reason} -> + ?INFO("received exit message from client (~p)" + "~n Reason: ~p", [Client, Reason]), + %% Unexpected client termination, inform the controller and die + global:send(hdlt_ctrl, {client_exit, Client, node(), Reason}), + exit({client_exit, Reason}); + + {nodedown, CtrlNode} -> + ?LOG("received nodedown for controller node - terminate", []), + halt(); + + {'DOWN', Ref, process, _, _} -> + ?INFO("received DOWN message for controller - terminate", []), + %% The controller has terminated, dont care why, time to die + halt() + + end. + + + +%% --------------------------------------------------------------------- +%% +%% The client process +%% + +client([SocketType, CertFile, URLBase, Sizes, Time, SendRate, Debug]) -> + SName = lists:flatten( + io_lib:format("HDLT CLIENT[~p,~p]", [self(), node()])), + ?SET_NAME(SName), + ?SET_LEVEL(Debug), + ?LOG("starting with" + "~n SocketType: ~p" + "~n Time: ~p" + "~n SendRate: ~p", [SocketType, Time, SendRate]), + httpc:set_options([{max_pipeline_length, 0}]), + if + (SocketType =:= ssl) orelse + (SocketType =:= ossl) orelse + (SocketType =:= essl) -> + %% Ensure crypto and ssl started: + crypto:start(), + ssl:start(); + true -> + ok + end, + State = #state{mode = idle, + url = URLBase, + time = Time, + send_rate = SendRate, + sizes = Sizes, + socket_type = SocketType, + cert_file = CertFile}, + ?DEBUG("started", []), + client_loop(State). + +%% The point is to first start all client nodes and then this +%% process. Then, when they are all started, the go-ahead, go, +%% message is sent to let them lose at the same time. +client_loop(#state{mode = idle, + time = Time, + send_rate = SendRate} = State) -> + ?DEBUG("[idle] awaiting the go command", []), + receive + go -> + ?LOG("[idle] received go", []), + erlang:send_after(Time, self(), stop), + NewState = send_requests(State, SendRate), + client_loop(NewState#state{mode = generating, + nof_reqs = SendRate}) + end; + +%% In this mode the client is generating traffic. +%% It will continue to do so until the stop message +%% is received. +client_loop(#state{mode = generating} = State) -> + receive + stop -> + ?LOG("[generating] received stop", []), + StopTime = timestamp(), + req_reply(State), + client_loop(State#state{mode = stopping, stop_time = StopTime}); + + {http, {_, {{_, 200, _}, _, _}}} -> + %% ?DEBUG("[generating] received reply - send another request", []), + NewState = send_requests(State, 1), + client_loop(NewState#state{nof_reps = NewState#state.nof_reps + 1, + nof_reqs = NewState#state.nof_reqs + 1}); + + {http, {ReqId, {error, Reason}}} -> + ?INFO("[generating] request ~p failed: " + "~n Reason: ~p" + "~n NofReqs: ~p" + "~n NofReps: ~p", + [ReqId, Reason, State#state.nof_reqs, State#state.nof_reps]), + exit({Reason, generating, State#state.nof_reqs, State#state.nof_reps}); + + Else -> + ?LOG("[generating] received unexpected message: " + "~n~p", [Else]), + unexpected_data(Else), + client_loop(State) + end; + +%% The client no longer issues any new requests, instead it +%% waits for replies for all the oustanding requests to +%% arrive. +client_loop(#state{mode = stopping, + time = Time, + last_req = LastReqId} = State) -> + receive + {http, {LastReqId, {{_, 200, _}, _, _}}} -> + ?DEBUG("[stopping] received reply for last request (~p)", [LastReqId]), + time_to_complete(State), + ok; + + {http, {ReqId, {{_, 200, _}, _, _}}} -> + ?DEBUG("[stopping] received reply ~p", [ReqId]), + client_loop(State); + + {http, {ReqId, {error, Reason}}} -> + ?INFO("[stopping] request ~p failed: " + "~n Reason: ~p" + "~n NofReqs: ~p" + "~n NofReps: ~p", + [ReqId, Reason, State#state.nof_reqs, State#state.nof_reps]), + exit({Reason, stopping, State#state.nof_reqs, State#state.nof_reps}); + + Else -> + ?LOG("[stopping] received unexpected message: " + "~n~p", [Else]), + unexpected_data(Else), + client_loop(State) + + after Time -> + ?INFO("timeout when" + "~n Number of requests: ~p" + "~n Number of replies: ~p", + [State#state.nof_reqs, State#state.nof_reps]), + exit({timeout, State#state.nof_reqs, State#state.nof_reps}) + end. + +req_reply(#state{nof_reqs = NofReqs, nof_reps = NofReps}) -> + load_data({req_reply, node(), NofReqs, NofReps}). + +time_to_complete(#state{stop_time = StopTime}) -> + StoppedTime = os:timestamp(), + load_data({time_to_complete, node(), StopTime, StoppedTime}). + +load_data(Data) -> + global:send(?CTRL, {load_data, Data}). + +unexpected_data(Else) -> + global:send(?CTRL, {unexpected_data, Else}). + + +send_requests(#state{sizes = Sizes} = State, N) -> + send_requests(State, N, Sizes). + +send_requests(State, 0, Sizes) -> + State#state{sizes = Sizes}; +send_requests(#state{socket_type = SocketType, + cert_file = CertFile} = State, N, [Sz | Sizes]) -> + URL = lists:flatten(io_lib:format("~s~w", [State#state.url, Sz])), + Method = get, + Request = {URL, []}, + HTTPOptions = + case SocketType of + ip_comm -> + []; + _ -> + SslOpts = [{verify, 0}, + {certfile, CertFile}, + {keyfile, CertFile}], + case SocketType of + ssl -> + [{ssl, SslOpts}]; + ossl -> + [{ssl, {ossl, SslOpts}}]; + essl -> + [{ssl, {essl, SslOpts}}] + end + end, + Options = [{sync, false}], + {ok, Ref} = httpc:request(Method, Request, HTTPOptions, Options), + send_requests(State#state{last_req = Ref}, N-1, lists:append(Sizes, [Sz])). + + +timestamp() -> + os:timestamp(). + + +get_node_info() -> + [{cpu_topology, erlang:system_info(cpu_topology)}, + {heap_type, erlang:system_info(heap_type)}, + {nof_schedulers, erlang:system_info(schedulers)}, + {otp_release, erlang:system_info(otp_release)}, + {version, erlang:system_info(version)}, + {system_version, erlang:system_info(system_version)}, + {system_architecture, erlang:system_info(system_architecture)}]. + + diff --git a/lib/inets/examples/httpd_load_test/hdlt_ctrl.erl b/lib/inets/examples/httpd_load_test/hdlt_ctrl.erl new file mode 100644 index 0000000000..950d2632f7 --- /dev/null +++ b/lib/inets/examples/httpd_load_test/hdlt_ctrl.erl @@ -0,0 +1,1530 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% Purpose: The httpd load test (hdlt) controller/collector module, +%% This module contains all the code of the httpd load test +%% controller/collector. It sets up the test, starts all +%% server and client nodes and applications and finally +%% collects test data. +%%---------------------------------------------------------------------- + +-module(hdlt_ctrl). + +-export([start/1, stop/0, help/0]). + +-export([init/1, proxy/7]). + +-include_lib("kernel/include/file.hrl"). +-include("hdlt_logger.hrl"). + +-define(DEFAULT_SENDRATE, 89). +-define(DEFAULT_TEST_TIME, 120). % 2 minutes +-define(DEFAULT_PORT, 8889). +-define(TIMEOUT, 60000). +-define(DEFAULT_MAX_NOF_SCHEDULERS, 8). +-define(DEFAULT_SERVER_DIR, "/tmp/hdlt"). +-define(DEFAULT_WORK_DIR, "/tmp/hdlt"). +-define(SSH_PORT, 22). +-define(DEFAULT_SOCKET_TYPE, ip_comm). +-define(DEFAULT_SERVER_CERT, "hdlt_ssl_server_cert.pem"). +-define(DEFAULT_CLIENT_CERT, "hdlt_ssl_client_cert.pem"). +-define(SSH_CONNECT_TIMEOUT, 5000). +-define(NODE_START_TIMEOUT, 5000). +-define(LOCAL_PROXY_START_TIMEOUT, ?NODE_START_TIMEOUT * 4). +-define(DEFAULT_DEBUGS, + [{ctrl, info}, {slave, silence}, {proxy, silence}, {client, silence}]). +-define(DEFAULT_WORK_SIM, 10000). +-define(DEFAULT_DATA_SIZE_START, 500). +-define(DEFAULT_DATA_SIZE_END, 1500). +-define(DEFAULT_DATA_SIZE_INCR, 1). +-define(DEFAULT_DATA_SIZE, {?DEFAULT_DATA_SIZE_START, + ?DEFAULT_DATA_SIZE_END, + ?DEFAULT_DATA_SIZE_INCR}). + + +%% hdlt = httpd load test + +-define(COLLECTOR, hdlt_ctrl). +-define(RESULTS_TAB, hdlt_results). + +-define(CLIENT_MOD, hdlt_client). +-define(CLIENT_NODE_NAME, ?CLIENT_MOD). + +-define(SERVER_MOD, hdlt_server). +-define(SERVER_NODE_NAME, ?SERVER_MOD). + +-define(LOGGER, hdlt_logger). + + +-record(state, + { + url, + test_time, + send_rate, + http_server, + http_port, + results = ?RESULTS_TAB, + nodes, + server_root, + doc_root, + server_dir, + work_dir, + server_conn, + client_conns = [], + client_mod = ?CLIENT_MOD, + clients, + nof_schedulers = 0, + max_nof_schedulers, + socket_type, + server_cert_file, + client_cert_file, + debugs, + client_sz_from, + client_sz_to, + client_sz_incr + } + ). + +-record(proxy, + { + mode, + mod, + connection, + channel, + host, + cmd, + node_name, + node, + ref, + erl_path, + paths, + args + }). + +-record(connection, + { + proxy, + node, + node_name, + host + }). + + +-record(client, {host, path, version}). +-record(server, {host, path, version}). + + +start(Config) when is_list(Config) -> + proc_lib:start_link(?MODULE, init, [Config]). + +stop() -> + global:send(?COLLECTOR, stop). + +init(Config) -> + %% io:format("Config: ~n~p~n", [Config]), + case (catch do_init(Config)) of + {ok, State} -> + proc_lib:init_ack({ok, self()}), + loop(State); + {error, _Reason} = Error -> + proc_lib:init_ack(Error), + ok; + {'EXIT', Reason} -> + proc_lib:init_ack({error, Reason}), + ok + end. + +do_init(Config) -> + %% Do not trap exit, but register ourself + global:register_name(?COLLECTOR, self()), + + State = #state{}, + ets:new(State#state.results, [bag, named_table]), + + hdlt_logger:start(), + global:sync(), + + %% Maybe enable debug + Debugs = get_debugs(Config), + ?SET_NAME("HDLT CTRL"), + set_debug_level(Debugs), + + ?DEBUG("network info: " + "~n Global names: ~p" + "~n Nodes: ~p", [global:registered_names(), nodes()]), + + %% Read config + ?LOG("read config", []), + SendRate = get_send_rate(Config), + Clients = get_clients(Config), + TestTime = get_test_time(Config), + Server = get_server(Config), + Port = get_port(Config), + ServerDir = get_server_dir(Config), + WorkingDir = get_work_dir(Config), + MaxNofSchedulers = get_max_nof_schedulers(Config), + SocketType = get_socket_type(Config), + ServerCertFile = get_server_cert_file(Config), + ClientCertFile = get_client_cert_file(Config), + WorkSim = get_work_sim(Config), + {From, To, Incr} = get_data_size(Config), + + URL = url(Server, Port, SocketType, WorkSim), + ServerRoot = filename:join(ServerDir, "server_root"), + DocRoot = ServerRoot, %% Not really used in this test + + ?DEBUG("randomize setup", []), + randomized_sizes_init(), + + %% Start used applications + ?DEBUG("ensure crypto started", []), + crypto:start(), + ?DEBUG("ensure ssh started", []), + ssh:start(), + + State2 = State#state{server_root = ServerRoot, + doc_root = DocRoot, + server_dir = ServerDir, + work_dir = WorkingDir, + max_nof_schedulers = MaxNofSchedulers, + socket_type = SocketType, + server_cert_file = ServerCertFile, + client_cert_file = ClientCertFile, + http_server = Server, + http_port = Port, + url = URL, + test_time = TestTime, + send_rate = SendRate, + clients = Clients, + debugs = Debugs, + client_sz_from = From, + client_sz_to = To, + client_sz_incr = Incr}, + + ?LOG("prepare server host", []), + prepare_server_host(State2), + + ?LOG("prepare client hosts", []), + State3 = prepare_client_hosts(State2), + + ?LOG("basic init done", []), + {ok, State3}. + + +loop(#state{nof_schedulers = N, max_nof_schedulers = M} = State) when N > M -> + + ?INFO("Starting to analyse data", []), + + AnalysedTab = analyse_data(State), + + Files = save_results_to_file(AnalysedTab, State), + io:format("~n******************************************************" + "~n~nResult(s) saved to: ~n~p~n", [Files]), + clean_up(State); + +loop(#state{url = URL, + test_time = TestTime, + send_rate = SendRate, + nof_schedulers = NofSchedulers} = State) -> + + {StartH, StartM, StartS} = erlang:time(), + + ?INFO("Performing test with ~p smp-scheduler(s): ~n" + " It will take a minimum of: ~p seconds. ~n" + " Start time: ~.2.0w:~.2.0w:~.2.0w", + [NofSchedulers, round(TestTime/1000), StartH, StartM, StartS]), + + %% Start the server node + %% (The local proxy, the node, the remote proxy, and the inets framework) + State1 = start_server_node(State), + ?DEBUG("nodes after server start: ~p", [nodes() -- [node()]]), + + %% Start the client node(s) + %% (The local proxy, the node, the remote proxy, and the inets framework) + ?LOG("start client node(s)", []), + State2 = start_client_nodes(State1), + ?DEBUG("nodes after client(s) start: ~p", [nodes() -- [node()]]), + + ?LOG("start server", []), + start_server(State2), + + ?LOG("start clients", []), + start_clients(State2, URL, TestTime, SendRate), + + ?LOG("release clients", []), + release_clients(State2), + + ?LOG("collect data", []), + collect_data(State2), + + ?LOG("stop all nodes", []), + State3 = stop_nodes(State2), + + ?INFO("Test with ~p smp-scheduler(s) complete" + "~n~n" + "****************************************************************" + "~n", + [NofSchedulers]), + loop(State3#state{nof_schedulers = NofSchedulers + 1}). + + +prepare_server_host(#state{server_root = ServerRoot, + http_server = #server{host = Host}, + socket_type = SocketType, + server_cert_file = CertFile}) -> + ?INFO("prepare server host ~s", [Host]), + Opts = [{user_interaction, false}, + {silently_accept_hosts, true}, + {timeout, 2*?SSH_CONNECT_TIMEOUT}, + {connect_timeout, ?SSH_CONNECT_TIMEOUT}], + case ssh_sftp:start_channel(Host, Opts) of + {ok, Sftp, ConnectionRef} -> + ?DEBUG("sftp connection established - now transer server content", + []), + create_server_content(Sftp, ServerRoot, SocketType, CertFile), + ?DEBUG("server content transfered - now close ssh connection ", + []), + ssh:close(ConnectionRef), + ?DEBUG("server preparation complete ", []), + ok; + Error -> + ?INFO("FAILED creating sftp channel to server host ~s: " + "~n ~p", [Host, Error]), + exit({failed_establishing_sftp_connection, Error}) + end. + +create_server_content(Sftp, ServerRoot, SocketType, CertFile) -> + %% Create server root + ?DEBUG("ensure existence of ~p", [ServerRoot]), + ensure_remote_dir_exist(Sftp, ServerRoot), + + %% Create the server ebin dir (for the starter module) + EBIN = filename:join(ServerRoot, "ebin"), + ?DEBUG("make ebin dir: ~p", [EBIN]), + maybe_create_remote_dir(Sftp, EBIN), + + %% Create the server ebin dir (for the starter module) + LOG = filename:join(ServerRoot, "log"), + ?DEBUG("make log dir: ~p", [LOG]), + maybe_create_remote_dir(Sftp, LOG), + + LocalServerMod = local_server_module(), + ?DEBUG("copy server stub/proxy module ~s", [LocalServerMod]), + RemoteServerMod = remote_server_module(EBIN), + {ok, ServerModBin} = file:read_file(LocalServerMod), + ok = ssh_sftp:write_file(Sftp, RemoteServerMod, ServerModBin), + + LocalSlaveMod = local_slave_module(), + ?DEBUG("copy slave module ~s", [LocalSlaveMod]), + RemoteSlaveMod = remote_slave_module(EBIN), + {ok, SlaveModBin} = file:read_file(LocalSlaveMod), + ok = ssh_sftp:write_file(Sftp, RemoteSlaveMod, SlaveModBin), + + LocalLoggerMod = local_logger_module(), + ?DEBUG("copy logger module ~s", [LocalLoggerMod]), + RemoteLoggerMod = remote_logger_module(EBIN), + {ok, LoggerModBin} = file:read_file(LocalLoggerMod), + ok = ssh_sftp:write_file(Sftp, RemoteLoggerMod, LoggerModBin), + + %% Create the inets server data dir + CGI = filename:join(ServerRoot, "cgi-bin"), + ?DEBUG("make cgi dir: ~p", [CGI]), + maybe_create_remote_dir(Sftp, CGI), + + LocalRandomMod = local_random_html_module(), + ?DEBUG("copy random-html module ~s", [LocalRandomMod]), + RemoteRandomMod = remote_random_html_module(EBIN), + {ok, RandomModBin} = file:read_file(LocalRandomMod), + ok = ssh_sftp:write_file(Sftp, RemoteRandomMod, RandomModBin), + + case SocketType of + ip_comm -> + ok; + _ -> + SSLDir = filename:join(ServerRoot, "ssl"), + ?DEBUG("make conf dir: ~p", [SSLDir]), + maybe_create_remote_dir(Sftp, SSLDir), + ?DEBUG("copy ssl cert file ~s", [CertFile]), + {ok, CertBin} = file:read_file(CertFile), + RemoteCertFile = filename:join(SSLDir, + filename:basename(CertFile)), + ok = ssh_sftp:write_file(Sftp, RemoteCertFile, CertBin), + ok + end, + + ?DEBUG("done", []), + ok. + +remote_server_module(Path) -> + Mod = server_module(), + filename:join(Path, Mod). + +local_server_module() -> + Mod = server_module(), + case code:where_is_file(Mod) of + Path when is_list(Path) -> + Path; + _ -> + exit({server_module_not_found, Mod}) + end. + +server_module() -> + module(?SERVER_MOD). + + +prepare_client_hosts(#state{work_dir = WorkDir, + clients = Clients, + socket_type = SocketType, + client_cert_file = CertFile} = State) -> + Clients2 = + prepare_client_hosts(WorkDir, SocketType, CertFile, Clients, []), + State#state{clients = Clients2}. + +prepare_client_hosts(_WorkDir, _SocketType, _CertFile, [], Acc) -> + lists:reverse(Acc); +prepare_client_hosts(WorkDir, SocketType, CertFile, [Client|Clients], Acc) -> + case prepare_client_host(WorkDir, SocketType, CertFile, Client) of + ok -> + prepare_client_hosts(WorkDir, SocketType, CertFile, Clients, + [Client|Acc]); + _ -> + prepare_client_hosts(WorkDir, SocketType, CertFile, Clients, Acc) + end. + +prepare_client_host(WorkDir, SocketType, CertFile, #client{host = Host}) -> + ?INFO("prepare client host ~s", [Host]), + Opts = [{user_interaction, false}, + {silently_accept_hosts, true}, + {timeout, 2*?SSH_CONNECT_TIMEOUT}, + {connect_timeout, ?SSH_CONNECT_TIMEOUT}], + case ssh_sftp:start_channel(Host, Opts) of + {ok, Sftp, ConnectionRef} -> + ?DEBUG("sftp connection established - now transer client content", + []), + create_client_content(Sftp, WorkDir, SocketType, CertFile), + ?DEBUG("client content transered - now close ssh connection ", []), + ssh:close(ConnectionRef), + ?DEBUG("client preparation complete ", []), + ok; + Error -> + ?INFO("FAILED creating sftp channel to client host ~s: skipping" + "~n ~p", [Host, Error]), + Error + end. + +create_client_content(Sftp, WorkDir, SocketType, CertFile) -> + %% Create work dir + ?DEBUG("ensure existence of ~p", [WorkDir]), + ensure_remote_dir_exist(Sftp, WorkDir), + + %% Create the client ebin dir + EBIN = filename:join(WorkDir, "ebin"), + RemoteClientMod = remote_client_module(EBIN), + ?DEBUG("make ebin dir: ~p", [EBIN]), + maybe_create_remote_dir(Sftp, EBIN), + + LocalClientMod = local_client_module(), + ?DEBUG("copy client stub/proxy module ~s", [LocalClientMod]), + {ok, ClientModBin} = file:read_file(LocalClientMod), + ok = ssh_sftp:write_file(Sftp, RemoteClientMod, ClientModBin), + + LocalSlaveMod = local_slave_module(), + ?DEBUG("copy slave module ~s", [LocalSlaveMod]), + RemoteSlaveMod = remote_slave_module(EBIN), + {ok, SlaveModBin} = file:read_file(LocalSlaveMod), + ok = ssh_sftp:write_file(Sftp, RemoteSlaveMod, SlaveModBin), + + LocalLoggerMod = local_logger_module(), + ?DEBUG("copy logger module ~s", [LocalLoggerMod]), + RemoteLoggerMod = remote_logger_module(EBIN), + {ok, LoggerModBin} = file:read_file(LocalLoggerMod), + ok = ssh_sftp:write_file(Sftp, RemoteLoggerMod, LoggerModBin), + + case SocketType of + ip_comm -> + ok; + _ -> + %% We should really store the remote path somewhere as + %% we use it when starting the client service... + SSLDir = filename:join(WorkDir, "ssl"), + ?DEBUG("make ssl dir: ~p", [SSLDir]), + maybe_create_remote_dir(Sftp, SSLDir), + ?DEBUG("copy ssl cert file ~s", [CertFile]), + {ok, CertBin} = file:read_file(CertFile), + RemoteCertFile = filename:join(SSLDir, + filename:basename(CertFile)), + ok = ssh_sftp:write_file(Sftp, RemoteCertFile, CertBin), + ok + end, + + ?DEBUG("done", []), + ok. + +remote_client_module(Path) -> + Mod = client_module(), + filename:join(Path, Mod). + +local_client_module() -> + Mod = client_module(), + case code:where_is_file(Mod) of + Path when is_list(Path) -> + Path; + _ -> + exit({client_module_not_found, Mod}) + end. + +client_module() -> + module(?CLIENT_MOD). + + +remote_slave_module(Path) -> + Mod = slave_module(), + filename:join(Path, Mod). + +local_slave_module() -> + Mod = slave_module(), + case code:where_is_file(Mod) of + Path when is_list(Path) -> + Path; + _ -> + exit({slave_module_not_found, Mod}) + end. + +slave_module() -> + module(hdlt_slave). + + +remote_logger_module(Path) -> + Mod = logger_module(), + filename:join(Path, Mod). + +local_logger_module() -> + Mod = logger_module(), + case code:where_is_file(Mod) of + Path when is_list(Path) -> + Path; + _ -> + exit({logger_module_not_found, Mod}) + end. + +logger_module() -> + module(hdlt_logger). + + +remote_random_html_module(Path) -> + Mod = random_html_module(), + filename:join(Path, Mod). + +local_random_html_module() -> + Mod = random_html_module(), + case code:where_is_file(Mod) of + Path when is_list(Path) -> + Path; + _ -> + exit({random_module_not_found, Mod}) + end. + +random_html_module() -> + module(hdlt_random_html). + + +module(Mod) -> + Ext = string:to_lower(erlang:system_info(machine)), + lists:flatten(io_lib:format("~w.~s", [Mod, Ext])). + + +%% ----------------------------------------------------------------------- +%% - For every node created (server and client both) there is both +%% a local and remote proxy. +%% - The local proxy is running on the local (controller/collector) node. +%% - The remote proxy is running on the client or server node(s). +%% - The local (ctrl) proxy monitor the remote (server/client) proxy. +%% - The remote (server/client) proxy monitor the local (ctrl) proxy. +%% + +start_client_nodes(#state{clients = Clients, + work_dir = WorkDir, + debugs = Debugs} = State) -> + Connections = + [start_client_node(Client, WorkDir, Debugs) || Client <- Clients], + State#state{client_conns = Connections}. + +start_client_node(#client{path = ErlPath, host = Host}, WorkDir, Debugs) -> + ?INFO("start client on host ~p", [Host]), + EbinDir = filename:join(WorkDir, "ebin"), + start_client_node(Host, ErlPath, [EbinDir], Debugs). + +start_client_node(Host, ErlPath, Paths, Debugs) -> + start_node(Host, ?CLIENT_NODE_NAME, + ErlPath, Paths, [], ?CLIENT_MOD, Debugs). + + +start_server_node(#state{http_server = #server{path = ErlPath, host = Host}, + server_root = ServerRoot, + nof_schedulers = NofScheds, + debugs = Debugs} = State) -> + ?INFO("start server on host ~p", [Host]), + CgiBinDir = filename:join(ServerRoot, "cgi-bin"), + EbinDir = filename:join(ServerRoot, "ebin"), + Connection = + start_server_node(Host, ErlPath, [CgiBinDir, EbinDir], + Debugs, NofScheds), + State#state{server_conn = Connection}. + +start_server_node(Host, ErlPath, Paths, Debugs, NofScheds) -> + Args = + if + NofScheds =:= 0 -> + "-smp disable"; + true -> + lists:flatten(io_lib:format("-smp +S ~w", [NofScheds])) + end, + start_node(Host, ?SERVER_NODE_NAME, + ErlPath, Paths, Args, ?SERVER_MOD, Debugs). + + +%% ----------------------------------------------------------------------- +%% - For every node created (server and client both) there is both +%% a local and remote proxy. +%% - The local proxy is running on the local (controller/collector) node. +%% - The remote proxy is running on the client or server node(s). +%% - The local (ctrl) proxy monitor the remote (server/client) proxy. +%% - The remote (server/client) proxy monitor the local (ctrl) proxy. +%% + +start_node(Host, NodeName, ErlPath, Paths, Args, Module, Debugs) -> + %% Start the (local) proxy + ?DEBUG("start_node -> start local proxy and remote node", []), + ProxyDebug = proplists:get_value(proxy, Debugs, silence), + Proxy = proxy_start(Host, NodeName, ErlPath, Paths, Args, Module, + ProxyDebug), + + ?DEBUG("start_node -> local proxy started - now start node", []), + SlaveDebug = proplists:get_value(slave, Debugs, silence), + Node = proxy_start_node(Proxy, SlaveDebug), + + ?DEBUG("start_node -> sync global", []), + global:sync(), + + ?DEBUG("start_node -> start remote proxy", []), + proxy_start_remote(Proxy), + + ?DEBUG("start_node -> start (remote) inets framework", []), + proxy_start_inets(Proxy), + + ?DEBUG("start_node -> done", []), + #connection{proxy = Proxy, node = Node, node_name = NodeName, host = Host}. + + +proxy_start(Host, NodeName, ErlPath, Paths, Args, Module, Debug) -> + ?LOG("try starting local proxy for ~p@~s", [NodeName, Host]), + ProxyArgs = [Host, NodeName, ErlPath, Paths, Args, Module, Debug], + case proc_lib:start_link(?MODULE, proxy, + ProxyArgs, ?LOCAL_PROXY_START_TIMEOUT) of + {ok, Proxy} -> + Proxy; + Error -> + exit({failed_starting_proxy, Error}) + end. + +proxy_start_node(Proxy, Debug) -> + {ok, Node} = proxy_request(Proxy, {start_node, Debug}), + Node. + +proxy_start_remote(Proxy) -> + proxy_request(Proxy, start_remote_proxy). + +proxy_start_inets(Proxy) -> + proxy_request(Proxy, start_inets). + +proxy_start_service(Proxy, Args) -> + proxy_request(Proxy, {start_service, Args}). + +proxy_release(Proxy) -> + proxy_request(Proxy, release). + +proxy_stop(Proxy) -> + StopResult = proxy_request(Proxy, stop), + ?DEBUG("proxy stop result: ~p", [StopResult]), + StopResult. + +proxy_request(Proxy, Req) -> + Ref = make_ref(), + Proxy ! {proxy_request, Ref, self(), Req}, + receive + {proxy_reply, Ref, Proxy, Rep} -> + Rep + end. + +proxy_reply(From, Ref, Rep) -> + From ! {proxy_reply, Ref, self(), Rep}. + +proxy(Host, NodeName, ErlPath, Paths, Args, Module, Debug) -> + process_flag(trap_exit, true), + SName = lists:flatten( + io_lib:format("HDLT CTRL PROXY[~p,~s,~w]", + [self(), Host, NodeName])), + ?SET_NAME(SName), + ?SET_LEVEL(Debug), + ?LOG("starting with" + "~n Host: ~p" + "~n NodeName: ~p" + "~n ErlPath: ~p" + "~n Paths: ~p" + "~n Args: ~p" + "~n Module: ~p", [Host, NodeName, ErlPath, Paths, Args, Module]), + State = #proxy{mode = started, + mod = Module, + host = Host, + node_name = NodeName, + erl_path = ErlPath, + paths = Paths, + args = Args}, + proc_lib:init_ack({ok, self()}), + ?DEBUG("started", []), + proxy_loop(State). + + +proxy_loop(#proxy{mode = stopping}) -> + receive + {proxy_request, Ref, From, stop} -> + ?LOG("[stopping] received stop order", []), + proxy_reply(From, Ref, ok), + exit(normal); + + {'EXIT', Pid, Reason} -> + ?INFO("[stopping] received exit message from ~p: " + "~n Reason: ~p", [Pid, Reason]), + exit(Reason) + + end; + +proxy_loop(#proxy{mode = started, + host = Host, + node_name = NodeName, + erl_path = ErlPath, + paths = Paths, + args = Args} = State) -> + receive + {proxy_request, Ref, From, {start_node, Debug}} -> + ?LOG("[starting] received start_node order", []), + case hdlt_slave:start_link(Host, NodeName, + ErlPath, Paths, Args, + Debug) of + {ok, Node} -> + ?DEBUG("[starting] node ~p started - now monitor", [Node]), + erlang:monitor_node(Node, true), + State2 = State#proxy{mode = operational, + node = Node}, + proxy_reply(From, Ref, {ok, Node}), + proxy_loop(State2); + {error, Reason} -> + ?INFO("[starting] failed starting node: " + "~n Reason: ~p", [Reason]), + exit({failed_starting_node, {Host, NodeName, Reason}}) + end; + + {'EXIT', Pid, Reason} -> + ?INFO("[stopping] received exit message from ~p: " + "~n Reason: ~p", [Pid, Reason]), + exit(Reason) + + end; + +proxy_loop(#proxy{mode = operational, + mod = Mod, + node = Node} = State) -> + ?DEBUG("[operational] await command", []), + receive + {proxy_request, Ref, From, start_remote_proxy} -> + ?LOG("[operational] start remote proxy", []), + case rpc:call(Node, Mod, start, [?GET_LEVEL()]) of + {ok, Pid} -> + ?DEBUG("[operational] remote proxy started (~p) - " + "create monitor", [Pid]), + ProxyRef = erlang:monitor(process, Pid), + ?DEBUG("[operational] monitor: ~p", [Ref]), + proxy_reply(From, Ref, ok), + proxy_loop(State#proxy{ref = ProxyRef}); + Error -> + ?INFO("[operational] failed starting remote proxy" + "~n Error: ~p", [Error]), + ReplyReason = {failed_starting_remote_proxy, + {Node, Error}}, + Reply = {error, ReplyReason}, + proxy_reply(From, Ref, Reply), + exit({failed_starting_remote_proxy, {Node, Error}}) + end; + + {proxy_request, Ref, From, start_inets} -> + ?INFO("[operational] start inets framework", []), + rpc:cast(Node, Mod, start_inets, []), + proxy_reply(From, Ref, ok), + proxy_loop(State); + + {proxy_request, Ref, From, {start_service, Args}} -> + ?INFO("[operational] start service with" + "~n ~p", [Args]), + case rpc:call(Node, Mod, start_service, Args) of + ok -> + ?DEBUG("[operational] service started", []), + proxy_reply(From, Ref, ok), + proxy_loop(State); + Error -> + ?INFO("[operational] failed starting service: " + "~n Args. ~p" + "~n Error: ~p", [Args, Error]), + erlang:demonitor(State#proxy.ref, [flush]), + Reply = {error, {failed_starting_service, Node, Error}}, + proxy_reply(From, Ref, Reply), + exit({failed_starting_service, Node, Error}) + end; + + {proxy_request, Ref, From, release} -> + ?INFO("[operational] release", []), + rpc:call(Node, Mod, release, []), + proxy_reply(From, Ref, ok), + proxy_loop(State); + + {proxy_request, Ref, From, stop} -> + ?INFO("[operational] received stop order", []), + erlang:demonitor(State#proxy.ref, [flush]), + ?DEBUG("[operational] rpc cast stop order", []), + rpc:cast(Node, Mod, stop, []), + %% And wait for the node death to be reported + Reason = + receive + {nodedown, Node} when State#proxy.node =:= Node -> + ok + after 10000 -> + ?INFO("Node did not die within expected time frame", + []), + {node_death_timeout, Node} + end, + ?DEBUG("[operational] ack stop", []), + proxy_reply(From, Ref, Reason), + exit(normal); + + {nodedown, Node} when State#proxy.node =:= Node -> + ?INFO("[operational] received unexpected nodedoen message", []), + exit({node_died, Node}); + + {'DOWN', Ref, process, _, normal} when State#proxy.ref =:= Ref -> + ?INFO("[operational] remote proxy terminated normally", []), + proxy_loop(State#proxy{ref = undefined, + connection = undefined, + mode = stopping}); + + {'DOWN', Ref, process, _, noconnection} when State#proxy.ref =:= Ref -> + ?INFO("[operational] remote proxy terminated - no node", []), + proxy_loop(State#proxy{ref = undefined, + connection = undefined, + mode = stopping}); + + {'DOWN', Ref, process, _, Reason} when State#proxy.ref =:= Ref -> + ?INFO("[operational] remote proxy terminated: " + "~n Reason: ~p", [Reason]), + exit({remote_proxy_crash, Reason}); + + {'EXIT', Pid, Reason} -> + ?INFO("[operational] received unexpected exit message from ~p: " + "~n Reason: ~p", [Pid, Reason]), + proxy_loop(State) + + end. + + +stop_nodes(#state{server_conn = ServerConn, + client_conns = ClientConns} = State) -> + lists:foreach( + fun(#connection{proxy = Proxy, node_name = NodeName, host = Host}) -> + ?DEBUG("stop_erlang_nodes -> send stop order to local proxy ~p" + "~n for node ~p on ~s", [Proxy, NodeName, Host]), + proxy_stop(Proxy) + end, + ClientConns ++ [ServerConn]), + ?DEBUG("stop_erlang_nodes -> sleep some to give the nodes time to die", + []), + timer:sleep(1000), + ?DEBUG("stop_erlang_nodes -> and a final cleanup round", []), + lists:foreach(fun(Node) -> + ?INFO("try brutal stop node ~p", [Node]), + rpc:cast(Node, erlang, halt, []) + end, + nodes() -- [node()]), + ?DEBUG("stop_erlang_nodes -> done", []), + State#state{server_conn = undefined, client_conns = []}. + + +%% The nodes on which the HDLT clients run have been started previously +start_clients(#state{client_conns = Connections, + debugs = Debugs, + work_dir = WorkDir, + socket_type = SocketType, + client_cert_file = CertFile, + client_sz_from = From, + client_sz_to = To, + client_sz_incr = Incr}, + URL, TestTime, SendRate) -> + Debug = proplists:get_value(client, Debugs, silence), + StartClient = + fun(#connection{host = Host} = Connection) -> + ?DEBUG("start client on ~p", [Host]), + start_client(Connection, + WorkDir, SocketType, CertFile, + URL, From, To, Incr, + TestTime, SendRate, Debug); + (_) -> + ok + end, + lists:foreach(StartClient, Connections). + +start_client(#connection{proxy = Proxy}, + WorkDir, SocketType, LocalCertFile, + URL, From, To, Incr, + TestTime, SendRate, Debug) -> + SSLDir = filename:join(WorkDir, "ssl"), + CertFile = filename:join(SSLDir, filename:basename(LocalCertFile)), + Sizes = randomized_sizes(From, To, Incr), + Args = [SocketType, CertFile, URL, Sizes, TestTime, SendRate, Debug], + proxy_start_service(Proxy, [Args]). + +release_clients(#state{client_conns = Connections}) -> + ReleaseClient = + fun(#connection{proxy = Proxy, + host = Host}) -> + ?DEBUG("release client on ~p", [Host]), + proxy_release(Proxy); + (_) -> + ok + end, + lists:foreach(ReleaseClient, Connections). + + +start_server(#state{server_conn = #connection{proxy = Proxy}, + http_port = Port, + server_root = ServerRoot, + doc_root = DocRoot, + socket_type = SocketType, + server_cert_file = CertFile}) -> + + HttpdConfig = + httpd_config(Port, "hdlt", ServerRoot, DocRoot, SocketType, CertFile), + ?LOG("start the httpd inets service with config: " + "~n ~p", [HttpdConfig]), + proxy_start_service(Proxy, [HttpdConfig]), + ?DEBUG("start_server -> done", []), + ok. + + +httpd_config(Port, ServerName, ServerRoot, DocRoot, + SocketType, LocalCertFile) -> + LogDir = filename:join(ServerRoot, "log"), + ErrorLog = filename:join(LogDir, "error_log"), + TransferLog = filename:join(LogDir, "access_log"), + + SSL = + case SocketType of + ip_comm -> + []; + _ -> % ssl + SSLDir = filename:join(ServerRoot, "ssl"), + CertFile = + filename:join(SSLDir, filename:basename(LocalCertFile)), + [ + {ssl_certificate_file, CertFile}, + {ssl_certificate_key_file, CertFile}, + {ssl_verify_client, 0} + ] + end, + [{port, Port}, + {server_name, ServerName}, + {server_root, ServerRoot}, + {document_root, DocRoot}, + {error_log, ErrorLog}, + {error_log_format, pretty}, + {transfer_log, TransferLog}, + {socket_type, SocketType}, + {max_clients, 10000}, + {modules, [mod_alias, mod_auth, mod_esi, mod_actions, mod_cgi, + mod_dir, mod_get, mod_head, mod_log, mod_disk_log]}, + {script_alias, {"/cgi-bin", filename:join(ServerRoot, "cgi-bin")}}, + {erl_script_alias, {"/cgi-bin", [hdlt_random_html]}}, + {erl_script_timeout, 120000} | SSL]. + + +clean_up(#state{server_root = ServerRoot, + work_dir = WorkDir, + http_server = #server{host = Host}, + clients = Clients}) -> + ?DEBUG("begin server cleanup", []), + server_clean_up(ServerRoot, WorkDir, Host), + ?DEBUG("begin lient cleanup", []), + clients_clean_up(WorkDir, Clients), + ?DEBUG("cleanup done", []), + ok. + +server_clean_up(ServerRoot, WorkDir, Host) -> + ?DEBUG("server cleanup - create sftp channel", []), + {ok, Sftp, ConnectionRef} = + ssh_sftp:start_channel(Host, [{user_interaction, false}, + {silently_accept_hosts, true}]), + ?DEBUG("server cleanup - delete ~p dirs", [ServerRoot]), + del_dirs(Sftp, ServerRoot), + ?DEBUG("server cleanup - delete ~p dirs", [WorkDir]), + del_dirs(Sftp, WorkDir), + ?DEBUG("server cleanup - close sftp channel", []), + ssh:close(ConnectionRef). + +clients_clean_up(_WorkDir, []) -> + ok; +clients_clean_up(WorkDir, [Client|Clients]) -> + client_clean_up(WorkDir, Client), + clients_clean_up(WorkDir, Clients). + +client_clean_up(WorkDir, #client{host = Host}) -> + ?DEBUG("client cleanup - create sftp channel to ~p", [Host]), + {ok, Sftp, ConnectionRef} = + ssh_sftp:start_channel(Host, [{user_interaction, false}, + {silently_accept_hosts, true}]), + ?DEBUG("client cleanup - delete ~p dirs", [WorkDir]), + del_dirs(Sftp, WorkDir), + ?DEBUG("client cleanup - close sftp channel", []), + ssh:close(ConnectionRef). + + +del_dirs(Sftp, Dir) -> + case ssh_sftp:list_dir(Sftp, Dir) of + {ok, []} -> + ssh_sftp:del_dir(Sftp, Dir); + {ok, Files} -> + Files2 = [F || F <- Files, (F =/= "..") andalso (F =/= ".")], + lists:foreach(fun(File) when ((File =/= "..") andalso + (File =/= ".")) -> + FullPath = filename:join(Dir, File), + case ssh_sftp:read_file_info(Sftp, + FullPath) of + {ok, #file_info{type = directory}} -> + del_dirs(Sftp, FullPath), + ssh_sftp:del_dir(Sftp, FullPath); + {ok, _} -> + ssh_sftp:delete(Sftp, FullPath) + end + end, Files2); + _ -> + ok + end. + +collect_data(#state{clients = Clients} = State) -> + N = length(Clients), + collect_req_reply(N, State), + collect_time(N, State). + +collect_req_reply(0, _State) -> + ?DEBUG("all reply data collected", []), + ok; +collect_req_reply(N, #state{nof_schedulers = NofScheduler, + results = Db, + client_conns = Conns} = State) -> + ?DEBUG("await reply data from ~p client(s)", [N]), + receive + {load_data, + {req_reply, Client, NoRequests, NoReplys}} -> + ?DEBUG("received req_reply load-data from client ~p: " + "~n Number of requests: ~p" + "~n Number of replies: ~p", + [Client, NoRequests, NoReplys]), + ets:insert(Db, {{NofScheduler, Client}, + {req_reply, NoRequests, NoReplys}}); + stop -> + ?INFO("received stop", []), + exit(self(), stop); + + {client_exit, Client, Node, Reason} -> + ?INFO("Received unexpected client exit from ~p on node ~p " + "while collecting replies: " + "~n ~p", [Client, Node, Reason]), + case lists:keysearch(Node, #connection.node, Conns) of + {value, Conn} -> + ?LOG("Found problem connection: " + "~n ~p", [Conn]), + exit({unexpected_client_exit, Reason}); + false -> + collect_req_reply(N, State) + end + end, + collect_req_reply(N-1, State). + +collect_time(0, _State) -> + ?DEBUG("all time data collected", []), + ok; +collect_time(N, #state{nof_schedulers = NofScheduler, + results = Db, + client_conns = Conns} = State) -> + ?DEBUG("await time data from ~p clients", [N]), + receive + {load_data, + {time_to_complete, Client, StopTime, LastResponseTime}} -> + ?LOG("received time load-data from client ~p: " + "~n Time of stop: ~p" + "~n Time of last response: ~p", + [Client, StopTime, LastResponseTime]), + ets:insert(Db, {{NofScheduler, Client}, + {time, StopTime, LastResponseTime}}); + stop -> + ?INFO("received stop while collecting data, when N = ~p", [N]), + exit(self(), stop); + + {client_exit, Client, Node, Reason} -> + ?INFO("Received unexpected exit from client ~p on node ~p " + "while collecting time data: " + "~n ~p", [Client, Node, Reason]), + case lists:keysearch(Node, #connection.node, Conns) of + {value, Conn} -> + ?LOG("Found problem connection: " + "~n ~p", [Conn]), + exit({unexpected_client_exit, Reason}); + false -> + collect_req_reply(N, State) + end; + + Else -> %%% Something is wrong! + ?INFO("RECEIVED UNEXPECTED MESSAGE WHILE COLLECTING TIME DATA: " + "~n ~p", [Else]), + collect_time(N, State) + end, + collect_time(N-1, State). + +analyse_data(#state{results = Db, + max_nof_schedulers = MaxNofSchedulers, + test_time = MicroSec}) -> + Tab = ets:new(analysed_results, [set]), + lists:foreach(fun(NofSchedulers) -> + Result = analyse(NofSchedulers, Db, MicroSec), + ets:insert(Tab, Result) + end, [N || N <- lists:seq(0, MaxNofSchedulers)]), + Tab. + + +no_requests_replys(NoSchedulers, Tab) -> + NoRequests = + ets:select(Tab, [{{{NoSchedulers,'_'},{req_reply, '$1', '_'}}, + [],['$$']}]), + NoReplys = + ets:select(Tab, [{{{NoSchedulers, '_'}, {req_reply, '_', '$1'}}, + [], ['$$']}]), + + {lists:sum(lists:append(NoRequests)), + lists:sum(lists:append(NoReplys))}. + +max_time_to_final_response(NofSchedulers, Tab) -> + Candidates = + ets:select(Tab, [{{{NofSchedulers, '_'}, {time, '$1', '$2'}}, + [], ['$$']}]), + + NewCandidates = lists:map( + fun([StopTime, LastTime]) -> + round( + timer:now_diff(LastTime, StopTime) / 100000)/10 + end, Candidates), + + lists:max(NewCandidates). + + +analyse(NofSchedulers, Db, TestTime) -> + Sec = TestTime / 1000, + {NoRequests, NoReplys} = no_requests_replys(NofSchedulers, Db), + {NofSchedulers, round(NoReplys / Sec), NoRequests, + max_time_to_final_response(NofSchedulers, Db)}. + + +save_results_to_file(AnalysedTab, + #state{socket_type = SocketType, + http_server = #server{host = Server}, + max_nof_schedulers = MaxNofSchedulers}) -> + FileName = fun(Post) -> + File = + lists:flatten( + io_lib:format("~s_~w_~s", + [Server, SocketType, Post])), + filename:join("./", File) + end, + Reps = FileName("replys_per_sec.txt"), + Reqs = FileName("total_requests.txt"), + Decay = FileName("decay_time.txt"), + + [FdReps, FdReqs, FdDecay] = + lists:map(fun(File) -> + {ok, Fd} = file:open(File, [write]), + Fd + end, [Reps, Reqs, Decay]), + lists:foreach(fun(NofSchedulers) -> + save_result_to_file(NofSchedulers, + FdReps, FdReqs, + FdDecay, AnalysedTab) + end, [N || N <- lists:seq(0, MaxNofSchedulers)]), + [Reps, Reqs, Decay]. + +save_result_to_file(NofSchedulers, + FdReps, FdReqs, FdDecay, AnalysedTab) -> + + [{NofSchedulers, NofRepsPerSec, NofReqs, MaxFinalResponseTime}] = + ets:lookup(AnalysedTab, NofSchedulers), + + file:write(FdReps, io_lib:format("~p,~p~n", + [NofRepsPerSec, NofSchedulers])), + file:write(FdReqs, io_lib:format("~p,~p~n", + [NofReqs, NofSchedulers])), + file:write(FdDecay, io_lib:format("~p,~p~n", [MaxFinalResponseTime, + NofSchedulers])). + + +help() -> + io:format("hdlt:start(Options). Where options:~n " + " ~n~p~n~n hdlt:start([]). -> hdlt:start(~p)~n~n", + [[{send_rate, "integer()", + "Numer of outstanding requests that a client " + "should have during the test to create a load situation."}, + {clients, "[{path(), host()}]", "Paths to erlang and names of hosts to run clients on."}, + {test_time, "{hours(), mins(), sec()}", + "How long the test should be run."}, + {server, "{path(), host()}", "Path to erl and name of host to run the HTTP-server on."}, + {port, "port()", "The port that the HTTP-server should use."}, + {server_dir, "dir()", "The directory where the HTTP server " + " stores its contents and configuration."}, + {work_dir, "dir()", "Path on the computer, where the test " + "is run, to a directory where the results can be saved."}, + {max_no_schedulers, "integer()", + "Max number of schedulers to run."}, + {socket_type, "Httpd configuration option socket_type"}], + defaults()]). + + +defaults() -> + [{send_rate, ?DEFAULT_SENDRATE}, + %% {clients, []}, + {test_time, ?DEFAULT_TEST_TIME}, + %% {server, ?DEFAULT_SERVER}, + {port, ?DEFAULT_PORT}, + {server_dir, ?DEFAULT_SERVER_DIR}, + {work_dir, ?DEFAULT_WORK_DIR}, + {max_nof_schedulers, ?DEFAULT_MAX_NOF_SCHEDULERS}, + {socket_type, ?DEFAULT_SOCKET_TYPE}]. + + +get_debugs(Config) -> + ?DEBUG("get debugs", []), + Debugs = proplists:get_value(debug, Config, ?DEFAULT_DEBUGS), + verify_debugs(Debugs), + Debugs. + +verify_debugs([]) -> + ok; +verify_debugs([{Tag, Debug}|Debugs]) -> + verify_debug(Tag, Debug), + verify_debugs(Debugs). + +verify_debug(Tag, Debug) -> + case lists:member(Tag, [ctrl, proxy, slave, client]) of + true -> + ok; + false -> + exit({bad_debug_tag, Tag}) + end, + case lists:member(Debug, [silence, info, log, debug]) of + true -> + ok; + false -> + exit({bad_debug_level, Debug}) + end. + +get_send_rate(Config) -> + ?DEBUG("get send_rate", []), + case proplists:get_value(send_rate, Config, ?DEFAULT_SENDRATE) of + SendRate when is_integer(SendRate) andalso (SendRate > 0) -> + SendRate; + BadSendRate -> + exit({bad_sendrate, BadSendRate}) + end. + + +get_clients(Config) -> + ?DEBUG("get clients", []), + case proplists:get_value(clients, Config, undefined) of + undefined -> + missing_mandatory_config(clients); + Clients when is_list(Clients) andalso (length(Clients) > 0) -> + case [#client{path = Path, host = Host} || + {Path, Host} <- Clients] of + Clients2 when (length(Clients2) > 0) -> + Clients2; + _ -> + exit({bad_clients, Clients}) + end; + + BadClients -> + exit({bad_clients, BadClients}) + + end. + +get_server(Config) -> + ?DEBUG("get server", []), + case proplists:get_value(server, Config) of + {Path, Host} when is_list(Path) andalso is_list(Host) -> + #server{path = Path, host = Host}; + undefined -> + missing_mandatory_config(server) + end. + +get_server_dir(Config) -> + ?DEBUG("get server_dir", []), + get_dir(server_dir, Config, ?DEFAULT_SERVER_DIR). + +get_work_dir(Config) -> + ?DEBUG("get work_dir", []), + get_dir(work_dir, Config, ?DEFAULT_WORK_DIR). + +get_dir(Key, Config, Default) -> + Dir = proplists:get_value(Key, Config, Default), + ensure_absolute(Dir), + Dir. + +ensure_absolute(Path) -> + case filename:pathtype(Path) of + absolute -> + ok; + PathType -> + exit({bad_pathtype, Path, PathType}) + end. + +get_port(Config) -> + ?DEBUG("get port", []), + case proplists:get_value(port, Config, ?DEFAULT_PORT) of + Port when is_integer(Port) andalso (Port > 0) -> + Port; + BadPort -> + exit({bad_port, BadPort}) + end. + +get_socket_type(Config) -> + ?DEBUG("get socket_type", []), + case proplists:get_value(socket_type, Config, ?DEFAULT_SOCKET_TYPE) of + SocketType when ((SocketType =:= ip_comm) orelse + (SocketType =:= ssl) orelse + (SocketType =:= essl) orelse + (SocketType =:= ossl)) -> + SocketType; + BadSocketType -> + exit({bad_socket_type, BadSocketType}) + end. + +get_test_time(Config) -> + ?DEBUG("get test_time", []), + case proplists:get_value(test_time, Config, ?DEFAULT_TEST_TIME) of + Seconds when is_integer(Seconds) andalso (Seconds > 0) -> + timer:seconds(Seconds); + BadTestTime -> + exit({bad_test_time, BadTestTime}) + end. + +get_max_nof_schedulers(Config) -> + ?DEBUG("get max_nof_schedulers", []), + case proplists:get_value(max_nof_schedulers, + Config, + ?DEFAULT_MAX_NOF_SCHEDULERS) of + MaxNofScheds when (is_integer(MaxNofScheds) andalso + (MaxNofScheds >= 0)) -> + MaxNofScheds; + BadMaxNofScheds -> + exit({bad_max_nof_schedulers, BadMaxNofScheds}) + end. + + +get_server_cert_file(Config) -> + ?DEBUG("get server cert file", []), + get_cert_file(server_cert_file, ?DEFAULT_SERVER_CERT, Config). + +get_client_cert_file(Config) -> + ?DEBUG("get client cert file", []), + get_cert_file(client_cert_file, ?DEFAULT_CLIENT_CERT, Config). + +get_cert_file(Tag, DefaultCertFileName, Config) -> + LibDir = code:lib_dir(inets), + HdltDir = filename:join(LibDir, "examples/httpd_load_test"), + DefaultCertFile = filename:join(HdltDir, DefaultCertFileName), + case proplists:get_value(Tag, Config, DefaultCertFile) of + F when is_list(F) -> + case file:read_file_info(F) of + {ok, #file_info{type = regular}} -> + F; + {ok, #file_info{type = Type}} -> + exit({wrong_file_type, Tag, F, Type}); + {error, Reason} -> + exit({failed_readin_file_info, Tag, F, Reason}) + end; + BadFile -> + exit({bad_cert_file, Tag, BadFile}) + end. + + +get_work_sim(Config) -> + ?DEBUG("get work_sim", []), + case proplists:get_value(work_simulator, Config, ?DEFAULT_WORK_SIM) of + WS when is_integer(WS) andalso (WS > 0) -> + WS; + BadWS -> + exit({bad_work_simulator, BadWS}) + end. + + +get_data_size(Config) -> + ?DEBUG("get data_size", []), + case proplists:get_value(data_size, Config, ?DEFAULT_DATA_SIZE) of + {From, To, Incr} = DS when (is_integer(From) andalso + is_integer(To) andalso + is_integer(Incr) andalso + (To > From) andalso + (From > 0) andalso + (Incr > 0)) -> + DS; + {From, To} when (is_integer(From) andalso + is_integer(To) andalso + (To > From) andalso + (From > 0)) -> + {From, To, ?DEFAULT_DATA_SIZE_INCR}; + BadDS -> + exit({bad_data_size, BadDS}) + end. + + +url(#server{host = Host}, Port, SocketType, WorkSim) -> + Scheme = + case SocketType of + ip_comm -> + "http"; + _ -> %% SSL + "https" + end, + lists:flatten( + io_lib:format("~s://~s:~w/cgi-bin/hdlt_random_html:page?~w:", + [Scheme, Host, Port, WorkSim])). + + +missing_mandatory_config(Missing) -> + exit({missing_mandatory_config, Missing}). + + +ensure_remote_dir_exist(Sftp, Path0) -> + case filename:split(Path0) of + [Root, Dir | Rest] -> + %% We never accept creating the root directory, + %% or the next level, so these *must* exist: + Path = filename:join(Root, Dir), + case ssh_sftp:read_file_info(Sftp, Path) of + {ok, #file_info{type = directory}} -> + ensure_remote_dir_exist(Sftp, Path, Rest); + {ok, #file_info{type = Type}} -> + ?INFO("Not a dir: ~p (~p)", [Path, Type]), + exit({not_a_dir, Path, Type}); + {error, Reason} -> + ?INFO("Failed reading file info for ~p: ~p", + [Path, Reason]), + exit({failed_reading_file_info, Path, Reason}) + end; + BadSplit -> + ?INFO("Bad remote dir path: ~p -> ~p", [Path0, BadSplit]), + exit({bad_dir, Path0}) + end. + +ensure_remote_dir_exist(_Sftp, _Dir, []) -> + ok; +ensure_remote_dir_exist(Sftp, Path, [Dir|Rest]) -> + NewPath = filename:join(Path, Dir), + case ssh_sftp:read_file_info(Sftp, NewPath) of + {ok, #file_info{type = directory}} -> + ensure_remote_dir_exist(Sftp, NewPath, Rest); + {ok, #file_info{type = Type}} -> + %% Exist, but is not a dir + ?INFO("Not a dir: ~p (~p)", [NewPath, Type]), + exit({not_a_dir, NewPath, Type}); + {error, Reason} -> + %% This *could* be because the dir does not exist, + %% but it could also be some other error. + %% As usual, the error reason of the sftp is + %% a pease of crap, so we cannot use the + %% error reason. + %% The simplest way to test this is to simply + %% try to create the directory, since we should + %% ensure its existence anyway.. + case ssh_sftp:make_dir(Sftp, NewPath) of + ok -> + ensure_remote_dir_exist(Sftp, NewPath, Rest); + _ -> + ?INFO("Failed reading file info for ~p: ~p", + [Dir, Reason]), + exit({failed_reading_file_info, NewPath, Reason}) + end + end. + +maybe_create_remote_dir(Sftp, Dir) -> + case ssh_sftp:read_file_info(Sftp, Dir) of + {ok, #file_info{type = directory}} -> + ok; + {ok, #file_info{type = Type}} -> + %% Exist, but is not a dir + ?INFO("Not a dir: ~p (~p)", [Dir, Type]), + exit({not_a_dir, Dir, Type}); + {error, Reason} -> + %% Assume dir noes not exist... + case ssh_sftp:make_dir(Sftp, Dir) of + ok -> + ok; + _ -> + ?INFO("Failed reading file info for ~p: ~p", + [Dir, Reason]), + exit({failed_reading_file_info, Dir, Reason}) + end + end. + + +set_debug_level(Debugs) -> + Debug = proplists:get_value(ctrl, Debugs, silence), + ?SET_LEVEL(Debug). + + +%% Generates a list of numbers between A and B, such that +%% there is exact one number between A and B and then +%% randomizes that list. + +randomized_sizes_init() -> + {A, B, C} = os:timestamp(), + random:seed(A, B, C). + +randomized_sizes(From, To, Incr) -> + L = lists:seq(From, To, Incr), + Len = length(L), + randomized_sizes2(L, 0, Len-1). + +randomized_sizes2(L, N, Len) when N >= Len -> + L; +randomized_sizes2(L, N, Len) -> + SplitWhere = random:uniform(Len), + {A, B} = lists:split(SplitWhere, L), + randomized_sizes2(B ++ A, N+1, Len). diff --git a/lib/inets/examples/httpd_load_test/hdlt_logger.erl b/lib/inets/examples/httpd_load_test/hdlt_logger.erl new file mode 100644 index 0000000000..b0c7eab2d1 --- /dev/null +++ b/lib/inets/examples/httpd_load_test/hdlt_logger.erl @@ -0,0 +1,138 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%%---------------------------------------------------------------------- +%% Purpose: This is a simple logger utility for the HDLT toolkit. +%% It assumesd that the debug level and the "name" of the +%% logging entity has been put in process environment +%% (using the set_level and set_name functions respectively). +%%---------------------------------------------------------------------- + +%% + +-module(hdlt_logger). + +-export([ + start/0, + set_level/1, get_level/0, set_name/1, + info/2, log/2, debug/2 + ]). + +-export([logger/1]). + +-define(LOGGER, ?MODULE). +-define(MSG, hdlt_logger_msg). +-define(LEVEL, hdlt_logger_level). +-define(NAME, hdlt_logger_name). +-define(INFO_STR, "INFO"). +-define(LOG_STR, "LOG "). +-define(DEBUG_STR, "DBG "). + + +start() -> + Self = self(), + proc_lib:start(?MODULE, logger, [Self]). + +set_name(Name) when is_list(Name) -> + put(?NAME, Name), + ok. + +get_level() -> + get(?LEVEL). + +set_level(Level) -> + case lists:member(Level, [silence, info, log, debug]) of + true -> + put(?LEVEL, Level), + ok; + false -> + erlang:error({bad_debug_level, Level}) + end. + + +info(F, A) -> +%% io:format("info -> " ++ F ++ "~n", A), + do_log(info, get(?LEVEL), F, A). + +log(F, A) -> +%% io:format("log -> " ++ F ++ "~n", A), + do_log(log, get(?LEVEL), F, A). + +debug(F, A) -> +%% io:format("debug -> " ++ F ++ "~n", A), + do_log(debug, get(?LEVEL), F, A). + + +logger(Parent) -> + global:register_name(?LOGGER, self()), + Ref = erlang:monitor(process, Parent), + proc_lib:init_ack(self()), + logger_loop(Ref). + +logger_loop(Ref) -> + receive + {?MSG, F, A} -> + io:format(F, A), + logger_loop(Ref); + {'DOWN', Ref, process, _Object, _Info} -> + %% start the stop timer + erlang:send_after(timer:seconds(5), self(), stop), + logger_loop(undefined); + stop -> + global:unregister_name(?LOGGER), + ok + end. + + +formated_timestamp() -> + {Date, Time} = erlang:localtime(), + {YYYY,MM,DD} = Date, + {Hour,Min,Sec} = Time, + FormatDate = + io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w", + [YYYY,MM,DD,Hour,Min,Sec]), + lists:flatten(FormatDate). + +do_log(_, silence, _, _) -> + ok; +do_log(info, info, F, A) -> + do_log(?INFO_STR, F, A); +do_log(info, log, F, A) -> + do_log(?INFO_STR, F, A); +do_log(log, log, F, A) -> + do_log(?LOG_STR, F, A); +do_log(info, debug, F, A) -> + do_log(?INFO_STR, F, A); +do_log(log, debug, F, A) -> + do_log(?LOG_STR, F, A); +do_log(debug, debug, F, A) -> + do_log(?DEBUG_STR, F, A); +do_log(_, _, _F, _A) -> + ok. + +do_log(SEV, F, A) -> + Name = + case get(?NAME) of + L when is_list(L) -> + L; + _ -> + "UNDEFINED" + end, + Msg = {?MSG, "~s ~s [~s] " ++ F ++ "~n", + [SEV, Name, formated_timestamp() | A]}, + (catch global:send(?LOGGER, Msg)). diff --git a/lib/inets/examples/httpd_load_test/hdlt_logger.hrl b/lib/inets/examples/httpd_load_test/hdlt_logger.hrl new file mode 100644 index 0000000000..aa94babc48 --- /dev/null +++ b/lib/inets/examples/httpd_load_test/hdlt_logger.hrl @@ -0,0 +1,33 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +-ifndef(hdlt_logger_hrl). +-define(hdlt_logger_hrl, true). + +%% Various log macros +-define(SET_LEVEL(N), hdlt_logger:set_level(N)). +-define(GET_LEVEL(), hdlt_logger:get_level()). +-define(SET_NAME(N), hdlt_logger:set_name(N)). + +-define(INFO(F, A), hdlt_logger:info(F, A)). +-define(LOG(F, A), hdlt_logger:log(F, A)). +-define(DEBUG(F, A), hdlt_logger:debug(F, A)). + +-endif. % -ifdef(hdlt_logger_hrl). diff --git a/lib/inets/examples/httpd_load_test/hdlt_random_html.erl b/lib/inets/examples/httpd_load_test/hdlt_random_html.erl new file mode 100644 index 0000000000..e3a572c61f --- /dev/null +++ b/lib/inets/examples/httpd_load_test/hdlt_random_html.erl @@ -0,0 +1,59 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(hdlt_random_html). +-export([page/3]). + +page(SessionID, _Env, Input) -> +%% log("page(~p) -> deliver content-type when" +%% "~n SessionID: ~p" +%% "~n Env: ~p" +%% "~n Input: ~p", [self(), SessionID, Env, Input]), + [WorkSimStr, SzSimStr] = string:tokens(Input, [$:]), + WorkSim = list_to_integer(WorkSimStr), + SzSim = list_to_integer(SzSimStr), + mod_esi:deliver(SessionID, "Content-Type:text/html\r\n\r\n"), + mod_esi:deliver(SessionID, start("Random test page")), + mod_esi:deliver(SessionID, content(WorkSim, SzSim)), + mod_esi:deliver(SessionID, stop()), + ok. + +start(Title) -> + "<HTML> +<HEAD> +<TITLE>" ++ Title ++ "</TITLE> + </HEAD> +<BODY>\n". + +stop() -> + "</BODY> +</HTML> +". + +content(WorkSim, SzSim) -> + {A, B, C} = now(), + random:seed(A, B, C), + lists:sort([random:uniform(X) || X <- lists:seq(1, WorkSim)]), + lists:flatten(lists:duplicate(SzSim, "Dummy data ")). + +%% log(F, A) -> +%% hdlt_logger:set_name("HDLT RANDOM-HTML"), +%% hdlt_logger:set_level(debug), +%% hdlt_logger:log(F, A). diff --git a/lib/inets/examples/httpd_load_test/hdlt_server.erl b/lib/inets/examples/httpd_load_test/hdlt_server.erl new file mode 100644 index 0000000000..3e5a849d5b --- /dev/null +++ b/lib/inets/examples/httpd_load_test/hdlt_server.erl @@ -0,0 +1,163 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% Purpose: The HDLT server module. +%% This is just a stub, making future expansion easy. +%% All code in this module is executed in the local node! +%%---------------------------------------------------------------------- + +-module(hdlt_server). + +-export([start/1, stop/0, start_inets/0, start_service/1]). + +-export([proxy/1]). + +-include_lib("kernel/include/file.hrl"). +-include("hdlt_logger.hrl"). + + +-define(PROXY, hdlt_proxy). + + +%% This function is used to start the proxy process +%% This function is called *after* the nodes has been +%% "connected" with the controller/collector node. + +start(Debug) -> + proc_lib:start(?MODULE, proxy, [Debug]). + +stop() -> + ?PROXY ! stop. + +start_inets() -> + ?PROXY ! start_inets. + +start_service(Config) -> + ?PROXY ! {server_start, Config, self()}, + receive + {server_start_result, Result} -> + Result + after 15000 -> + {error, timeout} + end. + + +proxy(Debug) -> + process_flag(trap_exit, true), + erlang:register(?PROXY, self()), + ?SET_NAME("HDLT PROXY"), + ?SET_LEVEL(Debug), + ?LOG("starting", []), + Ref = await_for_controller(10), + CtrlNode = node(Ref), + erlang:monitor_node(CtrlNode, true), + proc_lib:init_ack({ok, self()}), + ?DEBUG("started", []), + proxy_loop(Ref, CtrlNode). + +await_for_controller(N) when N > 0 -> + case global:whereis_name(hdlt_ctrl) of + Pid when is_pid(Pid) -> + erlang:monitor(process, Pid); + _ -> + timer:sleep(1000), + await_for_controller(N-1) + end; +await_for_controller(_) -> + proc_lib:init_ack({error, controller_not_found, nodes()}), + timer:sleep(500), + halt(). + + +proxy_loop(Ref, CtrlNode) -> + ?DEBUG("await command", []), + receive + stop -> + ?LOG("received stop", []), + halt(); + + start_inets -> + ?LOG("start the inets service framework", []), + case (catch inets:start()) of + ok -> + ?LOG("framework started", []), + proxy_loop(Ref, CtrlNode); + Error -> + ?LOG("failed starting inets service framework: " + "~n Error: ~p", [Error]), + halt() + end; + + {server_start, Config, From} -> + ?LOG("start-server", []), + maybe_start_crypto_and_ssl(Config), + %% inets:enable_trace(max, "/tmp/inets-httpd-trace.log", httpd), + %% inets:enable_trace(max, "/tmp/inets-httpd-trace.log", all), + case (catch inets:start(httpd, Config)) of + {ok, _} -> + ?LOG("server started when" + "~n which(inets): ~p" + "~n RootDir: ~p" + "~n System info: ~p", [code:which(inets), + code:root_dir(), + get_node_info()]), + From ! {server_start_result, ok}, + proxy_loop(Ref, CtrlNode); + Error -> + ?INFO("server start failed" + "~n Error: ~p", [Error]), + From ! {server_start_result, Error}, + halt() + end; + + {nodedown, CtrlNode} -> + ?LOG("received nodedown for controller node - terminate", []), + halt(); + + {'DOWN', Ref, process, _, _} -> + ?LOG("received DOWN message for controller - terminate", []), + %% The controller has terminated, time to die + halt() + + end. + + +maybe_start_crypto_and_ssl(Config) -> + case lists:keysearch(socket_type, 1, Config) of + {value, {socket_type, SocketType}} when ((SocketType =:= ssl) orelse + (SocketType =:= ossl) orelse + (SocketType =:= essl)) -> + ?LOG("maybe start crypto and ssl", []), + (catch crypto:start()), + ssl:start(); + _ -> + ok + end. + + +get_node_info() -> + [{cpu_topology, erlang:system_info(cpu_topology)}, + {heap_type, erlang:system_info(heap_type)}, + {nof_schedulers, erlang:system_info(schedulers)}, + {otp_release, erlang:system_info(otp_release)}, + {version, erlang:system_info(version)}, + {system_version, erlang:system_info(system_version)}, + {system_architecture, erlang:system_info(system_architecture)}]. + diff --git a/lib/inets/examples/httpd_load_test/hdlt_slave.erl b/lib/inets/examples/httpd_load_test/hdlt_slave.erl new file mode 100644 index 0000000000..52af9b5b90 --- /dev/null +++ b/lib/inets/examples/httpd_load_test/hdlt_slave.erl @@ -0,0 +1,291 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(hdlt_slave). + + +-export([start_link/4, start_link/5, start_link/6, stop/1]). + +%% Internal exports +-export([wait_for_slave/9, slave_start/1, wait_for_master_to_die/3]). + +-include("hdlt_logger.hrl"). + +-define(SSH_PORT, 22). +-define(TIMEOUT, 60000). +-define(LOGGER, hdlt_logger). + + +%% *********************************************************************** +%% start_link/4,5 -- +%% +%% The start/4,5 functions are used to start a slave Erlang node. +%% The node on which the start/N functions are used is called the +%% master in the description below. +%% +%% If hostname is the same for the master and the slave, +%% the Erlang node will simply be spawned. The only requirment for +%% this to work is that the 'erl' program can be found in PATH. +%% +%% If the master and slave are on different hosts, start/N uses +%% the 'rsh' program to spawn an Erlang node on the other host. +%% Alternative, if the master was started as +%% 'erl -sname xxx -rsh my_rsh...', then 'my_rsh' will be used instead +%% of 'rsh' (this is useful for systems where the rsh program is named +%% 'remsh'). +%% +%% For this to work, the following conditions must be fulfilled: +%% +%% 1. There must be an Rsh program on computer; if not an error +%% is returned. +%% +%% 2. The hosts must be configured to allowed 'rsh' access without +%% prompts for password. +%% +%% The slave node will have its filer and user server redirected +%% to the master. When the master node dies, the slave node will +%% terminate. For the start_link functions, the slave node will +%% terminate also if the process which called start_link terminates. +%% +%% Returns: {ok, Name@Host} | +%% {error, timeout} | +%% {error, no_rsh} | +%% {error, {already_running, Name@Host}} + +start_link(Host, Name, ErlPath, Paths) -> + start_link(Host, Name, ErlPath, Paths, [], silence). + +start_link(Host, Name, ErlPath, Paths, DebugLevel) when is_atom(DebugLevel) -> + start_link(Host, Name, ErlPath, Paths, [], DebugLevel); +start_link(Host, Name, ErlPath, Paths, Args) when is_list(Args) -> + start_link(Host, Name, ErlPath, Paths, Args, silence). + +start_link(Host, Name, ErlPath, Paths, Args, DebugLevel) -> + Node = list_to_atom(lists:concat([Name, "@", Host])), + case net_adm:ping(Node) of + pang -> + start_it(Host, Name, Node, ErlPath, Paths, Args, DebugLevel); + pong -> + {error, {already_running, Node}} + end. + +%% Stops a running node. + +stop(Node) -> + rpc:call(Node, erlang, halt, []), + ok. + + +%% Starts a new slave node. + +start_it(Host, Name, Node, ErlPath, Paths, Args, DebugLevel) -> + Prog = filename:join([ErlPath, "erl"]), + spawn(?MODULE, wait_for_slave, [self(), Host, Name, Node, Paths, Args, self(), Prog, DebugLevel]), + receive + {result, Result} -> Result + end. + +%% Waits for the slave to start. + +wait_for_slave(Parent, Host, Name, Node, Paths, Args, + LinkTo, Prog, DebugLevel) -> + ?SET_NAME("HDLT SLAVE STARTER"), + ?SET_LEVEL(DebugLevel), + ?DEBUG("begin", []), + Waiter = register_unique_name(0), + case mk_cmd(Host, Name, Paths, Args, Waiter, Prog) of + {ok, Cmd} -> + ?DEBUG("command generated: ~n~s", [Cmd]), + case (catch ssh_slave_start(Host, Cmd)) of + {ok, Conn, _Chan} -> + ?DEBUG("ssh channel created", []), + receive + {SlavePid, slave_started} -> + ?DEBUG("slave started: ~p", [SlavePid]), + unregister(Waiter), + slave_started(Parent, LinkTo, SlavePid, Conn, + DebugLevel) + after 32000 -> + ?INFO("slave node failed to report in on time", + []), + %% If it seems that the node was partially started, + %% try to kill it. + case net_adm:ping(Node) of + pong -> + spawn(Node, erlang, halt, []), + ok; + _ -> + ok + end, + Parent ! {result, {error, timeout}} + end; + {error, Reason} = Error -> + ?INFO("FAILED starting node: " + "~n ~p" + "~n ~p", [Reason, Cmd]), + Parent ! {result, Error} + end; + Other -> + ?INFO("FAILED creating node command string: " + "~n ~p", [Other]), + Parent ! {result, Other} + end. + + +ssh_slave_start(Host, ErlCmd) -> + ?DEBUG("ssh_slave_start -> try connect to ~p", [Host]), + Connection = + case (catch ssh:connect(Host, ?SSH_PORT, + [{silently_accept_hosts, true}])) of + {ok, Conn} -> + ?DEBUG("ssh_exec_erl -> connected: ~p", [Conn]), + Conn; + Error1 -> + ?LOG("failed connecting to ~p: ~p", [Host, Error1]), + throw({error, {ssh_connect_failed, Error1}}) + end, + + ?DEBUG("ssh_exec_erl -> connected - now create channel", []), + Channel = + case (catch ssh_connection:session_channel(Connection, ?TIMEOUT)) of + {ok, Chan} -> + ?DEBUG("ssh_exec_erl -> channel ~p created", [Chan]), + Chan; + Error2 -> + ?LOG("failed creating channel: ~p", [Error2]), + throw({error, {ssh_channel_create_failed, Error2}}) + end, + + ?DEBUG("ssh_exec_erl -> channel created - now exec command: " + "~n ~p", [ErlCmd]), + case (catch ssh_connection:exec(Connection, Channel, ErlCmd, infinity)) of + success -> + ?DEBUG("ssh_exec_erl -> command exec'ed - clean ssh msg", []), + clean_ssh_msg(), + ?DEBUG("ssh_exec_erl -> done", []), + {ok, Connection, Channel}; + Error3 -> + ?LOG("failed exec comand: ~p", [Error3]), + throw({error, {ssh_exec_failed, Error3}}) + end. + +clean_ssh_msg() -> + receive + {ssh_cm, _X, _Y} -> + clean_ssh_msg() + after 1000 -> + ok + end. + + +slave_started(ReplyTo, Master, Slave, Conn, Level) + when is_pid(Master) andalso is_pid(Slave) -> + process_flag(trap_exit, true), + SName = lists:flatten( + io_lib:format("HDLT SLAVE CTRL[~p,~p]", + [self(), node(Slave)])), + ?SET_NAME(SName), + ?SET_LEVEL(Level), + ?LOG("initiating", []), + MasterRef = erlang:monitor(process, Master), + SlaveRef = erlang:monitor(process, Slave), + ReplyTo ! {result, {ok, node(Slave)}}, + slave_running(Master, MasterRef, Slave, SlaveRef, Conn). + + +%% The slave node will be killed if the master process terminates, +%% The master process will not be killed if the slave node terminates. + +slave_running(Master, MasterRef, Slave, SlaveRef, Conn) -> + ?DEBUG("await message", []), + receive + {'DOWN', MasterRef, process, _Object, _Info} -> + ?LOG("received DOWN from master", []), + erlang:demonitor(SlaveRef, [flush]), + Slave ! {nodedown, node()}, + ssh:close(Conn); + + {'DOWN', SlaveRef, process, Object, _Info} -> + ?LOG("received DOWN from slave (~p)", [Object]), + erlang:demonitor(MasterRef, [flush]), + ssh:close(Conn); + + Other -> + ?DEBUG("received unknown: ~n~p", [Other]), + slave_running(Master, MasterRef, Slave, SlaveRef, Conn) + + end. + +register_unique_name(Number) -> + Name = list_to_atom(lists:concat([?MODULE, "_waiter_", Number])), + case catch register(Name, self()) of + true -> + Name; + {'EXIT', {badarg, _}} -> + register_unique_name(Number+1) + end. + + +%% Makes up the command to start the nodes. +%% If the node should run on the local host, there is +%% no need to use rsh. + +mk_cmd(Host, Name, Paths, Args, Waiter, Prog) -> + PaPaths = [[" -pa ", Path] || Path <- Paths], + {ok, lists:flatten( + lists:concat([Prog, + " -detached -nopinput ", + Args, " ", + " -sname ", Name, "@", Host, + " -s ", ?MODULE, " slave_start ", node(), + " ", Waiter, + " ", PaPaths]))}. + + +%% This function will be invoked on the slave, using the -s option of erl. +%% It will wait for the master node to terminate. + +slave_start([Master, Waiter]) -> + spawn(?MODULE, wait_for_master_to_die, [Master, Waiter, silence]); +slave_start([Master, Waiter, Level]) -> + spawn(?MODULE, wait_for_master_to_die, [Master, Waiter, Level]). + + +wait_for_master_to_die(Master, Waiter, Level) -> + process_flag(trap_exit, true), + SName = lists:flatten( + io_lib:format("HDLT-SLAVE MASTER MONITOR[~p,~p,~p]", + [self(), node(), Master])), + ?SET_NAME(SName), + ?SET_LEVEL(Level), + erlang:monitor_node(Master, true), + {Waiter, Master} ! {self(), slave_started}, + wloop(Master). + +wloop(Master) -> + ?DEBUG("await message", []), + receive + {nodedown, Master} -> + ?INFO("received master nodedown", []), + halt(); + _Other -> + wloop(Master) + end. + + + diff --git a/lib/inets/examples/httpd_load_test/hdlt_ssl_client_cert.pem b/lib/inets/examples/httpd_load_test/hdlt_ssl_client_cert.pem new file mode 120000 index 0000000000..41644a1098 --- /dev/null +++ b/lib/inets/examples/httpd_load_test/hdlt_ssl_client_cert.pem @@ -0,0 +1 @@ +../../test/httpc_SUITE_data/ssl_client_cert.pem
\ No newline at end of file diff --git a/lib/inets/examples/httpd_load_test/hdlt_ssl_server_cert.pem b/lib/inets/examples/httpd_load_test/hdlt_ssl_server_cert.pem new file mode 120000 index 0000000000..41644a1098 --- /dev/null +++ b/lib/inets/examples/httpd_load_test/hdlt_ssl_server_cert.pem @@ -0,0 +1 @@ +../../test/httpc_SUITE_data/ssl_client_cert.pem
\ No newline at end of file diff --git a/lib/inets/examples/httpd_load_test/modules.mk b/lib/inets/examples/httpd_load_test/modules.mk new file mode 100644 index 0000000000..9d0d7103d5 --- /dev/null +++ b/lib/inets/examples/httpd_load_test/modules.mk @@ -0,0 +1,44 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode + +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + +SCRIPT_SKELETONS = \ + hdlt.sh.skel + +CONF_SKELETONS = \ + hdlt.config.skel + +CERT_FILES = \ + hdlt_ssl_client_cert.pem \ + hdlt_ssl_server_cert.pem + +README = HDLT_README + +MODULES = \ + hdlt \ + hdlt_ctrl \ + hdlt_client \ + hdlt_logger \ + hdlt_random_html \ + hdlt_server \ + hdlt_slave + +INTERNAL_HRL_FILES = \ + hdlt_logger.hrl + + diff --git a/lib/inets/examples/server_root/Makefile b/lib/inets/examples/server_root/Makefile new file mode 100644 index 0000000000..d7a3231068 --- /dev/null +++ b/lib/inets/examples/server_root/Makefile @@ -0,0 +1,209 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2010. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(INETS_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/inets-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +MODULE= + +AUTH_FILES = auth/group \ + auth/passwd +CGI_FILES = cgi-bin/printenv.sh +CONF_FILES = conf/8080.conf \ + conf/8888.conf \ + conf/httpd.conf \ + conf/ssl.conf \ + conf/mime.types +OPEN_FILES = htdocs/open/dummy.html +MNESIA_OPEN_FILES = htdocs/mnesia_open/dummy.html +MISC_FILES = htdocs/misc/friedrich.html \ + htdocs/misc/oech.html +SECRET_FILES = htdocs/secret/dummy.html +MNESIA_SECRET_FILES = htdocs/mnesia_secret/dummy.html +HTDOCS_FILES = htdocs/index.html \ + htdocs/config.shtml \ + htdocs/echo.shtml \ + htdocs/exec.shtml \ + htdocs/flastmod.shtml \ + htdocs/fsize.shtml \ + htdocs/include.shtml +ICON_FILES = icons/README \ + icons/a.gif \ + icons/alert.black.gif \ + icons/alert.red.gif \ + icons/apache_pb.gif \ + icons/back.gif \ + icons/ball.gray.gif \ + icons/ball.red.gif \ + icons/binary.gif \ + icons/binhex.gif \ + icons/blank.gif \ + icons/bomb.gif \ + icons/box1.gif \ + icons/box2.gif \ + icons/broken.gif \ + icons/burst.gif \ + icons/button1.gif \ + icons/button10.gif \ + icons/button2.gif \ + icons/button3.gif \ + icons/button4.gif \ + icons/button5.gif \ + icons/button6.gif \ + icons/button7.gif \ + icons/button8.gif \ + icons/button9.gif \ + icons/buttonl.gif \ + icons/buttonr.gif \ + icons/c.gif \ + icons/comp.blue.gif \ + icons/comp.gray.gif \ + icons/compressed.gif \ + icons/continued.gif \ + icons/dir.gif \ + icons/down.gif \ + icons/dvi.gif \ + icons/f.gif \ + icons/folder.gif \ + icons/folder.open.gif \ + icons/folder.sec.gif \ + icons/forward.gif \ + icons/generic.gif \ + icons/generic.red.gif \ + icons/generic.sec.gif \ + icons/hand.right.gif \ + icons/hand.up.gif \ + icons/htdig.gif \ + icons/icon.sheet.gif \ + icons/image1.gif \ + icons/image2.gif \ + icons/image3.gif \ + icons/index.gif \ + icons/layout.gif \ + icons/left.gif \ + icons/link.gif \ + icons/movie.gif \ + icons/p.gif \ + icons/patch.gif \ + icons/pdf.gif \ + icons/pie0.gif \ + icons/pie1.gif \ + icons/pie2.gif \ + icons/pie3.gif \ + icons/pie4.gif \ + icons/pie5.gif \ + icons/pie6.gif \ + icons/pie7.gif \ + icons/pie8.gif \ + icons/portal.gif \ + icons/poweredby.gif \ + icons/ps.gif \ + icons/quill.gif \ + icons/right.gif \ + icons/screw1.gif \ + icons/screw2.gif \ + icons/script.gif \ + icons/sound1.gif \ + icons/sound2.gif \ + icons/sphere1.gif \ + icons/sphere2.gif \ + icons/star.gif \ + icons/star_blank.gif \ + icons/tar.gif \ + icons/tex.gif \ + icons/text.gif \ + icons/transfer.gif \ + icons/unknown.gif \ + icons/up.gif \ + icons/uu.gif \ + icons/uuencoded.gif \ + icons/world1.gif \ + icons/world2.gif + +SSL_FILES = ssl/ssl_client.pem \ + ssl/ssl_server.pem + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_COMPILE_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +debug opt: + +clean: + +docs: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/auth + $(INSTALL_DATA) $(AUTH_FILES) $(RELSYSDIR)/examples/server_root/auth + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/cgi-bin + $(INSTALL_SCRIPT) $(CGI_FILES) $(RELSYSDIR)/examples/server_root/cgi-bin + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/conf + $(INSTALL_DATA) $(CONF_FILES) $(RELSYSDIR)/examples/server_root/conf + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/htdocs/open + $(INSTALL_DATA) $(OPEN_FILES) \ + $(RELSYSDIR)/examples/server_root/htdocs/open + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/htdocs/mnesia_open + $(INSTALL_DATA) $(MNESIA_OPEN_FILES) \ + $(RELSYSDIR)/examples/server_root/htdocs/mnesia_open + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/htdocs/misc + $(INSTALL_DATA) $(MISC_FILES) \ + $(RELSYSDIR)/examples/server_root/htdocs/misc + $(INSTALL_DIR) \ + $(RELSYSDIR)/examples/server_root/htdocs/secret/top_secret + $(INSTALL_DIR) \ + $(RELSYSDIR)/examples/server_root/htdocs/mnesia_secret/top_secret + $(INSTALL_DATA) $(SECRET_FILES) \ + $(RELSYSDIR)/examples/server_root/htdocs/secret + $(INSTALL_DATA) $(MNESIA_SECRET_FILES) \ + $(RELSYSDIR)/examples/server_root/htdocs/mnesia_secret + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/htdocs + $(INSTALL_DATA) $(HTDOCS_FILES) $(RELSYSDIR)/examples/server_root/htdocs + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/icons + $(INSTALL_DATA) $(ICON_FILES) $(RELSYSDIR)/examples/server_root/icons + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/ssl + $(INSTALL_DATA) $(SSL_FILES) $(RELSYSDIR)/examples/server_root/ssl + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/logs + +release_docs_spec: + diff --git a/lib/inets/examples/subdirs.mk b/lib/inets/examples/subdirs.mk new file mode 100644 index 0000000000..10a331fc26 --- /dev/null +++ b/lib/inets/examples/subdirs.mk @@ -0,0 +1,3 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode + +SUB_DIRECTORIES = server_root httpd_load_test
\ No newline at end of file diff --git a/lib/inets/src/ftp/Makefile b/lib/inets/src/ftp/Makefile index 0c15277a18..19b93870df 100644 --- a/lib/inets/src/ftp/Makefile +++ b/lib/inets/src/ftp/Makefile @@ -22,6 +22,7 @@ include $(ERL_TOP)/make/target.mk EBIN = ../../ebin include $(ERL_TOP)/make/$(TARGET)/otp.mk + # ---------------------------------------------------- # Application version # ---------------------------------------------------- @@ -29,6 +30,7 @@ include ../../vsn.mk VSN = $(INETS_VSN) + # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- @@ -52,24 +54,21 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) # ---------------------------------------------------- -# INETS FLAGS +# FLAGS # ---------------------------------------------------- -INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' + +include ../inets_app/inets.mk ifeq ($(FTP_DEBUG),true) INETS_FLAGS += -Dftp_debug endif +ERL_COMPILE_FLAGS += \ + $(INETS_FLAGS) \ + $(INETS_ERL_COMPILE_FLAGS) \ + -I../../include \ + -I../inets_app -# ---------------------------------------------------- -# FLAGS -# ---------------------------------------------------- -INETS_ERL_FLAGS += -I ../inets_app -pa ../../ebin - -ERL_COMPILE_FLAGS += $(INETS_ERL_FLAGS) \ - $(INETS_FLAGS) \ - +'{parse_transform,sys_pre_attributes}' \ - +'{attribute,insert,app_vsn,$(APP_VSN)}' # ---------------------------------------------------- # Targets @@ -89,9 +88,10 @@ docs: include $(ERL_TOP)/make/otp_release_targets.mk release_spec: opt - $(INSTALL_DIR) $(RELSYSDIR)/src - $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src - $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/src/ftp + $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/ftp + $(INSTALL_DIR) $(RELSYSDIR)/ebin $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin release_docs_spec: diff --git a/lib/inets/src/ftp/ftp.erl b/lib/inets/src/ftp/ftp.erl index 534fcae675..5ad74851c8 100644 --- a/lib/inets/src/ftp/ftp.erl +++ b/lib/inets/src/ftp/ftp.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -25,14 +25,12 @@ -behaviour(gen_server). -behaviour(inets_service). --deprecated({open, 3, next_major_release}). --deprecated({force_active, 1, next_major_release}). %% API - Client interface -export([cd/2, close/1, delete/2, formaterror/1, lcd/2, lpwd/1, ls/1, ls/2, mkdir/2, nlist/1, nlist/2, - open/1, open/2, open/3, force_active/1, + open/1, open/2, pwd/1, quote/2, recv/2, recv/3, recv_bin/2, recv_chunk_start/2, recv_chunk/1, @@ -133,11 +131,6 @@ open(Host, Port) when is_integer(Port) -> open(Host, [{port, Port}]); %% </BACKWARD-COMPATIBILLITY> -%% <BACKWARD-COMPATIBILLITY> -open(Host, [H|_] = Flags) when is_atom(H) -> - open(Host, ?FTP_PORT, Flags); -%% </BACKWARD-COMPATIBILLITY> - open(Host, Opts) when is_list(Opts) -> ?fcrt("open", [{host, Host}, {opts, Opts}]), try @@ -160,32 +153,6 @@ open(Host, Opts) when is_list(Opts) -> end. -%% <BACKWARD-COMPATIBILLITY> -open(Host, Port, Flags) when is_integer(Port) andalso is_list(Flags) -> - ?fcrt("open", [{host, Host}, {port, Port}, {flags, Flags}]), - try - {ok, StartOptions} = start_options([{flags, Flags}]), - ?fcrt("open", [{start_options, StartOptions}]), - {ok, OpenOptions} = open_options([{host, Host}, {port, Port}|Flags]), - ?fcrt("open", [{open_options, OpenOptions}]), - case ftp_sup:start_child([[{client, self()} | StartOptions], []]) of - {ok, Pid} -> - ?fcrt("open - ok", [{pid, Pid}]), - call(Pid, {open, ip_comm, OpenOptions}, plain); - Error1 -> - ?fcrt("open - error", [{error1, Error1}]), - Error1 - end - catch - throw:Error2 -> - Error2 - end. -%% </BACKWARD-COMPATIBILLITY> - - - - - %%-------------------------------------------------------------------------- %% user(Pid, User, Pass, <Acc>) -> ok | {error, euser} | {error, econn} %% | {error, eacct} @@ -528,16 +495,6 @@ close(Pid) -> cast(Pid, close), ok. -%%-------------------------------------------------------------------------- -%% force_active(Pid) -> ok -%% Pid = pid() -%% -%% Description: Force connection to use active mode. -%%-------------------------------------------------------------------------- -force_active(Pid) -> - error_logger:info_report("This function is deprecated use the mode flag " - "instead"), - call(Pid, force_active, atom). %%-------------------------------------------------------------------------- %% formaterror(Tag) -> string() @@ -886,9 +843,6 @@ handle_call({_, {open, ip_comm, Host, Opts}}, From, State) -> {stop, normal, State2#state{client = undefined}} end; -handle_call({_, force_active}, _, State) -> - {reply, ok, State#state{mode = active}}; - handle_call({_, {user, User, Password}}, From, #state{csock = CSock} = State) when (CSock =/= undefined) -> handle_user(User, Password, "", State#state{client = From}); diff --git a/lib/inets/src/ftp/ftp_internal.hrl b/lib/inets/src/ftp/ftp_internal.hrl index c3fa1e611d..148f8217ba 100644 --- a/lib/inets/src/ftp/ftp_internal.hrl +++ b/lib/inets/src/ftp/ftp_internal.hrl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -21,7 +21,8 @@ -ifndef(ftp_internal_hrl). -define(ftp_internal_hrl, true). --include("inets_internal.hrl"). +-include_lib("inets/src/inets_app/inets_internal.hrl"). + -define(SERVICE, ftpc). -define(fcri(Label, Content), ?report_important(Label, ?SERVICE, Content)). -define(fcrv(Label, Content), ?report_verbose(Label, ?SERVICE, Content)). diff --git a/lib/inets/src/http_client/Makefile b/lib/inets/src/http_client/Makefile index 628c91421f..575c6efaec 100644 --- a/lib/inets/src/http_client/Makefile +++ b/lib/inets/src/http_client/Makefile @@ -61,20 +61,17 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) # ---------------------------------------------------- -# INETS FLAGS -# ---------------------------------------------------- -INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' - - -# ---------------------------------------------------- # FLAGS # ---------------------------------------------------- -INETS_ERL_FLAGS += -I ../http_lib -I ../inets_app -pa ../../ebin -ERL_COMPILE_FLAGS += $(INETS_ERL_FLAGS) \ - $(INETS_FLAGS) \ - +'{parse_transform,sys_pre_attributes}' \ - +'{attribute,insert,app_vsn,$(APP_VSN)}' +include ../inets_app/inets.mk + +ERL_COMPILE_FLAGS += \ + $(INETS_FLAGS) \ + $(INETS_ERL_COMPILE_FLAGS) \ + -I../../include \ + -I../inets_app \ + -I../http_lib # ---------------------------------------------------- @@ -94,9 +91,10 @@ docs: include $(ERL_TOP)/make/otp_release_targets.mk release_spec: opt - $(INSTALL_DIR) $(RELSYSDIR)/src - $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src - $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/src/http_client + $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/http_client + $(INSTALL_DIR) $(RELSYSDIR)/ebin $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin release_docs_spec: diff --git a/lib/inets/src/http_client/http.erl b/lib/inets/src/http_client/http.erl index 7e1e90b50e..bbe2fec267 100644 --- a/lib/inets/src/http_client/http.erl +++ b/lib/inets/src/http_client/http.erl @@ -18,21 +18,38 @@ %% %% -%% Description: -%%% This version of the HTTP/1.1 client supports: -%%% - RFC 2616 HTTP 1.1 client part -%%% - RFC 2818 HTTP Over TLS +%%% Description: OLD API MODULE - USE httpc INSTEAD -module(http). -%% API --export([request/1, request/2, request/4, request/5, +-deprecated({request, 1, next_major_release}). +-deprecated({request, 2, next_major_release}). +-deprecated({request, 4, next_major_release}). +-deprecated({request, 5, next_major_release}). +-deprecated({cancel_request, 1, next_major_release}). +-deprecated({cancel_request, 2, next_major_release}). +-deprecated({set_option, 2, next_major_release}). +-deprecated({set_option, 3, next_major_release}). +-deprecated({set_options, 1, next_major_release}). +-deprecated({set_options, 2, next_major_release}). +-deprecated({verify_cookies, 2, next_major_release}). +-deprecated({verify_cookies, 3, next_major_release}). +-deprecated({cookie_header, 1, next_major_release}). +-deprecated({cookie_header, 2, next_major_release}). +-deprecated({stream_next, 1, next_major_release}). +-deprecated({default_profile, 0, next_major_release}). + +%% Deprecated +-export([ + request/1, request/2, request/4, request/5, cancel_request/1, cancel_request/2, set_option/2, set_option/3, set_options/1, set_options/2, - verify_cookies/2, verify_cookies/3, cookie_header/1, - cookie_header/2, stream_next/1, - default_profile/0]). + verify_cookies/2, verify_cookies/3, + cookie_header/1, cookie_header/2, + stream_next/1, + default_profile/0 + ]). %%%========================================================================= diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl index 6deeab6948..851364001c 100644 --- a/lib/inets/src/http_client/httpc.erl +++ b/lib/inets/src/http_client/httpc.erl @@ -48,7 +48,7 @@ stop_service/1, services/0, service_info/1]). --include("http_internal.hrl"). +-include_lib("inets/src/http_lib/http_internal.hrl"). -include("httpc_internal.hrl"). -define(DEFAULT_PROFILE, default). @@ -104,8 +104,14 @@ request(Url, Profile) -> %% HTTPOptions - [HttpOption] %% HTTPOption - {timeout, Time} | {connect_timeout, Time} | %% {ssl, SSLOptions} | {proxy_auth, {User, Password}} -%% Ssloptions = [SSLOption] -%% SSLOption = {verify, code()} | {depth, depth()} | {certfile, path()} | +%% Ssloptions = ssl_options() | +%% {ssl, ssl_options()} | +%% {ossl, ssl_options()} | +%% {essl, ssl_options()} +%% ssl_options() = [ssl_option()] +%% ssl_option() = {verify, code()} | +%% {depth, depth()} | +%% {certfile, path()} | %% {keyfile, path()} | {password, string()} | {cacertfile, path()} | %% {ciphers, string()} %% Options - [Option] @@ -579,7 +585,13 @@ http_options_default() -> error end, SslPost = fun(Value) when is_list(Value) -> - {ok, Value}; + {ok, {?HTTP_DEFAULT_SSL_KIND, Value}}; + ({ssl, SslOptions}) when is_list(SslOptions) -> + {ok, {?HTTP_DEFAULT_SSL_KIND, SslOptions}}; + ({ossl, SslOptions}) when is_list(SslOptions) -> + {ok, {ossl, SslOptions}}; + ({essl, SslOptions}) when is_list(SslOptions) -> + {ok, {essl, SslOptions}}; (_) -> error end, @@ -604,14 +616,14 @@ http_options_default() -> error end, [ - {version, {value, "HTTP/1.1"}, #http_options.version, VersionPost}, - {timeout, {value, ?HTTP_REQUEST_TIMEOUT}, #http_options.timeout, TimeoutPost}, - {autoredirect, {value, true}, #http_options.autoredirect, AutoRedirectPost}, - {ssl, {value, []}, #http_options.ssl, SslPost}, - {proxy_auth, {value, undefined}, #http_options.proxy_auth, ProxyAuthPost}, - {relaxed, {value, false}, #http_options.relaxed, RelaxedPost}, - %% this field has to be *after* the timeout field (as that field is used for the default value) - {connect_timeout, {field, #http_options.timeout}, #http_options.connect_timeout, ConnTimeoutPost} + {version, {value, "HTTP/1.1"}, #http_options.version, VersionPost}, + {timeout, {value, ?HTTP_REQUEST_TIMEOUT}, #http_options.timeout, TimeoutPost}, + {autoredirect, {value, true}, #http_options.autoredirect, AutoRedirectPost}, + {ssl, {value, {?HTTP_DEFAULT_SSL_KIND, []}}, #http_options.ssl, SslPost}, + {proxy_auth, {value, undefined}, #http_options.proxy_auth, ProxyAuthPost}, + {relaxed, {value, false}, #http_options.relaxed, RelaxedPost}, + %% this field has to be *after* the timeout option (as that field is used for the default value) + {connect_timeout, {field, #http_options.timeout}, #http_options.connect_timeout, ConnTimeoutPost} ]. diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl index 5e79d874fb..c34b641b7b 100644 --- a/lib/inets/src/http_client/httpc_handler.erl +++ b/lib/inets/src/http_client/httpc_handler.erl @@ -22,8 +22,8 @@ -behaviour(gen_server). +-include_lib("inets/src/http_lib/http_internal.hrl"). -include("httpc_internal.hrl"). --include("http_internal.hrl"). %%-------------------------------------------------------------------- @@ -177,8 +177,8 @@ stream(BodyPart, Request = #request{stream = Self}, Code) stream(BodyPart, Request = #request{stream = Self}, 404) when (Self =:= self) orelse (Self =:= {self, once}) -> ?hcrt("stream - self with 404", [{stream, Self}]), - httpc_response:send(Request#request.from, - {Request#request.id, stream, BodyPart}), + httpc_response:send(Request#request.from, + {Request#request.id, stream, BodyPart}), {<<>>, Request}; %% Stream to file @@ -286,8 +286,7 @@ handle_call({connect_and_send, #request{address = Address0, handle_call(#request{address = Addr} = Request, _, #state{status = Status, - session = #tcp_session{socket = Socket, - type = pipeline} = Session, + session = #session{type = pipeline} = Session, timers = Timers, options = #options{proxy = Proxy} = _Options, profile_name = ProfileName} = State) @@ -301,7 +300,7 @@ handle_call(#request{address = Addr} = Request, _, Address = handle_proxy(Addr, Proxy), - case httpc_request:send(Address, Request, Socket) of + case httpc_request:send(Address, Session, Request) of ok -> ?hcrd("request sent", []), @@ -320,10 +319,10 @@ handle_call(#request{address = Addr} = Request, _, NewTimers = NewState#state.timers, NewPipeline = queue:in(Request, State#state.pipeline), NewSession = - Session#tcp_session{queue_length = - %% Queue + current - queue:len(NewPipeline) + 1, - client_close = ClientClose}, + Session#session{queue_length = + %% Queue + current + queue:len(NewPipeline) + 1, + client_close = ClientClose}, httpc_manager:insert_session(NewSession, ProfileName), ?hcrd("session updated", []), {reply, ok, State#state{pipeline = NewPipeline, @@ -336,8 +335,8 @@ handle_call(#request{address = Addr} = Request, _, cancel_timer(Timers#timers.queue_timer, timeout_queue), NewSession = - Session#tcp_session{queue_length = 1, - client_close = ClientClose}, + Session#session{queue_length = 1, + client_close = ClientClose}, httpc_manager:insert_session(NewSession, ProfileName), Relaxed = (Request#request.settings)#http_options.relaxed, @@ -357,8 +356,7 @@ handle_call(#request{address = Addr} = Request, _, handle_call(#request{address = Addr} = Request, _, #state{status = Status, - session = #tcp_session{socket = Socket, - type = keep_alive} = Session, + session = #session{type = keep_alive} = Session, timers = Timers, options = #options{proxy = Proxy} = _Options, profile_name = ProfileName} = State) @@ -370,7 +368,7 @@ handle_call(#request{address = Addr} = Request, _, {status, Status}]), Address = handle_proxy(Addr, Proxy), - case httpc_request:send(Address, Request, Socket) of + case httpc_request:send(Address, Session, Request) of ok -> ?hcrd("request sent", []), @@ -389,10 +387,10 @@ handle_call(#request{address = Addr} = Request, _, NewTimers = NewState#state.timers, NewKeepAlive = queue:in(Request, State#state.keep_alive), NewSession = - Session#tcp_session{queue_length = - %% Queue + current - queue:len(NewKeepAlive) + 1, - client_close = ClientClose}, + Session#session{queue_length = + %% Queue + current + queue:len(NewKeepAlive) + 1, + client_close = ClientClose}, httpc_manager:insert_session(NewSession, ProfileName), ?hcrd("session updated", []), {reply, ok, State#state{keep_alive = NewKeepAlive, @@ -405,8 +403,8 @@ handle_call(#request{address = Addr} = Request, _, cancel_timer(Timers#timers.queue_timer, timeout_queue), NewSession = - Session#tcp_session{queue_length = 1, - client_close = ClientClose}, + Session#session{queue_length = 1, + client_close = ClientClose}, httpc_manager:insert_session(NewSession, ProfileName), Relaxed = (Request#request.settings)#http_options.relaxed, @@ -589,13 +587,13 @@ handle_info({ssl_closed, _}, State = #state{request = undefined}) -> %%% Error cases handle_info({tcp_closed, _}, #state{session = Session0} = State) -> - Socket = Session0#tcp_session.socket, - Session = Session0#tcp_session{socket = {remote_close, Socket}}, + Socket = Session0#session.socket, + Session = Session0#session{socket = {remote_close, Socket}}, %% {stop, session_remotly_closed, State}; {stop, normal, State#state{session = Session}}; handle_info({ssl_closed, _}, #state{session = Session0} = State) -> - Socket = Session0#tcp_session.socket, - Session = Session0#tcp_session{socket = {remote_close, Socket}}, + Socket = Session0#session.socket, + Session = Session0#session{socket = {remote_close, Socket}}, %% {stop, session_remotly_closed, State}; {stop, normal, State#state{session = Session}}; handle_info({tcp_error, _, _} = Reason, State) -> @@ -699,19 +697,18 @@ terminate(normal, #state{session = undefined}) -> %% Init error sending, no session information has been setup but %% there is a socket that needs closing. terminate(normal, - #state{request = Request, - session = #tcp_session{id = undefined, - socket = Socket}}) -> - http_transport:close(socket_type(Request), Socket); + #state{session = #session{id = undefined} = Session}) -> + close_socket(Session); %% Socket closed remotely terminate(normal, - #state{session = #tcp_session{socket = {remote_close, Socket}, - id = Id}, + #state{session = #session{socket = {remote_close, Socket}, + socket_type = SocketType, + id = Id}, profile_name = ProfileName, - request = Request, - timers = Timers, - pipeline = Pipeline}) -> + request = Request, + timers = Timers, + pipeline = Pipeline}) -> ?hcrt("terminate(normal) - remote close", [{id, Id}, {profile, ProfileName}]), @@ -728,11 +725,11 @@ terminate(normal, deliver_answers([Request | queue:to_list(Pipeline)]), %% And, just in case, close our side (**really** overkill) - http_transport:close(socket_type(Request), Socket); + http_transport:close(SocketType, Socket); -terminate(_, #state{session = #tcp_session{id = Id, - socket = Socket, - scheme = Scheme}, +terminate(_, #state{session = #session{id = Id, + socket = Socket, + socket_type = SocketType}, request = undefined, profile_name = ProfileName, timers = Timers, @@ -744,7 +741,7 @@ terminate(_, #state{session = #tcp_session{id = Id, maybe_retry_queue(KeepAlive, State), cancel_timer(Timers#timers.queue_timer, timeout_queue), - http_transport:close(socket_type(Scheme), Socket); + http_transport:close(SocketType, Socket); terminate(Reason, #state{request = undefined}) -> ?hcrt("terminate", [{reason, Reason}]), @@ -878,22 +875,23 @@ connect_and_send_first_request(Address, ConnTimeout = Settings#http_options.connect_timeout, case connect(SocketType, Address, Options, ConnTimeout) of {ok, Socket} -> + Session = #session{id = {OrigAddress, self()}, + scheme = Scheme, + socket = Socket, + socket_type = SocketType}, ?hcrd("connected - now send first request", [{socket, Socket}]), - case httpc_request:send(Address, Request, Socket) of + case httpc_request:send(Address, Session, Request) of ok -> ?hcrd("first request sent", []), ClientClose = httpc_request:is_client_closing(Headers), SessionType = httpc_manager:session_type(Options), - Session = - #tcp_session{id = {OrigAddress, self()}, - scheme = Scheme, - socket = Socket, - client_close = ClientClose, - type = SessionType}, + Session2 = + Session#session{client_close = ClientClose, + type = SessionType}, TmpState = State#state{request = Request, - session = Session, + session = Session2, mfa = init_mfa(Request, State), status_line = init_status_line(Request), headers = undefined, @@ -947,21 +945,20 @@ handler_info(#state{request = Request, ?hcrt("handler info", [{request_info, RequestInfo}]), %% Info about the current session/socket - SessionType = Session#tcp_session.type, - QueueLen = case Session#tcp_session.type of + SessionType = Session#session.type, + QueueLen = case SessionType of pipeline -> queue:len(Pipeline); keep_alive -> queue:len(KeepAlive) end, - Socket = Session#tcp_session.socket, - Scheme = Session#tcp_session.scheme, - SocketType = socket_type(Scheme), + Scheme = Session#session.scheme, + Socket = Session#session.socket, + SocketType = Session#session.socket_type, ?hcrt("handler info", [{session_type, SessionType}, {queue_length, QueueLen}, {scheme, Scheme}, - {socket_type, SocketType}, {socket, Socket}]), SocketOpts = http_transport:getopts(SocketType, Socket), @@ -1118,9 +1115,7 @@ handle_response(#state{request = Request, ?hcrd("handle response - continue", []), %% Send request body {_, RequestBody} = Request#request.content, - http_transport:send(socket_type(Session#tcp_session.scheme), - Session#tcp_session.socket, - RequestBody), + send_raw(Session, RequestBody), %% Wait for next response activate_once(Session), Relaxed = (Request#request.settings)#http_options.relaxed, @@ -1217,7 +1212,7 @@ handle_pipeline(#state{status = pipeline, %% If a pipeline that has been idle for some time is not %% closed by the server, the client may want to close it. NewState = activate_queue_timeout(TimeOut, State), - NewSession = Session#tcp_session{queue_length = 0}, + NewSession = Session#session{queue_length = 0}, httpc_manager:insert_session(NewSession, ProfileName), %% Note mfa will be initilized when a new request %% arrives. @@ -1239,9 +1234,9 @@ handle_pipeline(#state{status = pipeline, false -> ?hcrv("next request", [{request, NextRequest}]), NewSession = - Session#tcp_session{queue_length = - %% Queue + current - queue:len(Pipeline) + 1}, + Session#session{queue_length = + %% Queue + current + queue:len(Pipeline) + 1}, httpc_manager:insert_session(NewSession, ProfileName), Relaxed = (NextRequest#request.settings)#http_options.relaxed, @@ -1290,16 +1285,16 @@ handle_keep_alive_queue( %% If a keep_alive session has been idle for some time is not %% closed by the server, the client may want to close it. NewState = activate_queue_timeout(TimeOut, State), - NewSession = Session#tcp_session{queue_length = 0}, + NewSession = Session#session{queue_length = 0}, httpc_manager:insert_session(NewSession, ProfileName), %% Note mfa will be initilized when a new request %% arrives. {noreply, - NewState#state{request = undefined, - mfa = undefined, + NewState#state{request = undefined, + mfa = undefined, status_line = undefined, - headers = undefined, - body = undefined + headers = undefined, + body = undefined } }; {{value, NextRequest}, KeepAlive} -> @@ -1342,10 +1337,12 @@ case_insensitive_header(Str) when is_list(Str) -> case_insensitive_header(Str) -> Str. -activate_once(#tcp_session{scheme = Scheme, socket = Socket}) -> - SocketType = socket_type(Scheme), +activate_once(#session{socket = Socket, socket_type = SocketType}) -> http_transport:setopts(SocketType, Socket, [{active, once}]). +close_socket(#session{socket = Socket, socket_type = SocketType}) -> + http_transport:close(SocketType, Socket). + activate_request_timeout( #state{request = #request{timer = undefined} = Request} = State) -> Timeout = (Request#request.settings)#http_options.timeout, @@ -1378,7 +1375,7 @@ activate_queue_timeout(Time, State) -> State#state{timers = #timers{queue_timer = Ref}}. -is_pipeline_enabled_client(#tcp_session{type = pipeline}) -> +is_pipeline_enabled_client(#session{type = pipeline}) -> true; is_pipeline_enabled_client(_) -> false. @@ -1391,7 +1388,7 @@ is_keep_alive_enabled_server("HTTP/1.0", is_keep_alive_enabled_server(_,_) -> false. -is_keep_alive_connection(Headers, #tcp_session{client_close = ClientClose}) -> +is_keep_alive_connection(Headers, #session{client_close = ClientClose}) -> (not ((ClientClose) orelse httpc_response:is_server_closing(Headers))). try_to_enable_pipeline_or_keep_alive( @@ -1416,7 +1413,7 @@ try_to_enable_pipeline_or_keep_alive( httpc_manager:insert_session(Session, ProfileName), %% Make sure type is keep_alive in session %% as it in this case might be pipeline - NewSession = Session#tcp_session{type = keep_alive}, + NewSession = Session#session{type = keep_alive}, State#state{status = keep_alive, session = NewSession} end; @@ -1551,11 +1548,11 @@ init_status_line(#request{settings = Settings}) -> socket_type(#request{scheme = http}) -> ip_comm; socket_type(#request{scheme = https, settings = Settings}) -> - {ssl, Settings#http_options.ssl}; -socket_type(http) -> - ip_comm; -socket_type(https) -> - {ssl, []}. %% Dummy value ok for ex setopts that does not use this value + Settings#http_options.ssl. +%% socket_type(http) -> +%% ip_comm; +%% socket_type(https) -> +%% {ssl1, []}. %% Dummy value ok for ex setopts that does not use this value start_stream({_Version, _Code, _ReasonPhrase}, _Headers, #request{stream = none} = Request) -> @@ -1624,18 +1621,15 @@ end_stream(SL, R) -> next_body_chunk(#state{request = #request{stream = {self, once}}, - once = once, session = Session} = State) -> - http_transport:setopts(socket_type(Session#tcp_session.scheme), - Session#tcp_session.socket, - [{active, once}]), + once = once, + session = Session} = State) -> + activate_once(Session), State#state{once = inactive}; next_body_chunk(#state{request = #request{stream = {self, once}}, once = inactive} = State) -> State; %% Wait for user to call stream_next next_body_chunk(#state{session = Session} = State) -> - http_transport:setopts(socket_type(Session#tcp_session.scheme), - Session#tcp_session.socket, - [{active, once}]), + activate_once(Session), State. handle_verbose(verbose) -> @@ -1712,6 +1706,11 @@ handle_verbose(_) -> %% ok. +send_raw(#session{socket = Socket, socket_type = SocketType}, Body) -> + http_transport:send(SocketType, Socket, Body). + + + call(Msg, Pid) -> Timeout = infinity, call(Msg, Pid, Timeout). diff --git a/lib/inets/src/http_client/httpc_internal.hrl b/lib/inets/src/http_client/httpc_internal.hrl index 4d76c4beb3..3cdd95a02b 100644 --- a/lib/inets/src/http_client/httpc_internal.hrl +++ b/lib/inets/src/http_client/httpc_internal.hrl @@ -18,7 +18,11 @@ %% %% --include("inets_internal.hrl"). +-ifndef(httpc_internal_hrl). +-define(httpc_internal_hrl, true). + +-include_lib("inets/src/inets_app/inets_internal.hrl"). + -define(SERVICE, httpc). -define(hcri(Label, Data), ?report_important(Label, ?SERVICE, Data)). -define(hcrv(Label, Data), ?report_verbose(Label, ?SERVICE, Data)). @@ -104,13 +108,14 @@ } ). --record(tcp_session, +-record(session, { id, % {{Host, Port}, HandlerPid} client_close, % true | false scheme, % http (HTTP/TCP) | https (HTTP/SSL/TCP) socket, % Open socket, used by connection - queue_length = 1, % Current length of pipeline or keep alive queue + socket_type, % socket-type, used by connection + queue_length = 1, % Current length of pipeline or keep-alive queue type % pipeline | keep_alive (wait for response before sending new request) }). @@ -138,3 +143,6 @@ %% path, % string() %% q % query: string() %% }). + + +-endif. % -ifdef(httpc_internal_hrl). diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl index b278077a66..d5d6376369 100644 --- a/lib/inets/src/http_client/httpc_manager.erl +++ b/lib/inets/src/http_client/httpc_manager.erl @@ -21,8 +21,8 @@ -behaviour(gen_server). +-include_lib("inets/src/http_lib/http_internal.hrl"). -include("httpc_internal.hrl"). --include("http_internal.hrl"). %% Internal Application API -export([ @@ -333,7 +333,7 @@ do_init(ProfileName, CookiesDir) -> ?hcrt("create session db", []), SessionDbName = session_db_name(ProfileName), ets:new(SessionDbName, - [public, set, named_table, {keypos, #tcp_session.id}]), + [public, set, named_table, {keypos, #session.id}]), %% Create handler db ?hcrt("create handler/request db", []), @@ -876,12 +876,12 @@ select_session(Method, HostPort, Scheme, SessionType, %% client_close, scheme and type specified. %% The fields id (part of: HandlerPid) and queue_length %% specified. - Pattern = #tcp_session{id = {HostPort, '$1'}, - client_close = false, - scheme = Scheme, - socket = '_', - queue_length = '$2', - type = SessionType}, + Pattern = #session{id = {HostPort, '$1'}, + client_close = false, + scheme = Scheme, + queue_length = '$2', + type = SessionType, + _ = '_'}, %% {'_', {HostPort, '$1'}, false, Scheme, '_', '$2', SessionTyp}, Candidates = ets:match(SessionDb, Pattern), ?hcrd("select session", [{host_port, HostPort}, diff --git a/lib/inets/src/http_client/httpc_request.erl b/lib/inets/src/http_client/httpc_request.erl index 55e0af4b42..d4df97ad40 100644 --- a/lib/inets/src/http_client/httpc_request.erl +++ b/lib/inets/src/http_client/httpc_request.erl @@ -19,12 +19,13 @@ -module(httpc_request). --include("http_internal.hrl"). +-include_lib("inets/src/http_lib/http_internal.hrl"). -include("httpc_internal.hrl"). %%% Internal API -export([send/3, is_idempotent/1, is_client_closing/1]). + %%%========================================================================= %%% Internal application API %%%========================================================================= @@ -39,10 +40,9 @@ %% %% Description: Composes and sends a HTTP-request. %%------------------------------------------------------------------------- -send(SendAddr, #request{scheme = Scheme, socket_opts = SocketOpts} = Request, - Socket) +send(SendAddr, #session{socket = Socket, socket_type = SocketType}, + #request{socket_opts = SocketOpts} = Request) when is_list(SocketOpts) -> - SocketType = socket_type(Scheme), case http_transport:setopts(SocketType, Socket, SocketOpts) of ok -> send(SendAddr, Socket, SocketType, @@ -50,8 +50,7 @@ send(SendAddr, #request{scheme = Scheme, socket_opts = SocketOpts} = Request, {error, Reason} -> {error, {setopts_failed, Reason}} end; -send(SendAddr, #request{scheme = Scheme} = Request, Socket) -> - SocketType = socket_type(Scheme), +send(SendAddr, #session{socket = Socket, socket_type = SocketType}, Request) -> send(SendAddr, Socket, SocketType, Request). send(SendAddr, Socket, SocketType, @@ -209,10 +208,6 @@ headers(_, "HTTP/0.9") -> headers(Headers, _) -> Headers. -socket_type(http) -> - ip_comm; -socket_type(https) -> - {ssl, []}. http_headers([], Headers) -> lists:flatten(Headers); diff --git a/lib/inets/src/http_client/httpc_response.erl b/lib/inets/src/http_client/httpc_response.erl index df7d40a33e..bb9c516259 100644 --- a/lib/inets/src/http_client/httpc_response.erl +++ b/lib/inets/src/http_client/httpc_response.erl @@ -19,7 +19,7 @@ -module(httpc_response). --include("http_internal.hrl"). +-include_lib("inets/src/http_lib/http_internal.hrl"). -include("httpc_internal.hrl"). %% API diff --git a/lib/inets/src/http_lib/Makefile b/lib/inets/src/http_lib/Makefile index 7f4c92861c..5dac3b0c00 100644 --- a/lib/inets/src/http_lib/Makefile +++ b/lib/inets/src/http_lib/Makefile @@ -55,24 +55,16 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) # ---------------------------------------------------- -# INETS FLAGS -# ---------------------------------------------------- -INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' - - -# ---------------------------------------------------- # FLAGS # ---------------------------------------------------- -INETS_ERL_FLAGS += -I ../inets_app -ifeq ($(WARN_UNUSED_WARS),true) -ERL_COMPILE_FLAGS += +warn_unused_vars -endif +include ../inets_app/inets.mk -ERL_COMPILE_FLAGS += $(INETS_ERL_FLAGS) \ - $(INETS_FLAGS) \ - +'{parse_transform,sys_pre_attributes}' \ - +'{attribute,insert,app_vsn,$(APP_VSN)}' +ERL_COMPILE_FLAGS += \ + $(INETS_FLAGS) \ + $(INETS_ERL_COMPILE_FLAGS) \ + -I../../include \ + -I../inets_app # ---------------------------------------------------- @@ -94,9 +86,10 @@ docs: include $(ERL_TOP)/make/otp_release_targets.mk release_spec: opt - $(INSTALL_DIR) $(RELSYSDIR)/src - $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src - $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/src/http_lib + $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/http_lib + $(INSTALL_DIR) $(RELSYSDIR)/ebin $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin release_docs_spec: diff --git a/lib/inets/src/http_lib/http_internal.hrl b/lib/inets/src/http_lib/http_internal.hrl index bb2e831727..5440f214b5 100644 --- a/lib/inets/src/http_lib/http_internal.hrl +++ b/lib/inets/src/http_lib/http_internal.hrl @@ -1,28 +1,37 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2002-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2002-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% --include("inets_internal.hrl"). +-ifndef(http_internal_hrl). +-define(http_internal_hrl, true). --define(HTTP_MAX_BODY_SIZE, nolimit). +-include_lib("inets/src/inets_app/inets_internal.hrl"). + +-define(HTTP_MAX_BODY_SIZE, nolimit). -define(HTTP_MAX_HEADER_SIZE, 10240). --define(HTTP_MAX_URI_SIZE, nolimit). +-define(HTTP_MAX_URI_SIZE, nolimit). + +-ifndef(HTTP_DEFAULT_SSL_KIND). +-define(HTTP_DEFAULT_SSL_KIND, ossl). +%% -define(HTTP_DEFAULT_SSL_KIND, essl). +-endif. % -ifdef(HTTP_DEFAULT_SSL_KIND). + %%% Response headers -record(http_response_h,{ @@ -106,3 +115,5 @@ 'last-modified', other=[] % list() - Key/Value list with other headers }). + +-endif. % -ifdef(http_internal_hrl). diff --git a/lib/inets/src/http_lib/http_transport.erl b/lib/inets/src/http_lib/http_transport.erl index 7c2ac626e6..b8121852b8 100644 --- a/lib/inets/src/http_lib/http_transport.erl +++ b/lib/inets/src/http_lib/http_transport.erl @@ -36,7 +36,9 @@ -export([negotiate/3]). --include("inets_internal.hrl"). +-include_lib("inets/src/inets_app/inets_internal.hrl"). +-include("http_internal.hrl"). + -define(SERVICE, httpl). -define(hlri(Label, Content), ?report_important(Label, ?SERVICE, Content)). -define(hlrv(Label, Content), ?report_verbose(Label, ?SERVICE, Content)). @@ -55,6 +57,18 @@ %% Description: Makes sure inet_db or ssl is started. %%------------------------------------------------------------------------- start(ip_comm) -> + do_start_ip_comm(); + +%% This is just for backward compatibillity +start({ssl, _}) -> + do_start_ssl(); +start({ossl, _}) -> + do_start_ssl(); +start({essl, _}) -> + do_start_ssl(). + + +do_start_ip_comm() -> case inet_db:start() of {ok, _} -> ok; @@ -62,8 +76,9 @@ start(ip_comm) -> ok; Error -> Error - end; -start({ssl, _}) -> + end. + +do_start_ssl() -> case ssl:start() of ok -> ok; @@ -97,18 +112,26 @@ connect(ip_comm = _SocketType, {Host, Port}, Opts0, Timeout) [{host, Host}, {port, Port}, {opts, Opts}, {timeout, Timeout}]), gen_tcp:connect(Host, Port, Opts, Timeout); -connect({ssl, SslConfig}, {Host, Port}, _, Timeout) -> - Opts = [binary, {active, false}] ++ SslConfig, - ?hlrt("connect using ssl", - [{host, Host}, {port, Port}, {ssl_config, SslConfig}, - {timeout, Timeout}]), +%% Wrapper for backaward compatibillity +connect({ssl, SslConfig}, Address, Opts, Timeout) -> + connect({?HTTP_DEFAULT_SSL_KIND, SslConfig}, Address, Opts, Timeout); + +connect({ossl, SslConfig}, {Host, Port}, _, Timeout) -> + Opts = [binary, {active, false}, {ssl_imp, old}] ++ SslConfig, + ?hlrt("connect using ossl", + [{host, Host}, + {port, Port}, + {ssl_config, SslConfig}, + {timeout, Timeout}]), ssl:connect(Host, Port, Opts, Timeout); -connect({erl_ssl, SslConfig}, {Host, Port}, _, Timeout) -> +connect({essl, SslConfig}, {Host, Port}, _, Timeout) -> Opts = [binary, {active, false}, {ssl_imp, new}] ++ SslConfig, - ?hlrt("connect using erl_ssl", - [{host, Host}, {port, Port}, {ssl_config, SslConfig}, - {timeout, Timeout}]), + ?hlrt("connect using essl", + [{host, Host}, + {port, Port}, + {ssl_config, SslConfig}, + {timeout, Timeout}]), ssl:connect(Host, Port, Opts, Timeout). @@ -136,13 +159,32 @@ listen(ip_comm, Addr, Port) -> Else end; -listen({ssl, SSLConfig} = Ssl, Addr, Port) -> +%% Wrapper for backaward compatibillity +listen({ssl, SSLConfig}, Addr, Port) -> + ?hlrt("listen (wrapper)", + [{addr, Addr}, + {port, Port}, + {ssl_config, SSLConfig}]), + listen({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Addr, Port); + +listen({ossl, SSLConfig} = Ssl, Addr, Port) -> + ?hlrt("listen (ossl)", + [{addr, Addr}, + {port, Port}, + {ssl_config, SSLConfig}]), Opt = sock_opt(Ssl, Addr, SSLConfig), - ssl:listen(Port, Opt); - -listen({erl_ssl, SSLConfig} = Ssl, Addr, Port) -> + ?hlrt("listen options", [{opt, Opt}]), + ssl:listen(Port, [{ssl_imp, old} | Opt]); + +listen({essl, SSLConfig} = Ssl, Addr, Port) -> + ?hlrt("listen (essl)", + [{addr, Addr}, + {port, Port}, + {ssl_config, SSLConfig}]), Opt = sock_opt(Ssl, Addr, SSLConfig), - ssl:listen(Port, [{ssl_imp, new} | Opt]). + ?hlrt("listen options", [{opt, Opt}]), + Opt2 = [{ssl_imp, new}, {reuseaddr, true} | Opt], + ssl:listen(Port, Opt2). listen_ip_comm(Addr, Port) -> @@ -228,9 +270,17 @@ ip_family_of(IpFamilyStr) -> %%------------------------------------------------------------------------- accept(SocketType, ListenSocket) -> accept(SocketType, ListenSocket, infinity). + accept(ip_comm, ListenSocket, Timeout) -> gen_tcp:accept(ListenSocket, Timeout); -accept({ssl,_SSLConfig}, ListenSocket, Timeout) -> + +%% Wrapper for backaward compatibillity +accept({ssl, SSLConfig}, ListenSocket, Timeout) -> + accept({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, ListenSocket, Timeout); + +accept({ossl, _SSLConfig}, ListenSocket, Timeout) -> + ssl:transport_accept(ListenSocket, Timeout); +accept({essl, _SSLConfig}, ListenSocket, Timeout) -> ssl:transport_accept(ListenSocket, Timeout). @@ -244,7 +294,15 @@ accept({ssl,_SSLConfig}, ListenSocket, Timeout) -> %%------------------------------------------------------------------------- controlling_process(ip_comm, Socket, NewOwner) -> gen_tcp:controlling_process(Socket, NewOwner); -controlling_process({ssl, _}, Socket, NewOwner) -> + +%% Wrapper for backaward compatibillity +controlling_process({ssl, SSLConfig}, Socket, NewOwner) -> + controlling_process({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket, NewOwner); + +controlling_process({ossl, _}, Socket, NewOwner) -> + ssl:controlling_process(Socket, NewOwner); + +controlling_process({essl, _}, Socket, NewOwner) -> ssl:controlling_process(Socket, NewOwner). @@ -259,9 +317,23 @@ controlling_process({ssl, _}, Socket, NewOwner) -> setopts(ip_comm, Socket, Options) -> ?hlrt("ip_comm setopts", [{socket, Socket}, {options, Options}]), inet:setopts(Socket, Options); -setopts({ssl, _}, Socket, Options) -> - ?hlrt("ssl setopts", [{socket, Socket}, {options, Options}]), - ssl:setopts(Socket, Options). + +%% Wrapper for backaward compatibillity +setopts({ssl, SSLConfig}, Socket, Options) -> + setopts({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket, Options); + +setopts({ossl, _}, Socket, Options) -> + ?hlrt("[o]ssl setopts", [{socket, Socket}, {options, Options}]), + Reason = (catch ssl:setopts(Socket, Options)), + ?hlrt("[o]ssl setopts result", [{reason, Reason}]), + Reason; + + +setopts({essl, _}, Socket, Options) -> + ?hlrt("[e]ssl setopts", [{socket, Socket}, {options, Options}]), + Reason = (catch ssl:setopts(Socket, Options)), + ?hlrt("[e]ssl setopts result", [{reason, Reason}]), + Reason. %%------------------------------------------------------------------------- @@ -283,15 +355,27 @@ getopts(ip_comm, Socket, Options) -> {error, _} -> [] end; -getopts({ssl, _}, Socket, Options) -> + +%% Wrapper for backaward compatibillity +getopts({ssl, SSLConfig}, Socket, Options) -> + getopts({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket, Options); + +getopts({ossl, _}, Socket, Options) -> ?hlrt("ssl getopts", [{socket, Socket}, {options, Options}]), + getopts_ssl(Socket, Options); + +getopts({essl, _}, Socket, Options) -> + ?hlrt("essl getopts", [{socket, Socket}, {options, Options}]), + getopts_ssl(Socket, Options). + +getopts_ssl(Socket, Options) -> case ssl:getopts(Socket, Options) of {ok, SocketOpts} -> SocketOpts; {error, _} -> [] end. - + %%------------------------------------------------------------------------- %% getstat(SocketType, Socket) -> socket_stats() @@ -308,8 +392,15 @@ getstat(ip_comm = _SocketType, Socket) -> {error, _} -> [] end; -getstat({ssl, _} = _SocketType, _Socket) -> - %% ?hlrt("ssl getstat", [{socket, Socket}]), + +%% Wrapper for backaward compatibillity +getstat({ssl, SSLConfig}, Socket) -> + getstat({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket); + +getstat({ossl, _} = _SocketType, _Socket) -> + []; + +getstat({essl, _} = _SocketType, _Socket) -> []. @@ -322,7 +413,15 @@ getstat({ssl, _} = _SocketType, _Socket) -> %%------------------------------------------------------------------------- send(ip_comm, Socket, Message) -> gen_tcp:send(Socket, Message); -send({ssl, _}, Socket, Message) -> + +%% Wrapper for backaward compatibillity +send({ssl, SSLConfig}, Socket, Message) -> + send({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket, Message); + +send({ossl, _}, Socket, Message) -> + ssl:send(Socket, Message); + +send({essl, _}, Socket, Message) -> ssl:send(Socket, Message). @@ -335,9 +434,18 @@ send({ssl, _}, Socket, Message) -> %%------------------------------------------------------------------------- close(ip_comm, Socket) -> gen_tcp:close(Socket); -close({ssl, _}, Socket) -> + +%% Wrapper for backaward compatibillity +close({ssl, SSLConfig}, Socket) -> + close({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket); + +close({ossl, _}, Socket) -> + ssl:close(Socket); + +close({essl, _}, Socket) -> ssl:close(Socket). + %%------------------------------------------------------------------------- %% peername(SocketType, Socket) -> {Port, SockName} %% SocketType = ip_comm | {ssl, _} @@ -368,7 +476,17 @@ peername(ip_comm, Socket) -> {-1, "unknown"} end; -peername({ssl, _}, Socket) -> +%% Wrapper for backaward compatibillity +peername({ssl, SSLConfig}, Socket) -> + peername({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket); + +peername({ossl, _}, Socket) -> + peername_ssl(Socket); + +peername({essl, _}, Socket) -> + peername_ssl(Socket). + +peername_ssl(Socket) -> case ssl:peername(Socket) of {ok,{{A, B, C, D}, Port}} -> PeerName = integer_to_list(A)++"."++integer_to_list(B)++"."++ @@ -409,7 +527,17 @@ sockname(ip_comm, Socket) -> {-1, "unknown"} end; -sockname({ssl, _}, Socket) -> +%% Wrapper for backaward compatibillity +sockname({ssl, SSLConfig}, Socket) -> + sockname({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket); + +sockname({ossl, _}, Socket) -> + sockname_ssl(Socket); + +sockname({essl, _}, Socket) -> + sockname_ssl(Socket). + +sockname_ssl(Socket) -> case ssl:sockname(Socket) of {ok,{{A, B, C, D}, Port}} -> SockName = integer_to_list(A)++"."++integer_to_list(B)++"."++ @@ -455,22 +583,31 @@ sock_opt2(Opts) -> [{packet, 0}, {active, false} | Opts]. negotiate(ip_comm,_,_) -> + ?hlrt("negotiate(ip_comm)", []), ok; -negotiate({ssl,_},Socket,Timeout) -> - negotiate(Socket, Timeout); -negotiate({erl_ssl, _}, Socket, Timeout) -> - negotiate(Socket, Timeout). - -negotiate(Socket, Timeout) -> +negotiate({ssl, SSLConfig}, Socket, Timeout) -> + ?hlrt("negotiate(ssl)", []), + negotiate({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket, Timeout); +negotiate({ossl, _}, Socket, Timeout) -> + ?hlrt("negotiate(ossl)", []), + negotiate_ssl(Socket, Timeout); +negotiate({essl, _}, Socket, Timeout) -> + ?hlrt("negotiate(essl)", []), + negotiate_ssl(Socket, Timeout). + +negotiate_ssl(Socket, Timeout) -> + ?hlrt("negotiate_ssl", [{socket, Socket}, {timeout, Timeout}]), case ssl:ssl_accept(Socket, Timeout) of ok -> ok; - {error, Error} -> - case lists:member(Error, - [timeout,econnreset,esslaccept,esslerrssl]) of + {error, Reason} -> + ?hlrd("negotiate_ssl - accept failed", [{reason, Reason}]), + %% Look for "valid" error reasons + ValidReasons = [timeout, econnreset, esslaccept, esslerrssl], + case lists:member(Reason, ValidReasons) of true -> - {error,normal}; + {error, normal}; false -> - {error, Error} + {error, Reason} end end. diff --git a/lib/inets/src/http_server/Makefile b/lib/inets/src/http_server/Makefile index ce1405011e..879e605217 100644 --- a/lib/inets/src/http_server/Makefile +++ b/lib/inets/src/http_server/Makefile @@ -90,20 +90,17 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) # ---------------------------------------------------- -# INETS FLAGS -# ---------------------------------------------------- -INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' - - -# ---------------------------------------------------- # FLAGS # ---------------------------------------------------- -INETS_ERL_FLAGS += -I ../http_lib -I ../inets_app -pa ../../ebin -ERL_COMPILE_FLAGS += $(INETS_ERL_FLAGS) \ - $(INETS_FLAGS) \ - +'{parse_transform,sys_pre_attributes}' \ - +'{attribute,insert,app_vsn,$(APP_VSN)}' +include ../inets_app/inets.mk + +ERL_COMPILE_FLAGS += \ + $(INETS_FLAGS) \ + $(INETS_ERL_COMPILE_FLAGS) \ + -I../../include \ + -I../inets_app \ + -I../http_lib # ---------------------------------------------------- @@ -125,9 +122,10 @@ docs: include $(ERL_TOP)/make/otp_release_targets.mk release_spec: opt - $(INSTALL_DIR) $(RELSYSDIR)/src - $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src - $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/src/http_server + $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/http_server + $(INSTALL_DIR) $(RELSYSDIR)/ebin $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin release_docs_spec: diff --git a/lib/inets/src/http_server/httpd.erl b/lib/inets/src/http_server/httpd.erl index 8fe54ccef6..fb5fa1c758 100644 --- a/lib/inets/src/http_server/httpd.erl +++ b/lib/inets/src/http_server/httpd.erl @@ -24,54 +24,25 @@ -include("httpd.hrl"). --deprecated({start, 0, next_major_release}). --deprecated({start, 1, next_major_release}). --deprecated({start_link, 1, next_major_release}). --deprecated({start_child, 0, next_major_release}). --deprecated({start_child, 1, next_major_release}). --deprecated({stop, 0, next_major_release}). --deprecated({stop, 1, next_major_release}). --deprecated({stop, 2, next_major_release}). --deprecated({stop_child, 0, next_major_release}). --deprecated({stop_child, 1, next_major_release}). --deprecated({stop_child, 2, next_major_release}). --deprecated({restart, 0, next_major_release}). --deprecated({restart, 1, next_major_release}). --deprecated({restart, 2, next_major_release}). --deprecated({block, 0, next_major_release}). --deprecated({block, 1, next_major_release}). --deprecated({block, 2, next_major_release}). --deprecated({block, 3, next_major_release}). --deprecated({block, 4, next_major_release}). --deprecated({unblock, 0, next_major_release}). --deprecated({unblock, 1, next_major_release}). --deprecated({unblock, 2, next_major_release}). %% Behavior callbacks --export([start_standalone/1, start_service/1, stop_service/1, services/0, - service_info/1]). +-export([ + start_standalone/1, + start_service/1, + stop_service/1, + services/0, + service_info/1 + ]). %% API -export([parse_query/1, reload_config/2, info/1, info/2, info/3]). -%% Deprecated --export([start/0, start/1, - start_link/0, start_link/1, - start_child/0,start_child/1, - stop/0,stop/1,stop/2, - stop_child/0,stop_child/1,stop_child/2, - restart/0,restart/1,restart/2]). - -%% Management stuff should be internal functions -%% Will be from r13 --export([block/0,block/1,block/2,block/3,block/4, - unblock/0,unblock/1,unblock/2]). - -%% Internal Debugging and status info stuff... -%% Keep for now should probably be moved to test catalog --export([get_status/1,get_status/2,get_status/3, - get_admin_state/0,get_admin_state/1,get_admin_state/2, - get_usage_state/0,get_usage_state/1,get_usage_state/2]). +%% Internal debugging and status info stuff... +-export([ + get_status/1, get_status/2, get_status/3, + get_admin_state/0, get_admin_state/1, get_admin_state/2, + get_usage_state/0, get_usage_state/1, get_usage_state/2 + ]). %%%======================================================================== %%% API @@ -111,6 +82,7 @@ info(Address, Port, Properties) when is_integer(Port) andalso is_list(Properties) -> httpd_conf:get_config(Address, Port, Properties). + %%%======================================================================== %%% Behavior callbacks %%%======================================================================== @@ -149,6 +121,8 @@ service_info(Pid) -> exit:{noproc, _} -> {error, service_not_available} end. + + %%%-------------------------------------------------------------- %%% Internal functions %%%-------------------------------------------------------------------- @@ -176,6 +150,7 @@ child_name2info({httpd_instance_sup, Address, Port}) -> {ok, [{bind_address, Address}, {port, Port} | Info]} end. + reload(Config, Address, Port) -> Name = make_name(Address,Port), case whereis(Name) of @@ -185,26 +160,12 @@ reload(Config, Address, Port) -> {error,not_started} end. -reload(Addr, Port) when is_integer(Port) -> - Name = make_name(Addr,Port), - case whereis(Name) of - Pid when is_pid(Pid) -> - httpd_manager:reload(Pid, undefined); - _ -> - {error,not_started} - end. %%% ========================================================= -%%% Function: block/0, block/1, block/2, block/3, block/4 -%%% block() -%%% block(Port) -%%% block(ConfigFile) -%%% block(Addr,Port) -%%% block(Port,Mode) -%%% block(ConfigFile,Mode) -%%% block(Addr,Port,Mode) -%%% block(ConfigFile,Mode,Timeout) -%%% block(Addr,Port,Mode,Timeout) +%%% Function: block/3, block/4 +%%% block(Addr, Port, Mode) +%%% block(ConfigFile, Mode, Timeout) +%%% block(Addr, Port, Mode, Timeout) %%% %%% Returns: ok | {error,Reason} %%% @@ -237,58 +198,32 @@ reload(Addr, Port) when is_integer(Port) -> %%% Mode -> disturbing | non_disturbing %%% Timeout -> integer() %%% -block() -> block(undefined,8888,disturbing). - -block(Port) when is_integer(Port) -> - block(undefined,Port,disturbing); - -block(ConfigFile) when is_list(ConfigFile) -> - case get_addr_and_port(ConfigFile) of - {ok,Addr,Port} -> - block(Addr,Port,disturbing); - Error -> - Error - end. - -block(Addr,Port) when is_integer(Port) -> - block(Addr,Port,disturbing); - -block(Port,Mode) when is_integer(Port) andalso is_atom(Mode) -> - block(undefined,Port,Mode); - -block(ConfigFile,Mode) when is_list(ConfigFile) andalso is_atom(Mode) -> - case get_addr_and_port(ConfigFile) of - {ok,Addr,Port} -> - block(Addr,Port,Mode); - Error -> - Error - end. - -block(Addr,Port,disturbing) when is_integer(Port) -> - do_block(Addr,Port,disturbing); -block(Addr,Port,non_disturbing) when is_integer(Port) -> - do_block(Addr,Port,non_disturbing); +block(Addr, Port, disturbing) when is_integer(Port) -> + do_block(Addr, Port, disturbing); +block(Addr, Port, non_disturbing) when is_integer(Port) -> + do_block(Addr, Port, non_disturbing); -block(ConfigFile,Mode,Timeout) when is_list(ConfigFile) andalso - is_atom(Mode) andalso - is_integer(Timeout) -> +block(ConfigFile, Mode, Timeout) + when is_list(ConfigFile) andalso + is_atom(Mode) andalso + is_integer(Timeout) -> case get_addr_and_port(ConfigFile) of - {ok,Addr,Port} -> - block(Addr,Port,Mode,Timeout); + {ok, Addr, Port} -> + block(Addr, Port, Mode, Timeout); Error -> Error end. -block(Addr,Port,non_disturbing,Timeout) +block(Addr, Port, non_disturbing, Timeout) + when is_integer(Port) andalso is_integer(Timeout) -> + do_block(Addr, Port, non_disturbing, Timeout); +block(Addr,Port,disturbing,Timeout) when is_integer(Port) andalso is_integer(Timeout) -> - do_block(Addr,Port,non_disturbing,Timeout); -block(Addr,Port,disturbing,Timeout) when is_integer(Port) andalso - is_integer(Timeout) -> - do_block(Addr,Port,disturbing,Timeout). + do_block(Addr, Port, disturbing, Timeout). -do_block(Addr,Port,Mode) when is_integer(Port) andalso is_atom(Mode) -> +do_block(Addr, Port, Mode) when is_integer(Port) andalso is_atom(Mode) -> Name = make_name(Addr,Port), case whereis(Name) of Pid when is_pid(Pid) -> @@ -298,7 +233,7 @@ do_block(Addr,Port,Mode) when is_integer(Port) andalso is_atom(Mode) -> end. -do_block(Addr,Port,Mode,Timeout) +do_block(Addr, Port, Mode, Timeout) when is_integer(Port) andalso is_atom(Mode) -> Name = make_name(Addr,Port), case whereis(Name) of @@ -310,11 +245,8 @@ do_block(Addr,Port,Mode,Timeout) %%% ========================================================= -%%% Function: unblock/0, unblock/1, unblock/2 -%%% unblock() -%%% unblock(Port) -%%% unblock(ConfigFile) -%%% unblock(Addr,Port) +%%% Function: unblock/2 +%%% unblock(Addr, Port) %%% %%% Description: This function is used to reverse a previous block %%% operation on the HTTP server. @@ -323,16 +255,6 @@ do_block(Addr,Port,Mode,Timeout) %%% Addr -> {A,B,C,D} | string() | undefined %%% ConfigFile -> string() %%% -unblock() -> unblock(undefined,8888). -unblock(Port) when is_integer(Port) -> unblock(undefined,Port); - -unblock(ConfigFile) when is_list(ConfigFile) -> - case get_addr_and_port(ConfigFile) of - {ok,Addr,Port} -> - unblock(Addr,Port); - Error -> - Error - end. unblock(Addr, Port) when is_integer(Port) -> Name = make_name(Addr,Port), @@ -521,80 +443,81 @@ do_reload_config(ConfigList, Mode) -> %%%-------------------------------------------------------------- %%% Deprecated %%%-------------------------------------------------------------- -start() -> - start("/var/tmp/server_root/conf/8888.conf"). -start(ConfigFile) -> - {ok, Pid} = inets:start(httpd, ConfigFile, stand_alone), - unlink(Pid), - {ok, Pid}. +%% start() -> +%% start("/var/tmp/server_root/conf/8888.conf"). -start_link() -> - start("/var/tmp/server_root/conf/8888.conf"). +%% start(ConfigFile) -> +%% {ok, Pid} = inets:start(httpd, ConfigFile, stand_alone), +%% unlink(Pid), +%% {ok, Pid}. -start_link(ConfigFile) when is_list(ConfigFile) -> - inets:start(httpd, ConfigFile, stand_alone). +%% start_link() -> +%% start("/var/tmp/server_root/conf/8888.conf"). -stop() -> - stop(8888). +%% start_link(ConfigFile) when is_list(ConfigFile) -> +%% inets:start(httpd, ConfigFile, stand_alone). -stop(Port) when is_integer(Port) -> - stop(undefined, Port); -stop(Pid) when is_pid(Pid) -> - old_stop(Pid); -stop(ConfigFile) when is_list(ConfigFile) -> - old_stop(ConfigFile). +%% stop() -> +%% stop(8888). -stop(Addr, Port) when is_integer(Port) -> - old_stop(Addr, Port). +%% stop(Port) when is_integer(Port) -> +%% stop(undefined, Port); +%% stop(Pid) when is_pid(Pid) -> +%% old_stop(Pid); +%% stop(ConfigFile) when is_list(ConfigFile) -> +%% old_stop(ConfigFile). -start_child() -> - start_child("/var/tmp/server_root/conf/8888.conf"). +%% stop(Addr, Port) when is_integer(Port) -> +%% old_stop(Addr, Port). -start_child(ConfigFile) -> - httpd_sup:start_child(ConfigFile). +%% start_child() -> +%% start_child("/var/tmp/server_root/conf/8888.conf"). -stop_child() -> - stop_child(8888). +%% start_child(ConfigFile) -> +%% httpd_sup:start_child(ConfigFile). -stop_child(Port) -> - stop_child(undefined, Port). +%% stop_child() -> +%% stop_child(8888). -stop_child(Addr, Port) when is_integer(Port) -> - httpd_sup:stop_child(Addr, Port). +%% stop_child(Port) -> +%% stop_child(undefined, Port). -restart() -> reload(undefined, 8888). +%% stop_child(Addr, Port) when is_integer(Port) -> +%% httpd_sup:stop_child(Addr, Port). -restart(Port) when is_integer(Port) -> - reload(undefined, Port). -restart(Addr, Port) -> - reload(Addr, Port). +%% restart() -> reload(undefined, 8888). -old_stop(Pid) when is_pid(Pid) -> - do_stop(Pid); -old_stop(ConfigFile) when is_list(ConfigFile) -> - case get_addr_and_port(ConfigFile) of - {ok, Addr, Port} -> - old_stop(Addr, Port); - - Error -> - Error - end; -old_stop(_StartArgs) -> - ok. +%% restart(Port) when is_integer(Port) -> +%% reload(undefined, Port). +%% restart(Addr, Port) -> +%% reload(Addr, Port). -old_stop(Addr, Port) when is_integer(Port) -> - Name = old_make_name(Addr, Port), - case whereis(Name) of - Pid when is_pid(Pid) -> - do_stop(Pid), - ok; - _ -> - not_started - end. +%% old_stop(Pid) when is_pid(Pid) -> +%% do_stop(Pid); +%% old_stop(ConfigFile) when is_list(ConfigFile) -> +%% case get_addr_and_port(ConfigFile) of +%% {ok, Addr, Port} -> +%% old_stop(Addr, Port); + +%% Error -> +%% Error +%% end; +%% old_stop(_StartArgs) -> +%% ok. + +%% old_stop(Addr, Port) when is_integer(Port) -> +%% Name = old_make_name(Addr, Port), +%% case whereis(Name) of +%% Pid when is_pid(Pid) -> +%% do_stop(Pid), +%% ok; +%% _ -> +%% not_started +%% end. -do_stop(Pid) -> - exit(Pid, shutdown). +%% do_stop(Pid) -> +%% exit(Pid, shutdown). -old_make_name(Addr,Port) -> - httpd_util:make_name("httpd_instance_sup",Addr,Port). +%% old_make_name(Addr,Port) -> +%% httpd_util:make_name("httpd_instance_sup",Addr,Port). diff --git a/lib/inets/src/http_server/httpd_acceptor.erl b/lib/inets/src/http_server/httpd_acceptor.erl index 568fd3c610..c261eff6b2 100644 --- a/lib/inets/src/http_server/httpd_acceptor.erl +++ b/lib/inets/src/http_server/httpd_acceptor.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2001-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -138,9 +138,9 @@ acceptor_loop(Manager, SocketType, ListenSocket, ConfigDb, AcceptTimeout) -> handle_error(Reason, ConfigDb), ?MODULE:acceptor_loop(Manager, SocketType, ListenSocket, ConfigDb, AcceptTimeout); - {'EXIT', Reason} -> - ?hdri("accept exited", [{reason, Reason}]), - handle_error({'EXIT', Reason}, ConfigDb), + {'EXIT', _Reason} = EXIT -> + ?hdri("accept exited", [{reason, _Reason}]), + handle_error(EXIT, ConfigDb), ?MODULE:acceptor_loop(Manager, SocketType, ListenSocket, ConfigDb, AcceptTimeout) end. diff --git a/lib/inets/src/http_server/httpd_cgi.erl b/lib/inets/src/http_server/httpd_cgi.erl index 0532d7d100..c06a06aad3 100644 --- a/lib/inets/src/http_server/httpd_cgi.erl +++ b/lib/inets/src/http_server/httpd_cgi.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -21,7 +21,8 @@ -export([parse_headers/1, handle_headers/1]). --include("inets_internal.hrl"). +-include_lib("inets/src/inets_app/inets_internal.hrl"). + %%%========================================================================= %%% Internal application API diff --git a/lib/inets/src/http_server/httpd_conf.erl b/lib/inets/src/http_server/httpd_conf.erl index 5ca2e47eb5..8438c4037e 100644 --- a/lib/inets/src/http_server/httpd_conf.erl +++ b/lib/inets/src/http_server/httpd_conf.erl @@ -25,13 +25,15 @@ %% Application internal API -export([load/1, load/2, load_mime_types/1, store/1, store/2, - remove/1, remove_all/1, config/1, get_config/2, get_config/3, - lookup/2, lookup/3, lookup/4, - validate_properties/1]). + remove/1, remove_all/1, get_config/2, get_config/3, + lookup_socket_type/1, + lookup/2, lookup/3, lookup/4, + validate_properties/1]). -define(VMODULE,"CONF"). -include("httpd.hrl"). -include("httpd_internal.hrl"). +-include_lib("inets/src/http_lib/http_internal.hrl"). %%%========================================================================= @@ -216,9 +218,12 @@ load("ServerName " ++ ServerName, []) -> {ok,[],{server_name,clean(ServerName)}}; load("SocketType " ++ SocketType, []) -> - case check_enum(clean(SocketType),["ssl","ip_comm"]) of + %% ssl is the same as HTTP_DEFAULT_SSL_KIND + %% ossl is ssl based on OpenSSL (the "old" ssl) + %% essl is the pure Erlang-based ssl (the "new" ssl) + case check_enum(clean(SocketType), ["ssl", "ossl", "essl", "ip_comm"]) of {ok, ValidSocketType} -> - {ok, [], {socket_type,ValidSocketType}}; + {ok, [], {socket_type, ValidSocketType}}; {error,_} -> {error, ?NICE(clean(SocketType) ++ " is an invalid SocketType")} end; @@ -226,7 +231,7 @@ load("SocketType " ++ SocketType, []) -> load("Port " ++ Port, []) -> case make_integer(Port) of {ok, Integer} -> - {ok, [], {port,Integer}}; + {ok, [], {port, Integer}}; {error, _} -> {error, ?NICE(clean(Port)++" is an invalid Port")} end; @@ -534,7 +539,10 @@ validate_config_params([{server_name, Value} | _]) -> throw({server_name, Value}); validate_config_params([{socket_type, Value} | Rest]) - when (Value =:= ip_comm) orelse (Value =:= ssl) -> + when (Value =:= ip_comm) orelse + (Value =:= ssl) orelse + (Value =:= ossl) orelse + (Value =:= essl) -> validate_config_params(Rest); validate_config_params([{socket_type, Value} | _]) -> throw({socket_type, Value}); @@ -695,6 +703,8 @@ store(ConfigList0) -> ConfigList) catch throw:Error -> + ?hdri("store - config parameter validation failed", + [{error, Error}]), {error, {invalid_option, Error}} end. @@ -741,27 +751,27 @@ remove(ConfigDB) -> ets:delete(ConfigDB), ok. -config(ConfigDB) -> - case httpd_util:lookup(ConfigDB, socket_type,ip_comm) of - ssl -> - case ssl_certificate_file(ConfigDB) of - undefined -> - {error, - "Directive SSLCertificateFile " - "not found in the config file"}; - SSLCertificateFile -> - {ssl, - SSLCertificateFile++ - ssl_certificate_key_file(ConfigDB)++ - ssl_verify_client(ConfigDB)++ - ssl_ciphers(ConfigDB)++ - ssl_password(ConfigDB)++ - ssl_verify_depth(ConfigDB)++ - ssl_ca_certificate_file(ConfigDB)} - end; - ip_comm -> - ip_comm - end. +%% config(ConfigDB) -> +%% case httpd_util:lookup(ConfigDB, socket_type, ip_comm) of +%% ssl -> +%% case ssl_certificate_file(ConfigDB) of +%% undefined -> +%% {error, +%% "Directive SSLCertificateFile " +%% "not found in the config file"}; +%% SSLCertificateFile -> +%% {ssl, +%% SSLCertificateFile++ +%% ssl_certificate_key_file(ConfigDB)++ +%% ssl_verify_client(ConfigDB)++ +%% ssl_ciphers(ConfigDB)++ +%% ssl_password(ConfigDB)++ +%% ssl_verify_depth(ConfigDB)++ +%% ssl_ca_certificate_file(ConfigDB)} +%% end; +%% ip_comm -> +%% ip_comm +%% end. get_config(Address, Port) -> @@ -797,6 +807,38 @@ table(Address, Port) -> httpd_util:make_name("httpd_conf", Address, Port). +lookup_socket_type(ConfigDB) -> + case httpd_util:lookup(ConfigDB, socket_type, ip_comm) of + ip_comm -> + ip_comm; + SSL when (SSL =:= ssl) orelse (SSL =:= ossl) orelse (SSL =:= essl) -> + SSLTag = + if + (SSL =:= ssl) -> + ?HTTP_DEFAULT_SSL_KIND; + true -> + SSL + end, + case ssl_certificate_file(ConfigDB) of + undefined -> + Reason = "Directive SSLCertificateFile " + "not found in the config file", + throw({error, Reason}); + SSLCertificateFile -> + {SSLTag, SSLCertificateFile ++ ssl_config(ConfigDB)} + end + end. + +ssl_config(ConfigDB) -> + ssl_certificate_key_file(ConfigDB) ++ + ssl_verify_client(ConfigDB) ++ + ssl_ciphers(ConfigDB) ++ + ssl_password(ConfigDB) ++ + ssl_verify_depth(ConfigDB) ++ + ssl_ca_certificate_file(ConfigDB). + + + %%%======================================================================== %%% Internal functions %%%======================================================================== diff --git a/lib/inets/src/http_server/httpd_esi.erl b/lib/inets/src/http_server/httpd_esi.erl index b1a75fda52..026ec9a5fe 100644 --- a/lib/inets/src/http_server/httpd_esi.erl +++ b/lib/inets/src/http_server/httpd_esi.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -21,7 +21,8 @@ -export([parse_headers/1, handle_headers/1]). --include("inets_internal.hrl"). +-include_lib("inets/src/inets_app/inets_internal.hrl"). + %%%========================================================================= %%% Internal application API diff --git a/lib/inets/src/http_server/httpd_internal.hrl b/lib/inets/src/http_server/httpd_internal.hrl index 7795ab6c18..38b0ddefd3 100644 --- a/lib/inets/src/http_server/httpd_internal.hrl +++ b/lib/inets/src/http_server/httpd_internal.hrl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2009-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -21,7 +21,8 @@ -ifndef(httpd_internal_hrl). -define(httpd_internal_hrl, true). --include("inets_internal.hrl"). +-include_lib("inets/src/inets_app/inets_internal.hrl"). + -define(SERVICE, httpd). -define(hdri(Label, Content), ?report_important(Label, ?SERVICE, Content)). -define(hdrv(Label, Content), ?report_verbose(Label, ?SERVICE, Content)). diff --git a/lib/inets/src/http_server/httpd_manager.erl b/lib/inets/src/http_server/httpd_manager.erl index f2e8763907..b44bc77c41 100644 --- a/lib/inets/src/http_server/httpd_manager.erl +++ b/lib/inets/src/http_server/httpd_manager.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2000-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2000-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -238,24 +238,25 @@ init([ConfigFile, ConfigList, AcceptTimeout, Addr, Port]) -> case (catch do_init(ConfigFile, ConfigList, AcceptTimeout, Addr, Port)) of {error, Reason} -> String = lists:flatten( - io_lib:format("Failed initiating " - "web server: ~n~p~n~p~n", - [ConfigFile,Reason])), + io_lib:format("Failed initiating web server: " + "~n~p" + "~n~p" + "~n", [ConfigFile, Reason])), error_logger:error_report(String), {stop, {error, Reason}}; {ok, State} -> {ok, State} end; -init([ConfigFile, ConfigList, AcceptTimeout, Addr, Port, - ListenInfo]) -> +init([ConfigFile, ConfigList, AcceptTimeout, Addr, Port, ListenInfo]) -> process_flag(trap_exit, true), case (catch do_init(ConfigFile, ConfigList, AcceptTimeout, Addr, Port, ListenInfo)) of {error, Reason} -> String = lists:flatten( - io_lib:format("Failed initiating " - "web server: ~n~p~n~p~n", - [ConfigFile,Reason])), + io_lib:format("Failed initiating web server: " + "~n~p" + "~n~p" + "~n", [ConfigFile, Reason])), error_logger:error_report(String), {stop, {error, Reason}}; {ok, State} -> @@ -264,13 +265,14 @@ init([ConfigFile, ConfigList, AcceptTimeout, Addr, Port, do_init(ConfigFile, ConfigList, AcceptTimeout, Addr, Port) -> NewConfigFile = proplists:get_value(file, ConfigList, ConfigFile), - ConfigDB = do_initial_store(ConfigList), - SocketType = httpd_conf:config(ConfigDB), + ConfigDB = do_initial_store(ConfigList), + SocketType = httpd_conf:lookup_socket_type(ConfigDB), case httpd_acceptor_sup:start_acceptor(SocketType, Addr, Port, ConfigDB, AcceptTimeout) of {ok, _Pid} -> - Status = [{max_conn,0}, {last_heavy_load,never}, - {last_connection,never}], + Status = [{max_conn, 0}, + {last_heavy_load, never}, + {last_connection, never}], State = #state{socket_type = SocketType, config_file = NewConfigFile, config_db = ConfigDB, @@ -284,7 +286,7 @@ do_init(ConfigFile, ConfigList, AcceptTimeout, Addr, Port) -> do_init(ConfigFile, ConfigList, AcceptTimeout, Addr, Port, ListenInfo) -> NewConfigFile = proplists:get_value(file, ConfigList, ConfigFile), ConfigDB = do_initial_store(ConfigList), - SocketType = httpd_conf:config(ConfigDB), + SocketType = httpd_conf:lookup_socket_type(ConfigDB), case httpd_acceptor_sup:start_acceptor(SocketType, Addr, Port, ConfigDB, AcceptTimeout, ListenInfo) of diff --git a/lib/inets/src/http_server/httpd_request.erl b/lib/inets/src/http_server/httpd_request.erl index 8eee08e766..883acbf585 100644 --- a/lib/inets/src/http_server/httpd_request.erl +++ b/lib/inets/src/http_server/httpd_request.erl @@ -19,22 +19,35 @@ -module(httpd_request). --include("http_internal.hrl"). +-include_lib("inets/src/http_lib/http_internal.hrl"). -include("httpd.hrl"). +-include("httpd_internal.hrl"). --export([parse/1, whole_body/2, validate/3, update_mod_data/5, - body_data/2]). +-export([ + parse/1, + whole_body/2, + validate/3, + update_mod_data/5, + body_data/2 + ]). %% Callback API - used for example if the header/body is received a %% little at a time on a socket. --export([parse_method/1, parse_uri/1, parse_version/1, parse_headers/1, - whole_body/1]). +-export([ + parse_method/1, parse_uri/1, parse_version/1, parse_headers/1, + whole_body/1 + ]). + %%%========================================================================= %%% Internal application API %%%========================================================================= parse([Bin, MaxSizes]) -> - parse_method(Bin, [], MaxSizes, []). + ?hdrt("parse", [{bin, Bin}, {max_sizes, MaxSizes}]), + parse_method(Bin, [], MaxSizes, []); +parse(Unknown) -> + ?hdrt("parse", [{unknown, Unknown}]), + exit({bad_args, Unknown}). %% Functions that may be returned during the decoding process %% if the input data is incompleate. @@ -119,30 +132,65 @@ update_mod_data(ModData, Method, RequestURI, HTTPVersion, Headers)-> %%% Internal functions %%%======================================================================== parse_method(<<>>, Method, MaxSizes, Result) -> + ?hdrt("parse_method - empty bin", + [{method, Method}, {max_sizes, MaxSizes}, {result, Result}]), {?MODULE, parse_method, [Method, MaxSizes, Result]}; parse_method(<<?SP, Rest/binary>>, Method, MaxSizes, Result) -> + ?hdrt("parse_method - SP begin", + [{rest, Rest}, + {method, Method}, + {max_sizes, MaxSizes}, + {result, Result}]), parse_uri(Rest, [], 0, MaxSizes, [string:strip(lists:reverse(Method)) | Result]); parse_method(<<Octet, Rest/binary>>, Method, MaxSizes, Result) -> + ?hdrt("parse_method", + [{octet, Octet}, + {rest, Rest}, + {method, Method}, + {max_sizes, MaxSizes}, + {result, Result}]), parse_method(Rest, [Octet | Method], MaxSizes, Result). -parse_uri(_, _, CurrSize, {MaxURI, _}, _) when CurrSize > MaxURI, - MaxURI =/= nolimit -> +parse_uri(_, _, CurrSize, {MaxURI, _}, _) + when (CurrSize > MaxURI) andalso (MaxURI =/= nolimit) -> + ?hdrt("parse_uri", + [{current_size, CurrSize}, + {max_uri, MaxURI}]), %% We do not know the version of the client as it comes after the %% uri send the lowest version in the response so that the client %% will be able to handle it. HttpVersion = "HTTP/0.9", {error, {uri_too_long, MaxURI}, HttpVersion}; parse_uri(<<>>, URI, CurrSize, MaxSizes, Result) -> + ?hdrt("parse_uri - empty bin", + [{uri, URI}, + {current_size, CurrSize}, + {max_sz, MaxSizes}, + {result, Result}]), {?MODULE, parse_uri, [URI, CurrSize, MaxSizes, Result]}; parse_uri(<<?SP, Rest/binary>>, URI, _, MaxSizes, Result) -> + ?hdrt("parse_uri - SP begin", + [{uri, URI}, + {max_sz, MaxSizes}, + {result, Result}]), parse_version(Rest, [], MaxSizes, [string:strip(lists:reverse(URI)) | Result]); %% Can happen if it is a simple HTTP/0.9 request e.i "GET /\r\n\r\n" -parse_uri(<<?CR, _Rest/binary>> = Data, URI, _,MaxSizes, Result) -> +parse_uri(<<?CR, _Rest/binary>> = Data, URI, _, MaxSizes, Result) -> + ?hdrt("parse_uri - CR begin", + [{uri, URI}, + {max_sz, MaxSizes}, + {result, Result}]), parse_version(Data, [], MaxSizes, [string:strip(lists:reverse(URI)) | Result]); parse_uri(<<Octet, Rest/binary>>, URI, CurrSize, MaxSizes, Result) -> + ?hdrt("parse_uri", + [{octet, Octet}, + {uri, URI}, + {curr_sz, CurrSize}, + {max_sz, MaxSizes}, + {result, Result}]), parse_uri(Rest, [Octet | URI], CurrSize + 1, MaxSizes, Result). parse_version(<<>>, Version, MaxSizes, Result) -> diff --git a/lib/inets/src/http_server/httpd_request_handler.erl b/lib/inets/src/http_server/httpd_request_handler.erl index fa832cba3f..a9db6e2058 100644 --- a/lib/inets/src/http_server/httpd_request_handler.erl +++ b/lib/inets/src/http_server/httpd_request_handler.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -101,11 +101,13 @@ init([Manager, ConfigDB, AcceptTimeout]) -> Then = erlang:now(), + ?hdrd("negotiate", []), case http_transport:negotiate(SocketType, Socket, TimeOut) of {error, Error} -> + ?hdrd("negotiation failed", [{error, Error}]), exit(Error); %% Can be 'normal'. ok -> - ?hdrt("negotiated", []), + ?hdrt("negotiation successfull", []), NewTimeout = TimeOut - timer:now_diff(now(),Then) div 1000, continue_init(Manager, ConfigDB, SocketType, Socket, NewTimeout) end. @@ -121,12 +123,9 @@ continue_init(Manager, ConfigDB, SocketType, Socket, TimeOut) -> socket = Socket, init_data = InitData}, - MaxHeaderSize = httpd_util:lookup(ConfigDB, max_header_size, - ?HTTP_MAX_HEADER_SIZE), - MaxURISize = httpd_util:lookup(ConfigDB, max_uri_size, - ?HTTP_MAX_URI_SIZE), - NrOfRequest = httpd_util:lookup(ConfigDB, - max_keep_alive_request, infinity), + MaxHeaderSize = max_header_size(ConfigDB), + MaxURISize = max_uri_size(ConfigDB), + NrOfRequest = max_keep_alive_request(ConfigDB), {_, Status} = httpd_manager:new_connection(Manager), @@ -142,9 +141,10 @@ continue_init(Manager, ConfigDB, SocketType, Socket, TimeOut) -> ?hdrt("activate request timeout", []), NewState = activate_request_timeout(State), - ?hdrt("update socket options", []), - http_transport:setopts(SocketType, Socket, [binary,{packet, 0}, - {active, once}]), + ?hdrt("set socket options (binary, packet & active)", []), + http_transport:setopts(SocketType, Socket, + [binary, {packet, 0}, {active, once}]), + ?hdrt("init done", []), gen_server:enter_loop(?MODULE, [], NewState). @@ -180,21 +180,29 @@ handle_cast(Msg, State) -> %% {stop, Reason, State} %% Description: Handling all non call/cast messages %%-------------------------------------------------------------------- -handle_info({Proto, Socket, Data}, State = +handle_info({Proto, Socket, Data}, #state{mfa = {Module, Function, Args} = MFA, mod = #mod{socket_type = SockType, socket = Socket} = ModData} = State) when (((Proto =:= tcp) orelse (Proto =:= ssl) orelse (Proto =:= dummy)) andalso is_binary(Data)) -> + ?hdrd("received data", [{data, Data}, {proto, Proto}, {socket, Socket}, {socket_type, SockType}, {mfa, MFA}]), - case Module:Function([Data | Args]) of + +%% case (catch Module:Function([Data | Args])) of + PROCESSED = (catch Module:Function([Data | Args])), + + ?hdrt("data processed", [{processing_result, PROCESSED}]), + + case PROCESSED of {ok, Result} -> ?hdrd("data processed", [{result, Result}]), NewState = cancel_request_timeout(State), handle_http_msg(Result, NewState); + {error, {uri_too_long, MaxSize}, Version} -> ?hdrv("uri too long", [{max_size, MaxSize}, {version, Version}]), NewModData = ModData#mod{http_version = Version}, @@ -205,7 +213,8 @@ handle_info({Proto, Socket, Data}, State = {stop, normal, State#state{response_sent = true, mod = NewModData}}; {error, {header_too_long, MaxSize}, Version} -> - ?hdrv("header too long", [{max_size, MaxSize}, {version, Version}]), + ?hdrv("header too long", + [{max_size, MaxSize}, {version, Version}]), NewModData = ModData#mod{http_version = Version}, httpd_response:send_status(NewModData, 413, "Header too long"), Reason = io_lib:format("Header too long, max size is ~p~n", @@ -263,14 +272,16 @@ terminate(Reason, #state{response_sent = false, mod = ModData} = State) -> httpd_response:send_status(ModData, 500, none), error_log(httpd_util:reason_phrase(500), ModData), terminate(Reason, State#state{response_sent = true, mod = ModData}); -terminate(_, State) -> +terminate(_Reason, State) -> do_terminate(State). do_terminate(#state{mod = ModData, manager = Manager} = State) -> catch httpd_manager:done_connection(Manager), cancel_request_timeout(State), + %% receive after 5000 -> ok end, httpd_socket:close(ModData#mod.socket_type, ModData#mod.socket). + %%-------------------------------------------------------------------- %% code_change(OldVsn, State, Extra) -> {ok, NewState} %% @@ -279,6 +290,7 @@ do_terminate(#state{mod = ModData, manager = Manager} = State) -> code_change(_OldVsn, State, _Extra) -> {ok, State}. + %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- @@ -383,9 +395,8 @@ is_host_specified_if_required(_, _, _) -> handle_body(#state{mod = #mod{config_db = ConfigDB}} = State) -> ?hdrt("handle body", []), - MaxHeaderSize = - httpd_util:lookup(ConfigDB, max_header_size, ?HTTP_MAX_HEADER_SIZE), - MaxBodySize = httpd_util:lookup(ConfigDB, max_body_size, nolimit), + MaxHeaderSize = max_header_size(ConfigDB), + MaxBodySize = max_body_size(ConfigDB), case handle_expect(State, MaxBodySize) of ok -> @@ -538,24 +549,23 @@ handle_response(#state{body = Body, {stop, normal, State#state{response_sent = true}}. handle_next_request(#state{mod = #mod{connection = true} = ModData, - max_keep_alive_request = Max} = State, Data) -> + max_keep_alive_request = Max} = State, Data) -> ?hdrt("handle next request", [{max, Max}]), + NewModData = #mod{socket_type = ModData#mod.socket_type, - socket = ModData#mod.socket, - config_db = ModData#mod.config_db, - init_data = ModData#mod.init_data}, - MaxHeaderSize = - httpd_util:lookup(ModData#mod.config_db, - max_header_size, ?HTTP_MAX_HEADER_SIZE), - MaxURISize = httpd_util:lookup(ModData#mod.config_db, max_uri_size, - ?HTTP_MAX_URI_SIZE), - TmpState = State#state{mod = NewModData, - mfa = {httpd_request, parse, [{MaxURISize, - MaxHeaderSize}]}, + socket = ModData#mod.socket, + config_db = ModData#mod.config_db, + init_data = ModData#mod.init_data}, + MaxHeaderSize = max_header_size(ModData#mod.config_db), + MaxURISize = max_uri_size(ModData#mod.config_db), + + MFA = {httpd_request, parse, [{MaxURISize, MaxHeaderSize}]}, + TmpState = State#state{mod = NewModData, + mfa = MFA, max_keep_alive_request = decrease(Max), - headers = undefined, - body = undefined, - response_sent = false}, + headers = undefined, + body = undefined, + response_sent = false}, NewState = activate_request_timeout(TmpState), @@ -596,7 +606,7 @@ decrease(N) -> error_log(ReasonString, Info) -> Error = lists:flatten( - io_lib:format("Error reading request:~s",[ReasonString])), + io_lib:format("Error reading request: ~s", [ReasonString])), error_log(mod_log, Info, Error), error_log(mod_disk_log, Info, Error). @@ -609,3 +619,21 @@ error_log(Mod, #mod{config_db = ConfigDB} = Info, String) -> _ -> ok end. + + +%%-------------------------------------------------------------------- +%% Config access wrapper functions +%%-------------------------------------------------------------------- + +max_header_size(ConfigDB) -> + httpd_util:lookup(ConfigDB, max_header_size, ?HTTP_MAX_HEADER_SIZE). + +max_uri_size(ConfigDB) -> + httpd_util:lookup(ConfigDB, max_uri_size, ?HTTP_MAX_URI_SIZE). + +max_body_size(ConfigDB) -> + httpd_util:lookup(ConfigDB, max_body_size, nolimit). + +max_keep_alive_request(ConfigDB) -> + httpd_util:lookup(ConfigDB, max_keep_alive_request, infinity). + diff --git a/lib/inets/src/http_server/mod_alias.erl b/lib/inets/src/http_server/mod_alias.erl index ec0a12242f..9c5a8cc1c6 100644 --- a/lib/inets/src/http_server/mod_alias.erl +++ b/lib/inets/src/http_server/mod_alias.erl @@ -103,6 +103,19 @@ real_name(ConfigDB, RequestURI, []) -> httpd_util:split_path(default_index(ConfigDB, RealName)), {ShortPath, Path, AfterPath}; +real_name(ConfigDB, RequestURI, [{MP,Replacement}|Rest]) + when element(1, MP) =:= re_pattern -> + case re:run(RequestURI, MP, [{capture,[]}]) of + match -> + 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) + end; + real_name(ConfigDB, RequestURI, [{FakeName,RealName}|Rest]) -> case inets_regexp:match(RequestURI, "^" ++ FakeName) of {match, _, _} -> @@ -120,6 +133,18 @@ real_name(ConfigDB, RequestURI, [{FakeName,RealName}|Rest]) -> real_script_name(_ConfigDB, _RequestURI, []) -> not_a_script; + +real_script_name(ConfigDB, RequestURI, [{MP,Replacement} | Rest]) + when element(1, MP) =:= re_pattern -> + case re:run(RequestURI, MP, [{capture,[]}]) of + match -> + ActualName = + re:replace(RequestURI, MP, Replacement, [{return,list}]), + httpd_util:split_script_path(default_index(ConfigDB, ActualName)); + nomatch -> + real_script_name(ConfigDB, RequestURI, Rest) + end; + real_script_name(ConfigDB, RequestURI, [{FakeName,RealName} | Rest]) -> case inets_regexp:match(RequestURI, "^" ++ FakeName) of {match,_,_} -> @@ -180,6 +205,8 @@ load("Alias " ++ Alias, []) -> {ok, _} -> {error,?NICE(httpd_conf:clean(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]} -> @@ -189,6 +216,24 @@ load("ScriptAlias " ++ ScriptAlias, []) -> {ok, _} -> {error, ?NICE(httpd_conf:clean(ScriptAlias)++ " is an invalid ScriptAlias")} + end; +load("ScriptReWrite " ++ Rule, Acc) -> + load_re_write(Rule, Acc, "ScriptReWrite", script_re_write). + +load_re_write(Rule0, Acc, Type, Tag) -> + case lists:dropwhile( + fun ($\s) -> true; ($\t) -> true; (_) -> false end, + Rule0) of + "" -> + {error, ?NICE(httpd_conf:clean(Rule0)++" is an invalid "++Type)}; + Rule -> + case string:chr(Rule, $\s) of + 0 -> + {ok, Acc, {Tag, {Rule, ""}}}; + N -> + {Re, [_|Replacement]} = lists:split(N-1, Rule), + {ok, Acc, {Tag, {Re, Replacement}}} + end end. store({directory_index, Value} = Conf, _) when is_list(Value) -> @@ -200,16 +245,36 @@ store({directory_index, Value} = Conf, _) when is_list(Value) -> end; store({directory_index, Value}, _) -> {error, {wrong_type, {directory_index, Value}}}; -store({alias, {Fake, Real}} = Conf, _) - when is_list(Fake) andalso is_list(Real) -> +store({alias, {Fake, Real}} = Conf, _) + when is_list(Fake), is_list(Real) -> {ok, Conf}; store({alias, Value}, _) -> {error, {wrong_type, {alias, Value}}}; +store({re_write, {Re, Replacement}} = Conf, _) + when is_list(Re), is_list(Replacement) -> + case re:compile(Re) of + {ok, MP} -> + {ok, {alias, {MP, Replacement}}}; + {error,_} -> + {error, {re_compile, Conf}} + end; +store({re_write, _} = Conf, _) -> + {error, {wrong_type, Conf}}; store({script_alias, {Fake, Real}} = Conf, _) - when is_list(Fake) andalso is_list(Real) -> + when is_list(Fake), is_list(Real) -> {ok, Conf}; store({script_alias, Value}, _) -> - {error, {wrong_type, {script_alias, Value}}}. + {error, {wrong_type, {script_alias, Value}}}; +store({script_re_write, {Re, Replacement}} = Conf, _) + when is_list(Re), is_list(Replacement) -> + case re:compile(Re) of + {ok, MP} -> + {ok, {script_alias, {MP, Replacement}}}; + {error,_} -> + {error, {re_compile, Conf}} + end; +store({script_re_write, _} = Conf, _) -> + {error, {wrong_type, Conf}}. is_directory_index_list([]) -> true; diff --git a/lib/inets/src/http_server/mod_esi.erl b/lib/inets/src/http_server/mod_esi.erl index cb33544540..f7877aa9e2 100644 --- a/lib/inets/src/http_server/mod_esi.erl +++ b/lib/inets/src/http_server/mod_esi.erl @@ -29,6 +29,7 @@ -export([do/1, load/2, store/2]). -include("httpd.hrl"). +-include("httpd_internal.hrl"). -define(VMODULE,"ESI"). -define(DEFAULT_ERL_TIMEOUT,15000). @@ -37,6 +38,7 @@ %%%========================================================================= %%% API %%%========================================================================= + %%-------------------------------------------------------------------------- %% deliver(SessionID, Data) -> ok | {error, bad_sessionID} %% SessionID = pid() @@ -48,7 +50,7 @@ %% request handling process so it can forward it to the client. %%------------------------------------------------------------------------- deliver(SessionID, Data) when is_pid(SessionID) -> - SessionID ! {ok, Data}, + SessionID ! {esi_data, Data}, ok; deliver(_SessionID, _Data) -> {error, bad_sessionID}. @@ -65,6 +67,7 @@ deliver(_SessionID, _Data) -> %% Description: See httpd(3) ESWAPI CALLBACK FUNCTIONS %%------------------------------------------------------------------------- do(ModData) -> + ?hdrt("do", []), case proplists:get_value(status, ModData#mod.data) of {_StatusCode, _PhraseArgs, _Reason} -> {proceed, ModData#mod.data}; @@ -184,6 +187,7 @@ store({erl_script_nocache, Value}, _) -> %%% Internal functions %%%======================================================================== generate_response(ModData) -> + ?hdrt("generate response", []), case scheme(ModData#mod.request_uri, ModData#mod.config_db) of {eval, ESIBody, Modules} -> eval(ModData, ESIBody, Modules); @@ -235,6 +239,7 @@ alias_match_str(Alias, eval_script_alias) -> erl(#mod{method = Method} = ModData, ESIBody, Modules) when (Method =:= "GET") orelse (Method =:= "HEAD") -> + ?hdrt("erl", [{method, Method}]), case httpd_util:split(ESIBody,":|%3A|/",2) of {ok, [ModuleName, FuncAndInput]} -> case httpd_util:split(FuncAndInput,"[\?/]",2) of @@ -260,6 +265,7 @@ erl(#mod{request_uri = ReqUri, method = "PUT", http_version = Version, data = Data}, _ESIBody, _Modules) -> + ?hdrt("erl", [{method, put}]), {proceed, [{status,{501,{"PUT", ReqUri, Version}, ?NICE("Erl mechanism doesn't support method PUT")}}| Data]}; @@ -268,12 +274,14 @@ erl(#mod{request_uri = ReqUri, method = "DELETE", http_version = Version, data = Data}, _ESIBody, _Modules) -> + ?hdrt("erl", [{method, delete}]), {proceed,[{status,{501,{"DELETE", ReqUri, Version}, ?NICE("Erl mechanism doesn't support method DELETE")}}| Data]}; erl(#mod{method = "POST", entity_body = Body} = ModData, ESIBody, Modules) -> + ?hdrt("erl", [{method, post}]), case httpd_util:split(ESIBody,":|%3A|/",2) of {ok,[ModuleName, Function]} -> generate_webpage(ModData, ESIBody, Modules, @@ -289,6 +297,7 @@ generate_webpage(ModData, ESIBody, [all], Module, FunctionName, FunctionName, Input, ScriptElements); generate_webpage(ModData, ESIBody, Modules, Module, FunctionName, Input, ScriptElements) -> + ?hdrt("generate webpage", []), Function = list_to_atom(FunctionName), case lists:member(Module, Modules) of true -> @@ -309,8 +318,9 @@ generate_webpage(ModData, ESIBody, Modules, Module, FunctionName, %% Old API that waits for the dymnamic webpage to be totally generated %% before anythig is sent back to the client. -erl_scheme_webpage_whole(Module, Function, Env, Input, ModData) -> - case (catch Module:Function(Env, Input)) of +erl_scheme_webpage_whole(Mod, Func, Env, Input, ModData) -> + ?hdrt("erl_scheme_webpage_whole", [{module, Mod}, {function, Func}]), + case (catch Mod:Func(Env, Input)) of {'EXIT',{undef, _}} -> {proceed, [{status, {404, ModData#mod.request_uri, "Not found"}} | ModData#mod.data]}; @@ -347,6 +357,7 @@ erl_scheme_webpage_whole(Module, Function, Env, Input, ModData) -> %% in small chunks at the time during generation. erl_scheme_webpage_chunk(Mod, Func, Env, Input, ModData) -> process_flag(trap_exit, true), + ?hdrt("erl_scheme_webpage_chunk", [{module, Mod}, {function, Func}]), Self = self(), %% Spawn worker that generates the webpage. %% It would be nicer to use erlang:function_exported/3 but if the @@ -372,9 +383,12 @@ deliver_webpage_chunk(#mod{config_db = Db} = ModData, Pid) -> deliver_webpage_chunk(ModData, Pid, Timeout). deliver_webpage_chunk(#mod{config_db = Db} = ModData, Pid, Timeout) -> + ?hdrt("deliver_webpage_chunk", [{timeout, Timeout}]), case receive_headers(Timeout) of {error, Reason} -> %% Happens when webpage generator callback/3 is undefined + ?hdrv("deliver_webpage_chunk - failed receiving headers", + [{reason, Reason}]), {error, Reason}; {Headers, Body} -> case httpd_esi:handle_headers(Headers) of @@ -399,6 +413,7 @@ deliver_webpage_chunk(#mod{config_db = Db} = ModData, Pid, Timeout) -> IsDisableChunkedSend) end; timeout -> + ?hdrv("deliver_webpage_chunk - timeout", []), send_headers(ModData, {504, "Timeout"},[{"connection", "close"}]), httpd_socket:close(ModData#mod.socket_type, ModData#mod.socket), process_flag(trap_exit,false), @@ -407,11 +422,17 @@ deliver_webpage_chunk(#mod{config_db = Db} = ModData, Pid, Timeout) -> receive_headers(Timeout) -> receive + {esi_data, Chunk} -> + ?hdrt("receive_headers - received esi data (esi)", []), + httpd_esi:parse_headers(lists:flatten(Chunk)); {ok, Chunk} -> + ?hdrt("receive_headers - received esi data (ok)", []), httpd_esi:parse_headers(lists:flatten(Chunk)); {'EXIT', Pid, erl_scheme_webpage_chunk_undefined} when is_pid(Pid) -> + ?hdrd("receive_headers - exit:chunk-undef", []), {error, erl_scheme_webpage_chunk_undefined}; {'EXIT', Pid, Reason} when is_pid(Pid) -> + ?hdrv("receive_headers - exit", [{reason, Reason}]), exit({mod_esi_linked_process_died, Pid, Reason}) after Timeout -> timeout @@ -427,19 +448,29 @@ handle_body(_, #mod{method = "HEAD"} = ModData, _, _, Size, _) -> {proceed, [{response, {already_sent, 200, Size}} | ModData#mod.data]}; handle_body(Pid, ModData, Body, Timeout, Size, IsDisableChunkedSend) -> + ?hdrt("handle_body - send chunk", [{timeout, Timeout}, {size, Size}]), httpd_response:send_chunk(ModData, Body, IsDisableChunkedSend), receive + {esi_data, Data} -> + ?hdrt("handle_body - received data (esi)", []), + handle_body(Pid, ModData, Data, Timeout, Size + length(Data), + IsDisableChunkedSend); {ok, Data} -> + ?hdrt("handle_body - received data (ok)", []), handle_body(Pid, ModData, Data, Timeout, Size + length(Data), IsDisableChunkedSend); {'EXIT', Pid, normal} when is_pid(Pid) -> + ?hdrt("handle_body - exit:normal", []), httpd_response:send_final_chunk(ModData, IsDisableChunkedSend), {proceed, [{response, {already_sent, 200, Size}} | ModData#mod.data]}; {'EXIT', Pid, Reason} when is_pid(Pid) -> + ?hdrv("handle_body - exit", [{reason, Reason}]), httpd_response:send_final_chunk(ModData, IsDisableChunkedSend), exit({mod_esi_linked_process_died, Pid, Reason}) + after Timeout -> + ?hdrv("handle_body - timeout", []), process_flag(trap_exit,false), httpd_response:send_final_chunk(ModData, IsDisableChunkedSend), exit({mod_esi_linked_process_timeout, Pid}) @@ -473,6 +504,7 @@ eval(#mod{request_uri = ReqUri, method = "PUT", http_version = Version, data = Data}, _ESIBody, _Modules) -> + ?hdrt("eval", [{method, put}]), {proceed,[{status,{501,{"PUT", ReqUri, Version}, ?NICE("Eval mechanism doesn't support method PUT")}}| Data]}; @@ -481,6 +513,7 @@ eval(#mod{request_uri = ReqUri, method = "DELETE", http_version = Version, data = Data}, _ESIBody, _Modules) -> + ?hdrt("eval", [{method, delete}]), {proceed,[{status,{501,{"DELETE", ReqUri, Version}, ?NICE("Eval mechanism doesn't support method DELETE")}}| Data]}; @@ -489,12 +522,14 @@ eval(#mod{request_uri = ReqUri, method = "POST", http_version = Version, data = Data}, _ESIBody, _Modules) -> + ?hdrt("eval", [{method, post}]), {proceed,[{status,{501,{"POST", ReqUri, Version}, ?NICE("Eval mechanism doesn't support method POST")}}| Data]}; eval(#mod{method = Method} = ModData, ESIBody, Modules) - when Method == "GET"; Method == "HEAD" -> + when (Method =:= "GET") orelse (Method =:= "HEAD") -> + ?hdrt("eval", [{method, Method}]), case is_authorized(ESIBody, Modules) of true -> case generate_webpage(ESIBody) of diff --git a/lib/inets/src/inets_app/Makefile b/lib/inets/src/inets_app/Makefile index 33c9e34a3a..4632ff3b68 100644 --- a/lib/inets/src/inets_app/Makefile +++ b/lib/inets/src/inets_app/Makefile @@ -67,18 +67,15 @@ APPUP_TARGET = $(EBIN)/$(APPUP_FILE) # ---------------------------------------------------- -# INETS FLAGS -# ---------------------------------------------------- -INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' - - -# ---------------------------------------------------- # FLAGS # ---------------------------------------------------- -ERL_COMPILE_FLAGS += $(INETS_FLAGS) \ - +'{parse_transform,sys_pre_attributes}' \ - +'{attribute,insert,app_vsn,$(APP_VSN)}' +include inets.mk + +ERL_COMPILE_FLAGS += \ + $(INETS_FLAGS) \ + $(INETS_ERL_COMPILE_FLAGS) \ + -I../../include # ---------------------------------------------------- @@ -112,7 +109,8 @@ include $(ERL_TOP)/make/otp_release_targets.mk release_spec: opt $(INSTALL_DIR) $(RELSYSDIR)/src - $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/src/inets_app + $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/inets_app $(INSTALL_DIR) $(RELSYSDIR)/ebin $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin diff --git a/lib/inets/src/inets_app/inets.app.src b/lib/inets/src/inets_app/inets.app.src index 04f6365b98..cb036157a5 100644 --- a/lib/inets/src/inets_app/inets.app.src +++ b/lib/inets/src/inets_app/inets.app.src @@ -107,5 +107,6 @@ tftp_sup ]}, {registered,[inets_sup, httpc_manager]}, + %% If the "new" ssl is used then 'crypto' must be started before inets. {applications,[kernel,stdlib]}, {mod,{inets_app,[]}}]}. diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src index 718f37b09e..64fe664006 100644 --- a/lib/inets/src/inets_app/inets.appup.src +++ b/lib/inets/src/inets_app/inets.appup.src @@ -18,29 +18,24 @@ {"%VSN%", [ + {"5.3.3", + [ + {restart_application, inets} + ] + }, {"5.3.2", [ - {load_module, http_util, soft_purge, soft_purge, []}, - {load_module, httpc_cookie, soft_purge, soft_purge, []} + {restart_application, inets} ] }, {"5.3.1", [ - {load_module, http_util, soft_purge, soft_purge, []}, - {load_module, httpc, soft_purge, soft_purge, []}, - {load_module, httpc_cookie, soft_purge, soft_purge, []}, - {update, httpc_handler, soft, soft_purge, soft_purge, [httpc_manager]}, - {update, httpc_manager, soft, soft_purge, soft_purge, []} + {restart_application, inets} ] }, {"5.3", [ - {load_module, http_util, soft_purge, soft_purge, []}, - {load_module, httpc, soft_purge, soft_purge, []}, - {load_module, httpc_cookie, soft_purge, soft_purge, []}, - {update, httpc_handler, soft, soft_purge, soft_purge, [httpc_manager]}, - {update, httpc_manager, soft, soft_purge, soft_purge, []}, - {load_module, mod_esi, soft_purge, soft_purge, []} + {restart_application, inets} ] }, {"5.2", @@ -60,29 +55,24 @@ } ], [ + {"5.3.3", + [ + {restart_application, inets} + ] + }, {"5.3.2", [ - {load_module, http_util, soft_purge, soft_purge, []}, - {load_module, httpc_cookie, soft_purge, soft_purge, []} + {restart_application, inets} ] }, {"5.3.1", [ - {load_module, http_util, soft_purge, soft_purge, []}, - {load_module, httpc, soft_purge, soft_purge, []}, - {load_module, httpc_cookie, soft_purge, soft_purge, []}, - {update, httpc_handler, soft, soft_purge, soft_purge, [httpc_manager]}, - {update, httpc_manager, soft, soft_purge, soft_purge, []} + {restart_application, inets} ] }, {"5.3", [ - {load_module, http_util, soft_purge, soft_purge, []}, - {load_module, httpc, soft_purge, soft_purge, []}, - {load_module, httpc_cookie, soft_purge, soft_purge, []}, - {update, httpc_handler, soft, soft_purge, soft_purge, [httpc_manager]}, - {update, httpc_manager, soft, soft_purge, soft_purge, []}, - {load_module, mod_esi, soft_purge, soft_purge, []} + {restart_application, inets} ] }, {"5.2", diff --git a/lib/inets/src/inets_app/inets.mk b/lib/inets/src/inets_app/inets.mk new file mode 100644 index 0000000000..b6e9fe1d96 --- /dev/null +++ b/lib/inets/src/inets_app/inets.mk @@ -0,0 +1,45 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode + +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + +ifeq ($(INETS_TRACE), io) +ERL_COMPILE_FLAGS += -Dinets_trace_io +endif + +ifeq ($(INETS_DEBUG), true) +ERL_COMPILE_FLAGS += -Dinets_debug +endif + +ifeq ($(USE_INETS_HIPE), true) +ERL_COMPILE_FLAGS += +native +endif + +ifeq ($(WARN_UNUSED_WARS), true) +ERL_COMPILE_FLAGS += +warn_unused_vars +endif + +INETS_APP_VSN_COMPILE_FLAGS = \ + +'{parse_transform,sys_pre_attributes}' \ + +'{attribute,insert,app_vsn,$(APP_VSN)}' + +INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' + +INETS_ERL_COMPILE_FLAGS += \ + -pa $(ERL_TOP)/lib/inets/ebin \ + $(INETS_APP_VSN_COMPILE_FLAGS) + diff --git a/lib/inets/src/inets_app/inets_service.erl b/lib/inets/src/inets_app/inets_service.erl index 3499314d54..e9eb9892f2 100644 --- a/lib/inets/src/inets_app/inets_service.erl +++ b/lib/inets/src/inets_app/inets_service.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2007-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -61,5 +61,5 @@ behaviour_info(_) -> %% service_info() -> [{Property, Value}] | {error, Reason} -%% ex: http:service_info() -> [{profile, ProfileName}] +%% ex: httpc:service_info() -> [{profile, ProfileName}] %% httpd:service_info() -> [{host, Host}, {port, Port}] diff --git a/lib/inets/src/tftp/Makefile b/lib/inets/src/tftp/Makefile index b4339da1e2..759b70c8e4 100644 --- a/lib/inets/src/tftp/Makefile +++ b/lib/inets/src/tftp/Makefile @@ -56,17 +56,16 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) # ---------------------------------------------------- -# INETS FLAGS +# FLAGS # ---------------------------------------------------- -INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' +include ../inets_app/inets.mk -# ---------------------------------------------------- -# FLAGS -# ---------------------------------------------------- -ERL_COMPILE_FLAGS += $(INETS_FLAGS) \ - +'{parse_transform,sys_pre_attributes}' \ - +'{attribute,insert,app_vsn,$(APP_VSN)}' +ERL_COMPILE_FLAGS += \ + $(INETS_FLAGS) \ + $(INETS_ERL_COMPILE_FLAGS) \ + -I../../include \ + -I../inets_app # ---------------------------------------------------- @@ -87,9 +86,10 @@ docs: include $(ERL_TOP)/make/otp_release_targets.mk release_spec: opt - $(INSTALL_DIR) $(RELSYSDIR)/src - $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src - $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/src/tftp + $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/tftp + $(INSTALL_DIR) $(RELSYSDIR)/ebin $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin release_docs_spec: diff --git a/lib/inets/test/Makefile b/lib/inets/test/Makefile index 668752da9e..bb7f2186af 100644 --- a/lib/inets/test/Makefile +++ b/lib/inets/test/Makefile @@ -143,6 +143,8 @@ else INETS_FLAGS += -Dhttpd_security_verbosity=log endif +INETS_FLAGS += -pa ../../inets/ebin + INETS_ROOT = ../../inets MODULES = \ @@ -241,8 +243,11 @@ RELTESTSYSBINDIR = $(RELTESTSYSALLDATADIR)/bin # The path to the test_server ebin dir is needed when # running the target "targets". # ---------------------------------------------------- -ERL_COMPILE_FLAGS += -pa ../../../internal_tools/test_server/ebin \ - $(INCLUDES) $(FTP_FLAGS) $(INETS_FLAGS) +ERL_COMPILE_FLAGS += \ + -pa ../../../internal_tools/test_server/ebin \ + $(INCLUDES) \ + $(FTP_FLAGS) \ + $(INETS_FLAGS) # ---------------------------------------------------- # Targets diff --git a/lib/inets/test/ftp_suite_lib.erl b/lib/inets/test/ftp_suite_lib.erl index 75e1a5a7f9..5e27bc3a86 100644 --- a/lib/inets/test/ftp_suite_lib.erl +++ b/lib/inets/test/ftp_suite_lib.erl @@ -48,14 +48,17 @@ -ifdef(ftp_debug_client). -define(ftp_open(Host, Flags), - do_ftp_open(Host, [debug, {timeout, timer:seconds(15)}] ++ Flags)). + do_ftp_open(Host, [{debug, debug}, + {timeout, timer:seconds(15)} | Flags])). -else. -ifdef(ftp_trace_client). -define(ftp_open(Host, Flags), - do_ftp_open(Host, [trace, {timeout, timer:seconds(15)}] ++ Flags)). + do_ftp_open(Host, [{debug, trace}, + {timeout, timer:seconds(15)} | Flags])). -else. -define(ftp_open(Host, Flags), - do_ftp_open(Host, [verbose, {timeout, timer:seconds(15)}] ++ Flags)). + do_ftp_open(Host, [{verbose, true}, + {timeout, timer:seconds(15)} | Flags])). -endif. -endif. @@ -113,9 +116,7 @@ get_ftpd_host([Host|Hosts]) -> p("get_ftpd_host -> entry with" "~n Host: ~p" "~n", [Host]), - case (catch ftp:open({option_list, - [{host, Host}, {port, ?FTP_PORT}, - {timeout, 20000}]})) of + case (catch ftp:open(Host, [{port, ?FTP_PORT}, {timeout, 20000}])) of {ok, Pid} -> (catch ftp:close(Pid)), {ok, Host}; @@ -212,7 +213,7 @@ do_init_per_testcase(Case, Config) inets:start(), NewConfig = close_connection(watch_dog(Config)), Host = ftp_host(Config), - case (catch ?ftp_open(Host, [])) of + case (catch ?ftp_open(Host, [{mode, passive}])) of {ok, Pid} -> [{ftp, Pid} | data_dir(NewConfig)]; {skip, _} = SKIP -> @@ -225,9 +226,8 @@ do_init_per_testcase(Case, Config) inets:start(), NewConfig = close_connection(watch_dog(Config)), Host = ftp_host(Config), - case (catch ?ftp_open(Host, [])) of + case (catch ?ftp_open(Host, [{mode, active}])) of {ok, Pid} -> - ok = ftp:force_active(Pid), [{ftp, Pid} | data_dir(NewConfig)]; {skip, _} = SKIP -> SKIP @@ -240,11 +240,10 @@ do_init_per_testcase(Case, Config) io:format(user, "~n~n*** INIT ~w:~w ***~n~n", [?MODULE, Case]), NewConfig = close_connection(watch_dog(Config)), Host = ftp_host(Config), - Opts = [{host, Host}, - {port, ?FTP_PORT}, - {flags, [verbose]}, + Opts = [{port, ?FTP_PORT}, + {verbose, true}, {progress, {?MODULE, progress, #progress{}}}], - case ftp:open({option_list, Opts}) of + case ftp:open(Host, Opts) of {ok, Pid} -> ok = ftp:user(Pid, ?FTP_USER, ?FTP_PASS), [{ftp, Pid} | data_dir(NewConfig)]; @@ -257,22 +256,23 @@ do_init_per_testcase(Case, Config) -> inets:start(), NewConfig = close_connection(watch_dog(Config)), Host = ftp_host(Config), - Flags = + Opts1 = if ((Case =:= passive_ip_v6_disabled) orelse (Case =:= active_ip_v6_disabled)) -> - [ip_v6_disabled]; + [{ipfamily, inet}]; true -> [] end, - case (catch ?ftp_open(Host, Flags)) of + Opts2 = + case string:tokens(atom_to_list(Case), [$_]) of + [_, "active" | _] -> + [{mode, active} | Opts1]; + _ -> + [{mode, passive} | Opts1] + end, + case (catch ?ftp_open(Host, Opts2)) of {ok, Pid} -> - case string:tokens(atom_to_list(Case), [$_]) of - [_, "active"|_] -> - ok = ftp:force_active(Pid); - _ -> - ok - end, ok = ftp:user(Pid, ?FTP_USER, ?FTP_PASS), [{ftp, Pid} | data_dir(NewConfig)]; {skip, _} = SKIP -> @@ -365,6 +365,7 @@ open(Config) when is_list(Config) -> Host = ftp_host(Config), (catch tc_open(Host)). + tc_open(Host) -> {ok, Pid} = ?ftp_open(Host, []), ok = ftp:close(Pid), @@ -374,8 +375,9 @@ tc_open(Host) -> {flags, [verbose]}, {timeout, 30000}]}), ok = ftp:close(Pid1), - {error, ehost} = ftp:open({option_list, [{port, ?FTP_PORT}, - {flags, [verbose]}]}), + + {error, ehost} = + ftp:open({option_list, [{port, ?FTP_PORT}, {flags, [verbose]}]}), {ok, Pid2} = ftp:open(Host), ok = ftp:close(Pid2), @@ -408,6 +410,15 @@ tc_open(Host) -> {mode, cool}]}), test_server:sleep(100), ok = ftp:close(Pid6), + + {ok, Pid7} = + ftp:open(Host, [{port, ?FTP_PORT}, {verbose, true}, {timeout, 30000}]), + ok = ftp:close(Pid7), + + {ok, Pid8} = + ftp:open(Host, ?FTP_PORT), + ok = ftp:close(Pid8), + ok. @@ -420,7 +431,7 @@ open_port(suite) -> []; open_port(Config) when is_list(Config) -> Host = ftp_host(Config), - {ok, Pid} = ftp:open(Host, ?FTP_PORT), + {ok, Pid} = ftp:open(Host, [{port, ?FTP_PORT}]), ok = ftp:close(Pid), {error, ehost} = ftp:open(?BAD_HOST, []), ok. @@ -954,26 +965,39 @@ api_missuse(doc)-> ["Test that behaviour of the ftp process if the api is abused"]; api_missuse(suite) -> []; api_missuse(Config) when is_list(Config) -> + io:format("api_missuse -> entry~n", []), + Flag = process_flag(trap_exit, true), Pid = ?config(ftp, Config), Host = ftp_host(Config), - + %% Serious programming fault, connetion will be shut down - {error, {connection_terminated, 'API_violation'}} = - gen_server:call(Pid, {self(), foobar, 10}, infinity), + io:format("api_missuse -> verify bad call termination (~p)~n", [Pid]), + case (catch gen_server:call(Pid, {self(), foobar, 10}, infinity)) of + {error, {connection_terminated, 'API_violation'}} -> + ok; + Unexpected1 -> + exit({unexpected_result, Unexpected1}) + end, test_server:sleep(500), undefined = process_info(Pid, status), + io:format("api_missuse -> start new client~n", []), {ok, Pid2} = ?ftp_open(Host, []), %% Serious programming fault, connetion will be shut down + io:format("api_missuse -> verify bad cast termination~n", []), gen_server:cast(Pid2, {self(), foobar, 10}), test_server:sleep(500), undefined = process_info(Pid2, status), + io:format("api_missuse -> start new client~n", []), {ok, Pid3} = ?ftp_open(Host, []), %% Could be an innocent misstake the connection lives. + io:format("api_missuse -> verify bad bang~n", []), Pid3 ! foobar, test_server:sleep(500), {status, _} = process_info(Pid3, status), + process_flag(trap_exit, Flag), + io:format("api_missuse -> done~n", []), ok. @@ -1525,11 +1549,11 @@ split([C| Cs], I, Is) -> split([], I, Is) -> lists:reverse([lists:reverse(I)| Is]). -do_ftp_open(Host, Flags) -> +do_ftp_open(Host, Opts) -> io:format("do_ftp_open -> entry with" - "~n Host: ~p" - "~n Flags: ~p", [Host, Flags]), - case ftp:open(Host, Flags) of + "~n Host: ~p" + "~n Opts: ~p", [Host, Opts]), + case ftp:open(Host, Opts) of {ok, _} = OK -> OK; {error, Reason} -> diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index aa65fb1197..b5fd896001 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -87,8 +87,14 @@ all(suite) -> http_headers_dummy, http_bad_response, ssl_head, + ossl_head, + essl_head, ssl_get, + ossl_get, + essl_get, ssl_trace, + ossl_trace, + essl_trace, http_redirect, http_redirect_loop, http_internal_server_error, @@ -179,49 +185,66 @@ init_per_testcase(otp_8154_1 = Case, Config) -> init_per_testcase(Case, Config) -> init_per_testcase(Case, 2, Config). +init_per_testcase_ssl(Tag, PrivDir, SslConfFile, Config) -> + tsp("init_per_testcase_ssl -> stop ssl"), + application:stop(ssl), + Config2 = lists:keydelete(local_ssl_server, 1, Config), + %% Will start inets + tsp("init_per_testcase_ssl -> try start http server (including inets)"), + Server = inets_test_lib:start_http_server( + filename:join(PrivDir, SslConfFile), Tag), + tsp("init_per_testcase -> Server: ~p", [Server]), + [{local_ssl_server, Server} | Config2]. + init_per_testcase(Case, Timeout, Config) -> - io:format(user, "~n~n*** INIT ~w:~w[~w] ***~n~n", + io:format(user, "~n~n*** INIT ~w:[~w][~w] ***~n~n", [?MODULE, Timeout, Case]), - PrivDir = ?config(priv_dir, Config), + PrivDir = ?config(priv_dir, Config), + tsp("init_per_testcase -> stop inets"), application:stop(inets), - Dog = test_server:timetrap(inets_test_lib:minutes(Timeout)), - TmpConfig = lists:keydelete(watchdog, 1, Config), - IpConfFile = integer_to_list(?IP_PORT) ++ ".conf", + Dog = test_server:timetrap(inets_test_lib:minutes(Timeout)), + TmpConfig = lists:keydelete(watchdog, 1, Config), + IpConfFile = integer_to_list(?IP_PORT) ++ ".conf", SslConfFile = integer_to_list(?SSL_PORT) ++ ".conf", + %% inets:enable_trace(max, io, httpd), + %% inets:enable_trace(max, io, httpc), + inets:enable_trace(max, io, all), + NewConfig = case atom_to_list(Case) of - "ssl" ++ _ -> - application:stop(ssl), - TmpConfig2 = - lists:keydelete(local_ssl_server, 1, TmpConfig), - %% Will start inets - Server = - inets_test_lib:start_http_server( - filename:join(PrivDir, SslConfFile)), - [{watchdog, Dog}, {local_ssl_server, Server} | TmpConfig2]; + [$s, $s, $l | _] -> + init_per_testcase_ssl(ssl, PrivDir, SslConfFile, [{watchdog, Dog} | TmpConfig]); + + [$o, $s, $s, $l | _] -> + init_per_testcase_ssl(ossl, PrivDir, SslConfFile, [{watchdog, Dog} | TmpConfig]); + + [$e, $s, $s, $l | _] -> + init_per_testcase_ssl(essl, PrivDir, SslConfFile, [{watchdog, Dog} | TmpConfig]); + "proxy" ++ Rest -> - case Rest of - "_https_not_supported" -> - inets:start(), - case (catch application:start(ssl)) of - ok -> - [{watchdog, Dog} | TmpConfig]; - _ -> - [{skip, - "SSL does not seem to be supported"} - | TmpConfig] - end; - _ -> - case is_proxy_available(?PROXY, ?PROXY_PORT) of - true -> - inets:start(), - [{watchdog, Dog} | TmpConfig]; - false -> - [{skip, "Failed to contact proxy"} | - TmpConfig] - end - end; + case Rest of + "_https_not_supported" -> + tsp("init_per_testcase -> [proxy case] start inets"), + inets:start(), + tsp("init_per_testcase -> [proxy case] start ssl"), + case (catch application:start(ssl)) of + ok -> + [{watchdog, Dog} | TmpConfig]; + _ -> + [{skip, "SSL does not seem to be supported"} + | TmpConfig] + end; + _ -> + case is_proxy_available(?PROXY, ?PROXY_PORT) of + true -> + inets:start(), + [{watchdog, Dog} | TmpConfig]; + false -> + [{skip, "Failed to contact proxy"} | + TmpConfig] + end + end; _ -> TmpConfig2 = lists:keydelete(local_server, 1, TmpConfig), Server = @@ -231,13 +254,12 @@ init_per_testcase(Case, Timeout, Config) -> [{watchdog, Dog}, {local_server, Server} | TmpConfig2] end, - http:set_options([{proxy, {{?PROXY, ?PROXY_PORT}, - ["localhost", ?IPV6_LOCAL_HOST]}}]), - inets:enable_trace(max, io, httpc), - %% inets:enable_trace(max, io, all), + httpc:set_options([{proxy, {{?PROXY, ?PROXY_PORT}, + ["localhost", ?IPV6_LOCAL_HOST]}}]), %% snmp:set_trace([gen_tcp, inet_tcp, prim_inet]), NewConfig. + %%-------------------------------------------------------------------- %% Function: end_per_testcase(Case, Config) -> _ %% Case - atom() @@ -306,7 +328,7 @@ http_head(Config) when is_list(Config) -> ok -> Port = ?config(local_port, Config), URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", - case http:request(head, {URL, []}, [], []) of + case httpc:request(head, {URL, []}, [], []) of {ok, {{_,200,_}, [_ | _], []}} -> ok; {ok, WrongReply} -> @@ -337,7 +359,7 @@ http_get(Config) when is_list(Config) -> HttpOptions1 = [{timeout, Timeout}, {connect_timeout, ConnTimeout}], Options1 = [], Body = - case http:request(Method, Request, HttpOptions1, Options1) of + case httpc:request(Method, Request, HttpOptions1, Options1) of {ok, {{_,200,_}, [_ | _], ReplyBody = [_ | _]}} -> ReplyBody; {ok, UnexpectedReply1} -> @@ -346,12 +368,12 @@ http_get(Config) when is_list(Config) -> tsf({bad_reply, Error1}) end, - %% eqvivivalent to http:request(get, {URL, []}, [], []), + %% eqvivivalent to httpc:request(get, {URL, []}, [], []), inets_test_lib:check_body(Body), HttpOptions2 = [], Options2 = [{body_format, binary}], - case http:request(Method, Request, HttpOptions2, Options2) of + case httpc:request(Method, Request, HttpOptions2, Options2) of {ok, {{_,200,_}, [_ | _], Bin}} when is_binary(Bin) -> ok; {ok, {{_,200,_}, [_ | _], BadBin}} -> @@ -390,11 +412,11 @@ http_post(Config) when is_list(Config) -> Body = lists:duplicate(100, "1"), {ok, {{_,200,_}, [_ | _], [_ | _]}} = - http:request(post, {URL, [{"expect","100-continue"}], + httpc:request(post, {URL, [{"expect","100-continue"}], "text/plain", Body}, [], []), {ok, {{_,504,_}, [_ | _], []}} = - http:request(post, {URL, [{"expect","100-continue"}], + httpc:request(post, {URL, [{"expect","100-continue"}], "text/plain", "foobar"}, [], []); _ -> {skip, "Failed to start local http-server"} @@ -411,13 +433,13 @@ http_emulate_lower_versions(Config) when is_list(Config) -> Port = ?config(local_port, Config), URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", {ok, Body0} = - http:request(get, {URL, []}, [{version, "HTTP/0.9"}], []), + httpc:request(get, {URL, []}, [{version, "HTTP/0.9"}], []), inets_test_lib:check_body(Body0), {ok, {{"HTTP/1.0", 200, _}, [_ | _], Body1 = [_ | _]}} = - http:request(get, {URL, []}, [{version, "HTTP/1.0"}], []), + httpc:request(get, {URL, []}, [{version, "HTTP/1.0"}], []), inets_test_lib:check_body(Body1), {ok, {{"HTTP/1.1", 200, _}, [_ | _], Body2 = [_ | _]}} = - http:request(get, {URL, []}, [{version, "HTTP/1.1"}], []), + httpc:request(get, {URL, []}, [{version, "HTTP/1.1"}], []), inets_test_lib:check_body(Body2); _-> {skip, "Failed to start local http-server"} @@ -431,24 +453,24 @@ http_relaxed(doc) -> http_relaxed(suite) -> []; http_relaxed(Config) when is_list(Config) -> - ok = http:set_options([{ipv6, disabled}]), % also test the old option - %% ok = http:set_options([{ipfamily, inet}]), + ok = httpc:set_options([{ipv6, disabled}]), % also test the old option + %% ok = httpc:set_options([{ipfamily, inet}]), {DummyServerPid, Port} = dummy_server(self(), ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/missing_reason_phrase.html", {error, Reason} = - http:request(get, {URL, []}, [{relaxed, false}], []), + httpc:request(get, {URL, []}, [{relaxed, false}], []), test_server:format("Not relaxed: ~p~n", [Reason]), {ok, {{_, 200, _}, [_ | _], [_ | _]}} = - http:request(get, {URL, []}, [{relaxed, true}], []), + httpc:request(get, {URL, []}, [{relaxed, true}], []), DummyServerPid ! stop, - ok = http:set_options([{ipv6, enabled}]), - %% ok = http:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* + ok = httpc:set_options([{ipv6, enabled}]), + %% ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* ok. @@ -458,7 +480,7 @@ http_dummy_pipe(doc) -> http_dummy_pipe(suite) -> []; http_dummy_pipe(Config) when is_list(Config) -> - ok = http:set_options([{ipfamily, inet}]), + ok = httpc:set_options([{ipfamily, inet}]), {DummyServerPid, Port} = dummy_server(self(), ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/foobar.html", @@ -466,7 +488,7 @@ http_dummy_pipe(Config) when is_list(Config) -> test_pipeline(URL), DummyServerPid ! stop, - ok = http:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* + ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* ok. http_inets_pipe(doc) -> @@ -488,11 +510,11 @@ test_pipeline(URL) -> p("test_pipeline -> entry with" "~n URL: ~p", [URL]), - http:set_options([{pipeline_timeout, 50000}]), + httpc:set_options([{pipeline_timeout, 50000}]), p("test_pipeline -> issue (async) request 1"), {ok, RequestId1} = - http:request(get, {URL, []}, [], [{sync, false}]), + httpc:request(get, {URL, []}, [], [{sync, false}]), test_server:format("RequestId1: ~p~n", [RequestId1]), p("test_pipeline -> RequestId1: ~p", [RequestId1]), @@ -502,13 +524,13 @@ test_pipeline(URL) -> p("test_pipeline -> issue (async) request 2"), {ok, RequestId2} = - http:request(get, {URL, []}, [], [{sync, false}]), + httpc:request(get, {URL, []}, [], [{sync, false}]), tsp("RequestId2: ~p", [RequestId2]), p("test_pipeline -> RequestId2: ~p", [RequestId2]), p("test_pipeline -> issue (sync) request 3"), {ok, {{_,200,_}, [_ | _], [_ | _]}} = - http:request(get, {URL, []}, [], []), + httpc:request(get, {URL, []}, [], []), p("test_pipeline -> expect reply for (async) request 1 or 2"), receive @@ -544,18 +566,18 @@ test_pipeline(URL) -> p("test_pipeline -> issue (async) request 4"), {ok, RequestId3} = - http:request(get, {URL, []}, [], [{sync, false}]), + httpc:request(get, {URL, []}, [], [{sync, false}]), tsp("RequestId3: ~p", [RequestId3]), p("test_pipeline -> RequestId3: ~p", [RequestId3]), p("test_pipeline -> issue (async) request 5"), {ok, RequestId4} = - http:request(get, {URL, []}, [], [{sync, false}]), + httpc:request(get, {URL, []}, [], [{sync, false}]), tsp("RequestId4: ~p~n", [RequestId4]), p("test_pipeline -> RequestId4: ~p", [RequestId4]), p("test_pipeline -> cancel (async) request 4"), - ok = http:cancel_request(RequestId3), + ok = httpc:cancel_request(RequestId3), p("test_pipeline -> expect *no* reply for cancelled (async) request 4 (for 3 secs)"), receive @@ -607,7 +629,7 @@ http_trace(Config) when is_list(Config) -> ok -> Port = ?config(local_port, Config), URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", - case http:request(trace, {URL, []}, [], []) of + case httpc:request(trace, {URL, []}, [], []) of {ok, {{_,200,_}, [_ | _], "TRACE /dummy.html" ++ _}} -> ok; {ok, {{_,200,_}, [_ | _], WrongBody}} -> @@ -631,7 +653,7 @@ http_async(Config) when is_list(Config) -> Port = ?config(local_port, Config), URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", {ok, RequestId} = - http:request(get, {URL, []}, [], [{sync, false}]), + httpc:request(get, {URL, []}, [], [{sync, false}]), Body = receive @@ -644,8 +666,8 @@ http_async(Config) when is_list(Config) -> inets_test_lib:check_body(binary_to_list(Body)), {ok, NewRequestId} = - http:request(get, {URL, []}, [], [{sync, false}]), - ok = http:cancel_request(NewRequestId), + httpc:request(get, {URL, []}, [], [{sync, false}]), + ok = httpc:cancel_request(NewRequestId), receive {http, {NewRequestId, _NewResult}} -> test_server:fail(http_cancel_request_failed) @@ -669,9 +691,9 @@ http_save_to_file(Config) when is_list(Config) -> Port = ?config(local_port, Config), URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", {ok, saved_to_file} - = http:request(get, {URL, []}, [], [{stream, FilePath}]), + = httpc:request(get, {URL, []}, [], [{stream, FilePath}]), {ok, Bin} = file:read_file(FilePath), - {ok, {{_,200,_}, [_ | _], Body}} = http:request(URL), + {ok, {{_,200,_}, [_ | _], Body}} = httpc:request(URL), Bin == Body; _ -> {skip, "Failed to start local http-server"} @@ -690,7 +712,7 @@ http_save_to_file_async(Config) when is_list(Config) -> FilePath = filename:join(PrivDir, "dummy.html"), Port = ?config(local_port, Config), URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", - {ok, RequestId} = http:request(get, {URL, []}, [], + {ok, RequestId} = httpc:request(get, {URL, []}, [], [{stream, FilePath}, {sync, false}]), receive @@ -701,7 +723,7 @@ http_save_to_file_async(Config) when is_list(Config) -> end, {ok, Bin} = file:read_file(FilePath), - {ok, {{_,200,_}, [_ | _], Body}} = http:request(URL), + {ok, {{_,200,_}, [_ | _], Body}} = httpc:request(URL), Bin == Body; _ -> {skip, "Failed to start local http-server"} @@ -731,7 +753,7 @@ http_headers(Config) when is_list(Config) -> Date = httpd_util:rfc1123_date({date(), time()}), {ok, {{_,200,_}, [_ | _], [_ | _]}} = - http:request(get, {URL, [{"If-Modified-Since", + httpc:request(get, {URL, [{"If-Modified-Since", Mod}, {"From","[email protected]"}, {"Date", Date} @@ -742,7 +764,7 @@ http_headers(Config) when is_list(Config) -> CreatedSec+1)), {ok, {{_,200,_}, [_ | _], [_ | _]}} = - http:request(get, {URL, [{"If-UnModified-Since", + httpc:request(get, {URL, [{"If-UnModified-Since", Mod1} ]}, [], []), @@ -750,12 +772,12 @@ http_headers(Config) when is_list(Config) -> {ok, {{_,200,_}, [_ | _], [_ | _]}} = - http:request(get, {URL, [{"If-Match", + httpc:request(get, {URL, [{"If-Match", Tag} ]}, [], []), {ok, {{_,200,_}, [_ | _], _}} = - http:request(get, {URL, [{"If-None-Match", + httpc:request(get, {URL, [{"If-None-Match", "NotEtag,NeihterEtag"}, {"Connection", "Close"} ]}, [], []), @@ -773,7 +795,7 @@ http_headers_dummy(doc) -> http_headers_dummy(suite) -> []; http_headers_dummy(Config) when is_list(Config) -> - ok = http:set_options([{ipfamily, inet}]), + ok = httpc:set_options([{ipfamily, inet}]), {DummyServerPid, Port} = dummy_server(self(), ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy_headers.html", @@ -789,7 +811,7 @@ http_headers_dummy(Config) when is_list(Config) -> %% that the client header-handling code. This would not %% be a vaild http-request! {ok, {{_,200,_}, [_ | _], [_|_]}} = - http:request(post, + httpc:request(post, {URL, [{"Via", "1.0 fred, 1.1 nowhere.com (Apache/1.1)"}, @@ -828,7 +850,7 @@ http_headers_dummy(Config) when is_list(Config) -> ], "text/plain", FooBar}, [], []), DummyServerPid ! stop, - ok = http:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* + ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* ok. @@ -838,21 +860,21 @@ http_bad_response(doc) -> http_bad_response(suite) -> []; http_bad_response(Config) when is_list(Config) -> - ok = http:set_options([{ipfamily, inet}]), + ok = httpc:set_options([{ipfamily, inet}]), {DummyServerPid, Port} = dummy_server(self(), ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/missing_crlf.html", URL1 = ?URL_START ++ integer_to_list(Port) ++ "/wrong_statusline.html", - {error, timeout} = http:request(get, {URL, []}, [{timeout, 400}], []), + {error, timeout} = httpc:request(get, {URL, []}, [{timeout, 400}], []), - {error, Reason} = http:request(URL1), + {error, Reason} = httpc:request(URL1), test_server:format("Wrong Statusline: ~p~n", [Reason]), DummyServerPid ! stop, - ok = http:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* + ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* ok. @@ -862,69 +884,168 @@ ssl_head(doc) -> ssl_head(suite) -> []; ssl_head(Config) when is_list(Config) -> + ssl_head(ssl, Config). + +ossl_head(doc) -> + ["Same as http_head/1 but over ssl sockets."]; +ossl_head(suite) -> + []; +ossl_head(Config) when is_list(Config) -> + ssl_head(ossl, Config). + +essl_head(doc) -> + ["Same as http_head/1 but over ssl sockets."]; +essl_head(suite) -> + []; +essl_head(Config) when is_list(Config) -> + ssl_head(essl, Config). + +ssl_head(SslTag, Config) -> + tsp("ssl_head -> entry with" + "~n SslTag: ~p" + "~n Config: ~p", [SslTag, Config]), case ?config(local_ssl_server, Config) of ok -> - DataDir = ?config(data_dir, Config), - Port = ?config(local_ssl_port, Config), - URL = ?SSL_URL_START ++ integer_to_list(Port) ++ "/dummy.html", - CertFile = filename:join(DataDir, "ssl_client_cert.pem"), + DataDir = ?config(data_dir, Config), + Port = ?config(local_ssl_port, Config), + URL = ?SSL_URL_START ++ integer_to_list(Port) ++ "/dummy.html", + CertFile = filename:join(DataDir, "ssl_client_cert.pem"), SSLOptions = [{certfile, CertFile}, {keyfile, CertFile}], + SSLConfig = + case SslTag of + ssl -> + SSLOptions; + ossl -> + {ossl, SSLOptions}; + essl -> + {essl, SSLOptions} + end, + tsp("ssl_head -> make request using: " + "~n URL: ~p" + "~n SslTag: ~p" + "~n SSLOptions: ~p", [URL, SslTag, SSLOptions]), {ok, {{_,200, _}, [_ | _], []}} = - http:request(head, {URL, []}, [{ssl, SSLOptions}], []); + httpc:request(head, {URL, []}, [{ssl, SSLConfig}], []); {ok, _} -> - {skip, "Failed to start local http-server"}; + {skip, "local http-server not started"}; _ -> - {skip, "Failed to start SSL"} + {skip, "SSL not started"} end. + + %%------------------------------------------------------------------------- ssl_get(doc) -> ["Same as http_get/1 but over ssl sockets."]; ssl_get(suite) -> []; ssl_get(Config) when is_list(Config) -> + ssl_get(ssl, Config). + +ossl_get(doc) -> + ["Same as http_get/1 but over ssl sockets."]; +ossl_get(suite) -> + []; +ossl_get(Config) when is_list(Config) -> + ssl_get(ossl, Config). + +essl_get(doc) -> + ["Same as http_get/1 but over ssl sockets."]; +essl_get(suite) -> + []; +essl_get(Config) when is_list(Config) -> + ssl_get(essl, Config). + +ssl_get(SslTag, Config) when is_list(Config) -> case ?config(local_ssl_server, Config) of ok -> - DataDir = ?config(data_dir, Config), - Port = ?config(local_ssl_port, Config), - URL = ?SSL_URL_START ++ integer_to_list(Port) ++ "/dummy.html", - CertFile = filename:join(DataDir, "ssl_client_cert.pem"), + DataDir = ?config(data_dir, Config), + Port = ?config(local_ssl_port, Config), + URL = ?SSL_URL_START ++ integer_to_list(Port) ++ "/dummy.html", + CertFile = filename:join(DataDir, "ssl_client_cert.pem"), SSLOptions = [{certfile, CertFile}, {keyfile, CertFile}], - {ok, {{_,200, _}, [_ | _], Body = [_ | _]}} = - http:request(get, {URL, []}, [{ssl, SSLOptions}], []), - inets_test_lib:check_body(Body); + SSLConfig = + case SslTag of + ssl -> + SSLOptions; + ossl -> + {ossl, SSLOptions}; + essl -> + {essl, SSLOptions} + end, + tsp("ssl_get -> make request using: " + "~n URL: ~p" + "~n SslTag: ~p" + "~n SSLOptions: ~p", [URL, SslTag, SSLOptions]), + {ok, {{_,200, _}, [_ | _], Body = [_ | _]}} = + httpc:request(get, {URL, []}, [{ssl, SSLConfig}], []), + inets_test_lib:check_body(Body); {ok, _} -> {skip, "Failed to start local http-server"}; _ -> {skip, "Failed to start SSL"} end. + + %%------------------------------------------------------------------------- ssl_trace(doc) -> ["Same as http_trace/1 but over ssl sockets."]; ssl_trace(suite) -> []; ssl_trace(Config) when is_list(Config) -> + ssl_trace(ssl, Config). + +ossl_trace(doc) -> + ["Same as http_trace/1 but over ssl sockets."]; +ossl_trace(suite) -> + []; +ossl_trace(Config) when is_list(Config) -> + ssl_trace(ossl, Config). + +essl_trace(doc) -> + ["Same as http_trace/1 but over ssl sockets."]; +essl_trace(suite) -> + []; +essl_trace(Config) when is_list(Config) -> + ssl_trace(essl, Config). + +ssl_trace(SslTag, Config) when is_list(Config) -> case ?config(local_ssl_server, Config) of ok -> - DataDir = ?config(data_dir, Config), - Port = ?config(local_ssl_port, Config), - URL = ?SSL_URL_START ++ integer_to_list(Port) ++ "/dummy.html", - CertFile = filename:join(DataDir, "ssl_client_cert.pem"), + DataDir = ?config(data_dir, Config), + Port = ?config(local_ssl_port, Config), + URL = ?SSL_URL_START ++ integer_to_list(Port) ++ "/dummy.html", + CertFile = filename:join(DataDir, "ssl_client_cert.pem"), SSLOptions = [{certfile, CertFile}, {keyfile, CertFile}], - case http:request(trace, {URL, []}, [{ssl, SSLOptions}], []) of + SSLConfig = + case SslTag of + ssl -> + SSLOptions; + ossl -> + {ossl, SSLOptions}; + essl -> + {essl, SSLOptions} + end, + tsp("ssl_trace -> make request using: " + "~n URL: ~p" + "~n SslTag: ~p" + "~n SSLOptions: ~p", [URL, SslTag, SSLOptions]), + case httpc:request(trace, {URL, []}, [{ssl, SSLConfig}], []) of {ok, {{_,200, _}, [_ | _], "TRACE /dummy.html" ++ _}} -> ok; {ok, {{_,200,_}, [_ | _], WrongBody}} -> - test_server:fail({wrong_body, WrongBody}); + tsf({wrong_body, WrongBody}); {ok, WrongReply} -> - test_server:fail({wrong_reply, WrongReply}); + tsf({wrong_reply, WrongReply}); Error -> - test_server:fail({failed, Error}) + tsf({failed, Error}) end; {ok, _} -> {skip, "Failed to start local http-server"}; _ -> {skip, "Failed to start SSL"} end. + + %%------------------------------------------------------------------------- http_redirect(doc) -> ["Test redirect with dummy server as httpd does not implement" @@ -937,7 +1058,7 @@ http_redirect(Config) when is_list(Config) -> case ?config(local_server, Config) of ok -> tsp("http_redirect -> set ipfamily option to inet"), - ok = http:set_options([{ipfamily, inet}]), + ok = httpc:set_options([{ipfamily, inet}]), tsp("http_redirect -> start dummy server inet"), {DummyServerPid, Port} = dummy_server(self(), ipv4), @@ -948,29 +1069,29 @@ http_redirect(Config) when is_list(Config) -> tsp("http_redirect -> issue request 1: " "~n ~p", [URL300]), {ok, {{_,200,_}, [_ | _], [_|_]}} - = http:request(get, {URL300, []}, [], []), + = httpc:request(get, {URL300, []}, [], []), tsp("http_redirect -> issue request 2: " "~n ~p", [URL300]), {ok, {{_,300,_}, [_ | _], _}} = - http:request(get, {URL300, []}, [{autoredirect, false}], []), + httpc:request(get, {URL300, []}, [{autoredirect, false}], []), URL301 = ?URL_START ++ integer_to_list(Port) ++ "/301.html", tsp("http_redirect -> issue request 3: " "~n ~p", [URL301]), {ok, {{_,200,_}, [_ | _], [_|_]}} - = http:request(get, {URL301, []}, [], []), + = httpc:request(get, {URL301, []}, [], []), tsp("http_redirect -> issue request 4: " "~n ~p", [URL301]), {ok, {{_,200,_}, [_ | _], []}} - = http:request(head, {URL301, []}, [], []), + = httpc:request(head, {URL301, []}, [], []), tsp("http_redirect -> issue request 5: " "~n ~p", [URL301]), {ok, {{_,301,_}, [_ | _], [_|_]}} - = http:request(post, {URL301, [],"text/plain", "foobar"}, + = httpc:request(post, {URL301, [],"text/plain", "foobar"}, [], []), URL302 = ?URL_START ++ integer_to_list(Port) ++ "/302.html", @@ -978,8 +1099,8 @@ http_redirect(Config) when is_list(Config) -> tsp("http_redirect -> issue request 6: " "~n ~p", [URL302]), {ok, {{_,200,_}, [_ | _], [_|_]}} - = http:request(get, {URL302, []}, [], []), - case http:request(get, {URL302, []}, [], []) of + = httpc:request(get, {URL302, []}, [], []), + case httpc:request(get, {URL302, []}, [], []) of {ok, Reply7} -> case Reply7 of {{_,200,_}, [_ | _], [_|_]} -> @@ -1006,12 +1127,12 @@ http_redirect(Config) when is_list(Config) -> tsp("http_redirect -> issue request 7: " "~n ~p", [URL302]), {ok, {{_,200,_}, [_ | _], []}} - = http:request(head, {URL302, []}, [], []), + = httpc:request(head, {URL302, []}, [], []), tsp("http_redirect -> issue request 8: " "~n ~p", [URL302]), {ok, {{_,302,_}, [_ | _], [_|_]}} - = http:request(post, {URL302, [],"text/plain", "foobar"}, + = httpc:request(post, {URL302, [],"text/plain", "foobar"}, [], []), URL307 = ?URL_START ++ integer_to_list(Port) ++ "/307.html", @@ -1019,23 +1140,23 @@ http_redirect(Config) when is_list(Config) -> tsp("http_redirect -> issue request 9: " "~n ~p", [URL307]), {ok, {{_,200,_}, [_ | _], [_|_]}} - = http:request(get, {URL307, []}, [], []), + = httpc:request(get, {URL307, []}, [], []), tsp("http_redirect -> issue request 10: " "~n ~p", [URL307]), {ok, {{_,200,_}, [_ | _], []}} - = http:request(head, {URL307, []}, [], []), + = httpc:request(head, {URL307, []}, [], []), tsp("http_redirect -> issue request 11: " "~n ~p", [URL307]), {ok, {{_,307,_}, [_ | _], [_|_]}} - = http:request(post, {URL307, [],"text/plain", "foobar"}, + = httpc:request(post, {URL307, [],"text/plain", "foobar"}, [], []), tsp("http_redirect -> stop dummy server"), DummyServerPid ! stop, tsp("http_redirect -> reset ipfamily option (to inet6fb4)"), - ok = http:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* + ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* tsp("http_redirect -> done"), ok; @@ -1051,15 +1172,15 @@ http_redirect_loop(doc) -> http_redirect_loop(suite) -> []; http_redirect_loop(Config) when is_list(Config) -> - ok = http:set_options([{ipfamily, inet}]), + ok = httpc:set_options([{ipfamily, inet}]), {DummyServerPid, Port} = dummy_server(self(), ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/redirectloop.html", {ok, {{_,300,_}, [_ | _], _}} - = http:request(get, {URL, []}, [], []), + = httpc:request(get, {URL, []}, [], []), DummyServerPid ! stop, - ok = http:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* + ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* ok. %%------------------------------------------------------------------------- @@ -1068,13 +1189,13 @@ http_internal_server_error(doc) -> http_internal_server_error(suite) -> []; http_internal_server_error(Config) when is_list(Config) -> - ok = http:set_options([{ipfamily, inet}]), + ok = httpc:set_options([{ipfamily, inet}]), {DummyServerPid, Port} = dummy_server(self(), ipv4), URL500 = ?URL_START ++ integer_to_list(Port) ++ "/500.html", {ok, {{_,500,_}, [_ | _], _}} - = http:request(get, {URL500, []}, [], []), + = httpc:request(get, {URL500, []}, [], []), URL503 = ?URL_START ++ integer_to_list(Port) ++ "/503.html", @@ -1084,16 +1205,16 @@ http_internal_server_error(Config) when is_list(Config) -> ets:insert(unavailable, {503, unavailable}), {ok, {{_,200, _}, [_ | _], [_|_]}} = - http:request(get, {URL503, []}, [], []), + httpc:request(get, {URL503, []}, [], []), ets:insert(unavailable, {503, long_unavailable}), {ok, {{_,503, _}, [_ | _], [_|_]}} = - http:request(get, {URL503, []}, [], []), + httpc:request(get, {URL503, []}, [], []), ets:delete(unavailable), DummyServerPid ! stop, - ok = http:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* + ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* ok. @@ -1103,7 +1224,7 @@ http_userinfo(doc) -> http_userinfo(suite) -> []; http_userinfo(Config) when is_list(Config) -> - ok = http:set_options([{ipfamily, inet}]), + ok = httpc:set_options([{ipfamily, inet}]), {DummyServerPid, Port} = dummy_server(self(), ipv4), @@ -1111,16 +1232,16 @@ http_userinfo(Config) when is_list(Config) -> ++ integer_to_list(Port) ++ "/userinfo.html", {ok, {{_,200,_}, [_ | _], _}} - = http:request(get, {URLAuth, []}, [], []), + = httpc:request(get, {URLAuth, []}, [], []), URLUnAuth = "http://alladin:foobar@localhost:" ++ integer_to_list(Port) ++ "/userinfo.html", {ok, {{_,401, _}, [_ | _], _}} = - http:request(get, {URLUnAuth, []}, [], []), + httpc:request(get, {URLUnAuth, []}, [], []), DummyServerPid ! stop, - ok = http:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* + ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* ok. @@ -1130,7 +1251,7 @@ http_cookie(doc) -> http_cookie(suite) -> []; http_cookie(Config) when is_list(Config) -> - ok = http:set_options([{cookies, enabled}, {ipfamily, inet}]), + ok = httpc:set_options([{cookies, enabled}, {ipfamily, inet}]), {DummyServerPid, Port} = dummy_server(self(), ipv4), URLStart = ?URL_START @@ -1139,19 +1260,19 @@ http_cookie(Config) when is_list(Config) -> URLCookie = URLStart ++ "/cookie.html", {ok, {{_,200,_}, [_ | _], [_|_]}} - = http:request(get, {URLCookie, []}, [], []), + = httpc:request(get, {URLCookie, []}, [], []), ets:new(cookie, [named_table, public, set]), ets:insert(cookie, {cookies, true}), {ok, {{_,200,_}, [_ | _], [_|_]}} - = http:request(get, {URLStart ++ "/", []}, [], []), + = httpc:request(get, {URLStart ++ "/", []}, [], []), ets:delete(cookie), - ok = http:set_options([{cookies, disabled}, {ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* + ok = httpc:set_options([{cookies, disabled}, {ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* DummyServerPid ! stop, - ok = http:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6************ + ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6************ ok. %%------------------------------------------------------------------------- @@ -1162,7 +1283,7 @@ proxy_options(suite) -> proxy_options(Config) when is_list(Config) -> case ?config(skip, Config) of undefined -> - case http:request(options, {?PROXY_URL, []}, [], []) of + case httpc:request(options, {?PROXY_URL, []}, [], []) of {ok, {{_,200,_}, Headers, _}} -> case lists:keysearch("allow", 1, Headers) of {value, {"allow", _}} -> @@ -1186,7 +1307,7 @@ proxy_head(suite) -> proxy_head(Config) when is_list(Config) -> case ?config(skip, Config) of undefined -> - case http:request(head, {?PROXY_URL, []}, [], []) of + case httpc:request(head, {?PROXY_URL, []}, [], []) of {ok, {{_,200, _}, [_ | _], []}} -> ok; Unexpected -> @@ -1205,7 +1326,7 @@ proxy_get(suite) -> proxy_get(Config) when is_list(Config) -> case ?config(skip, Config) of undefined -> - case http:request(get, {?PROXY_URL, []}, [], []) of + case httpc:request(get, {?PROXY_URL, []}, [], []) of {ok, {{_,200,_}, [_ | _], Body = [_ | _]}} -> inets_test_lib:check_body(Body); Unexpected -> @@ -1257,7 +1378,7 @@ proxy_emulate_lower_versions(Config) when is_list(Config) -> end. pelv_get(Version) -> - http:request(get, {?PROXY_URL, []}, [{version, Version}], []). + httpc:request(get, {?PROXY_URL, []}, [{version, Version}], []). %%------------------------------------------------------------------------- proxy_trace(doc) -> @@ -1266,7 +1387,7 @@ proxy_trace(suite) -> []; proxy_trace(Config) when is_list(Config) -> %%{ok, {{_,200,_}, [_ | _], "TRACE " ++ _}} = - %% http:request(trace, {?PROXY_URL, []}, [], []), + %% httpc:request(trace, {?PROXY_URL, []}, [], []), {skip, "HTTP TRACE is no longer allowed on the ?PROXY_URL server due " "to security reasons"}. @@ -1281,7 +1402,7 @@ proxy_post(suite) -> proxy_post(Config) when is_list(Config) -> case ?config(skip, Config) of undefined -> - case http:request(post, {?PROXY_URL, [], + case httpc:request(post, {?PROXY_URL, [], "text/plain", "foobar"}, [],[]) of {ok, {{_,405,_}, [_ | _], [_ | _]}} -> ok; @@ -1303,7 +1424,7 @@ proxy_put(suite) -> proxy_put(Config) when is_list(Config) -> case ?config(skip, Config) of undefined -> - case http:request(put, {"http://www.erlang.org/foobar.html", [], + case httpc:request(put, {"http://www.erlang.org/foobar.html", [], "html", "<html> <body><h1> foo </h1>" "<p>bar</p> </body></html>"}, [], []) of {ok, {{_,405,_}, [_ | _], [_ | _]}} -> @@ -1328,7 +1449,7 @@ proxy_delete(Config) when is_list(Config) -> case ?config(skip, Config) of undefined -> URL = ?PROXY_URL ++ "/foobar.html", - case http:request(delete, {URL, []}, [], []) of + case httpc:request(delete, {URL, []}, [], []) of {ok, {{_,404,_}, [_ | _], [_ | _]}} -> ok; Unexpected -> @@ -1348,7 +1469,7 @@ proxy_headers(Config) when is_list(Config) -> case ?config(skip, Config) of undefined -> {ok, {{_,200,_}, [_ | _], [_ | _]}} - = http:request(get, {?PROXY_URL, + = httpc:request(get, {?PROXY_URL, [ {"Accept", "text/*, text/html," @@ -1383,7 +1504,7 @@ proxy_auth(Config) when is_list(Config) -> %% atleast the code for sending the header does not crash! case ?config(skip, Config) of undefined -> - case http:request(get, {?PROXY_URL, []}, + case httpc:request(get, {?PROXY_URL, []}, [{proxy_auth, {"foo", "bar"}}], []) of {ok, {{_,200, _}, [_ | _], [_|_]}} -> ok; @@ -1403,7 +1524,7 @@ http_server_does_not_exist(suite) -> []; http_server_does_not_exist(Config) when is_list(Config) -> {error, _} = - http:request(get, {"http://localhost:" ++ + httpc:request(get, {"http://localhost:" ++ integer_to_list(?NOT_IN_USE_PORT) ++ "/", []},[], []), ok. @@ -1418,7 +1539,7 @@ page_does_not_exist(Config) when is_list(Config) -> Port = ?config(local_port, Config), URL = ?URL_START ++ integer_to_list(Port) ++ "/doesnotexist.html", {ok, {{_,404,_}, [_ | _], [_ | _]}} - = http:request(get, {URL, []}, [], []), + = httpc:request(get, {URL, []}, [], []), ok. @@ -1432,7 +1553,7 @@ proxy_page_does_not_exist(Config) when is_list(Config) -> undefined -> URL = ?PROXY_URL ++ "/doesnotexist.html", {ok, {{_,404,_}, [_ | _], [_ | _]}} = - http:request(get, {URL, []}, [], []), + httpc:request(get, {URL, []}, [], []), ok; Reason -> {skip, Reason} @@ -1446,7 +1567,7 @@ proxy_https_not_supported(doc) -> proxy_https_not_supported(suite) -> []; proxy_https_not_supported(Config) when is_list(Config) -> - Result = http:request(get, {"https://login.yahoo.com", []}, [], []), + Result = httpc:request(get, {"https://login.yahoo.com", []}, [], []), case Result of {error, Reason} -> %% ok so far @@ -1478,10 +1599,10 @@ http_stream(Config) when is_list(Config) -> Port = ?config(local_port, Config), URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", {ok, {{_,200,_}, [_ | _], Body}} = - http:request(get, {URL, []}, [], []), + httpc:request(get, {URL, []}, [], []), {ok, RequestId} = - http:request(get, {URL, []}, [], [{sync, false}, + httpc:request(get, {URL, []}, [], [{sync, false}, {stream, self}]), receive @@ -1506,7 +1627,7 @@ http_stream_once(Config) when is_list(Config) -> "~n Config: ~p", [Config]), p("http_stream_once -> set ipfamily to inet", []), - ok = http:set_options([{ipfamily, inet}]), + ok = httpc:set_options([{ipfamily, inet}]), p("http_stream_once -> start dummy server", []), {DummyServerPid, Port} = dummy_server(self(), ipv4), @@ -1521,18 +1642,18 @@ http_stream_once(Config) when is_list(Config) -> p("http_stream_once -> stop dummy server", []), DummyServerPid ! stop, p("http_stream_once -> set ipfamily to inet6fb4", []), - ok = http:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* + ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* p("http_stream_once -> done", []), ok. once(URL) -> p("once -> issue sync request for ~p", [URL]), {ok, {{_,200,_}, [_ | _], Body}} = - http:request(get, {URL, []}, [], []), + httpc:request(get, {URL, []}, [], []), p("once -> issue async (self stream) request for ~p", [URL]), {ok, RequestId} = - http:request(get, {URL, []}, [], [{sync, false}, + httpc:request(get, {URL, []}, [], [{sync, false}, {stream, {self, once}}]), p("once -> await stream_start reply for (async) request ~p", [RequestId]), @@ -1576,10 +1697,10 @@ proxy_stream(Config) when is_list(Config) -> case ?config(skip, Config) of undefined -> {ok, {{_,200,_}, [_ | _], Body}} = - http:request(get, {?PROXY_URL, []}, [], []), + httpc:request(get, {?PROXY_URL, []}, [], []), {ok, RequestId} = - http:request(get, {?PROXY_URL, []}, [], + httpc:request(get, {?PROXY_URL, []}, [], [{sync, false}, {stream, self}]), receive @@ -1659,7 +1780,7 @@ ipv6(Config) when is_list(Config) -> URL = "http://[" ++ ?IPV6_LOCAL_HOST ++ "]:" ++ integer_to_list(Port) ++ "/foobar.html", {ok, {{_,200,_}, [_ | _], [_|_]}} = - http:request(get, {URL, []}, [], []), + httpc:request(get, {URL, []}, [], []), DummyServerPid ! stop, ok; @@ -1677,11 +1798,11 @@ headers_as_is(Config) when is_list(Config) -> Port = ?config(local_port, Config), URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", {ok, {{_,200,_}, [_|_], [_|_]}} = - http:request(get, {URL, [{"Host", "localhost"},{"Te", ""}]}, + httpc:request(get, {URL, [{"Host", "localhost"},{"Te", ""}]}, [], [{headers_as_is, true}]), {ok, {{_,400,_}, [_|_], [_|_]}} = - http:request(get, {URL, [{"Te", ""}]},[], [{headers_as_is, true}]), + httpc:request(get, {URL, [{"Te", ""}]},[], [{headers_as_is, true}]), ok. @@ -1696,13 +1817,13 @@ options(Config) when is_list(Config) -> Port = ?config(local_port, Config), URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", {ok, {{_,200,_}, [_ | _], Bin}} - = http:request(get, {URL, []}, [{foo, bar}], + = httpc:request(get, {URL, []}, [{foo, bar}], %% Ignore unknown options [{body_format, binary}, {foo, bar}]), true = is_binary(Bin), {ok, {200, [_|_]}} - = http:request(get, {URL, []}, [{timeout, infinity}], + = httpc:request(get, {URL, []}, [{timeout, infinity}], [{full_result, false}]); _ -> {skip, "Failed to start local http-server"} @@ -1715,17 +1836,17 @@ http_invalid_http(doc) -> http_invalid_http(suite) -> []; http_invalid_http(Config) when is_list(Config) -> - ok = http:set_options([{ipfamily, inet}]), + ok = httpc:set_options([{ipfamily, inet}]), {DummyServerPid, Port} = dummy_server(self(), ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/invalid_http.html", {error, {could_not_parse_as_http, _} = Reason} = - http:request(get, {URL, []}, [], []), + httpc:request(get, {URL, []}, [], []), test_server:format("Parse error: ~p ~n", [Reason]), DummyServerPid ! stop, - ok = http:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* + ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* ok. @@ -1762,7 +1883,7 @@ empty_body_otp_6243(Config) when is_list(Config) -> Port = ?config(local_port, Config), URL = ?URL_START ++ integer_to_list(Port) ++ "/empty.html", {ok, {{_,200,_}, [_ | _], []}} = - http:request(get, {URL, []}, [{timeout, 500}], []). + httpc:request(get, {URL, []}, [{timeout, 500}], []). %%------------------------------------------------------------------------- @@ -1772,14 +1893,14 @@ transfer_encoding_otp_6807(doc) -> transfer_encoding_otp_6807(suite) -> []; transfer_encoding_otp_6807(Config) when is_list(Config) -> - ok = http:set_options([{ipfamily, inet}]), + ok = httpc:set_options([{ipfamily, inet}]), {DummyServerPid, Port} = dummy_server(self(), ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/capital_transfer_encoding.html", - {ok, {{_,200,_}, [_|_], [_ | _]}} = http:request(URL), + {ok, {{_,200,_}, [_|_], [_ | _]}} = httpc:request(URL), DummyServerPid ! stop, - ok = http:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* + ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* ok. @@ -1805,13 +1926,13 @@ empty_response_header_otp_6830(doc) -> empty_response_header_otp_6830(suite) -> []; empty_response_header_otp_6830(Config) when is_list(Config) -> - ok = http:set_options([{ipfamily, inet}]), + ok = httpc:set_options([{ipfamily, inet}]), {DummyServerPid, Port} = dummy_server(self(), ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/no_headers.html", - {ok, {{_,200,_}, [], [_ | _]}} = http:request(URL), + {ok, {{_,200,_}, [], [_ | _]}} = httpc:request(URL), DummyServerPid ! stop, - ok = http:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* + ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* ok. @@ -1822,13 +1943,13 @@ no_content_204_otp_6982(doc) -> no_content_204_otp_6982(suite) -> []; no_content_204_otp_6982(Config) when is_list(Config) -> - ok = http:set_options([{ipfamily, inet}]), + ok = httpc:set_options([{ipfamily, inet}]), {DummyServerPid, Port} = dummy_server(self(), ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/no_content.html", - {ok, {{_,204,_}, [], []}} = http:request(URL), + {ok, {{_,204,_}, [], []}} = httpc:request(URL), DummyServerPid ! stop, - ok = http:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* + ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* ok. @@ -1840,13 +1961,13 @@ missing_CR_otp_7304(doc) -> missing_CR_otp_7304(suite) -> []; missing_CR_otp_7304(Config) when is_list(Config) -> - ok = http:set_options([{ipfamily, inet}]), + ok = httpc:set_options([{ipfamily, inet}]), {DummyServerPid, Port} = dummy_server(self(), ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/missing_CR.html", - {ok, {{_,200,_}, _, [_ | _]}} = http:request(URL), + {ok, {{_,200,_}, _, [_ | _]}} = httpc:request(URL), DummyServerPid ! stop, - ok = http:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* + ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* ok. @@ -1860,15 +1981,15 @@ otp_7883_1(doc) -> otp_7883_1(suite) -> []; otp_7883_1(Config) when is_list(Config) -> - ok = http:set_options([{ipfamily, inet}]), + ok = httpc:set_options([{ipfamily, inet}]), {DummyServerPid, Port} = dummy_server(self(), ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/just_close.html", - {error, socket_closed_remotely} = http:request(URL), + {error, socket_closed_remotely} = httpc:request(URL), DummyServerPid ! stop, - ok = http:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* + ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* ok. otp_7883_2(doc) -> @@ -1876,7 +1997,7 @@ otp_7883_2(doc) -> otp_7883_2(suite) -> []; otp_7883_2(Config) when is_list(Config) -> - ok = http:set_options([{ipfamily, inet}]), + ok = httpc:set_options([{ipfamily, inet}]), {DummyServerPid, Port} = dummy_server(self(), ipv4), @@ -1885,9 +2006,9 @@ otp_7883_2(Config) when is_list(Config) -> Request = {URL, []}, HttpOptions = [], Options = [{sync, false}], - Profile = http:default_profile(), + Profile = httpc:default_profile(), {ok, RequestId} = - http:request(Method, Request, HttpOptions, Options, Profile), + httpc:request(Method, Request, HttpOptions, Options, Profile), ok = receive {http, {RequestId, {error, socket_closed_remotely}}} -> @@ -1895,7 +2016,7 @@ otp_7883_2(Config) when is_list(Config) -> end, DummyServerPid ! stop, - ok = http:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* + ok = httpc:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* ok. @@ -1966,7 +2087,7 @@ run_clients(NumClients, ServerPort, SeqNumServer) -> fun() -> io:format("[~w] client started - " "issue request~n", [Id]), - case http:request(Url) of + case httpc:request(Url) of {ok, {{_,200,_}, _, Resp}} -> io:format("[~w] 200 response: " "~p~n", [Id, Resp]), @@ -2354,7 +2475,7 @@ otp_8352(Config) when is_list(Config) -> ConnOptions = [{max_sessions, MaxSessions}, {max_keep_alive_length, MaxKeepAlive}, {keep_alive_timeout, KeepAliveTimeout}], - http:set_options(ConnOptions), + httpc:set_options(ConnOptions), Method = get, Port = ?config(local_port, Config), @@ -2366,9 +2487,9 @@ otp_8352(Config) when is_list(Config) -> Options1 = [{socket_opts, [{tos, 87}, {recbuf, 16#FFFF}, {sndbuf, 16#FFFF}]}], - case http:request(Method, Request, HttpOptions1, Options1) of + case httpc:request(Method, Request, HttpOptions1, Options1) of {ok, {{_,200,_}, [_ | _], ReplyBody1 = [_ | _]}} -> - %% equivaliant to http:request(get, {URL, []}, [], []), + %% equivaliant to httpc:request(get, {URL, []}, [], []), inets_test_lib:check_body(ReplyBody1); {ok, UnexpectedReply1} -> tsf({unexpected_reply, UnexpectedReply1}); @@ -2382,9 +2503,9 @@ otp_8352(Config) when is_list(Config) -> Options2 = [{socket_opts, [{tos, 84}, {recbuf, 32#1FFFF}, {sndbuf, 32#1FFFF}]}], - case http:request(Method, Request, HttpOptions2, Options2) of + case httpc:request(Method, Request, HttpOptions2, Options2) of {ok, {{_,200,_}, [_ | _], ReplyBody2 = [_ | _]}} -> - %% equivaliant to http:request(get, {URL, []}, [], []), + %% equivaliant to httpc:request(get, {URL, []}, [], []), inets_test_lib:check_body(ReplyBody2); {ok, UnexpectedReply2} -> tsf({unexpected_reply, UnexpectedReply2}); @@ -2406,13 +2527,13 @@ otp_8371(doc) -> otp_8371(suite) -> []; otp_8371(Config) when is_list(Config) -> - ok = http:set_options([{ipv6, disabled}]), % also test the old option + ok = httpc:set_options([{ipv6, disabled}]), % also test the old option {DummyServerPid, Port} = dummy_server(self(), ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/ensure_host_header_with_port.html", - case http:request(get, {URL, []}, [], []) of + case httpc:request(get, {URL, []}, [], []) of {ok, Result} -> case Result of {{_, 200, _}, _Headers, Body} -> @@ -2436,7 +2557,7 @@ otp_8371(Config) when is_list(Config) -> end, DummyServerPid ! stop, - ok = http:set_options([{ipv6, enabled}]), + ok = httpc:set_options([{ipv6, enabled}]), ok. @@ -2537,7 +2658,7 @@ receive_streamed_body(RequestId, Body) -> end. receive_streamed_body(RequestId, Body, Pid) -> - http:stream_next(Pid), + httpc:stream_next(Pid), test_server:format("~p:receive_streamed_body -> requested next stream ~n", [?MODULE]), receive {http, {RequestId, stream, BinBodyPart}} -> @@ -2921,11 +3042,11 @@ provocate_not_modified_bug(Url) -> Timeout = 15000, %% 15s should be plenty {ok, {{_, 200, _}, ReplyHeaders, _Body}} = - http:request(get, {Url, []}, [{timeout, Timeout}], []), + httpc:request(get, {Url, []}, [{timeout, Timeout}], []), Etag = pick_header(ReplyHeaders, "ETag"), Last = pick_header(ReplyHeaders, "last-modified"), - case http:request(get, {Url, [{"If-None-Match", Etag}, + case httpc:request(get, {Url, [{"If-None-Match", Etag}, {"If-Modified-Since", Last}]}, [{timeout, 15000}], []) of diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl index 7403d4a643..3c9b5e41a7 100644 --- a/lib/inets/test/httpd_SUITE.erl +++ b/lib/inets/test/httpd_SUITE.erl @@ -32,44 +32,176 @@ init_per_suite/1, end_per_suite/1]). %% Test cases must be exported. --export([ip/1, ssl/1, http_1_1_ip/1, http_1_0_ip/1, http_0_9_ip/1, - ipv6/1, tickets/1]). +-export([ + ip/1, + ssl/1, pssl/1, ossl/1, essl/1, + http_1_1_ip/1, + http_1_0_ip/1, + http_0_9_ip/1, + ipv6/1, + tickets/1 + ]). %% Core Server tests --export([ip_mod_alias/1, ip_mod_actions/1, ip_mod_security/1, ip_mod_auth/1, - ip_mod_auth_api/1, ip_mod_auth_mnesia_api/1, - ip_mod_htaccess/1, ip_mod_cgi/1, ip_mod_esi/1, - ip_mod_get/1, ip_mod_head/1, ip_mod_all/1, ip_load_light/1, - ip_load_medium/1, ip_load_heavy/1, ip_dos_hostname/1, - ip_time_test/1, ip_block_disturbing_idle/1, - ip_block_non_disturbing_idle/1, ip_block_503/1, - ip_block_disturbing_active/1, ip_block_non_disturbing_active/1, +-export([ + ip_mod_alias/1, + ip_mod_actions/1, + ip_mod_security/1, + ip_mod_auth/1, + ip_mod_auth_api/1, + ip_mod_auth_mnesia_api/1, + ip_mod_htaccess/1, + ip_mod_cgi/1, + ip_mod_esi/1, + ip_mod_get/1, + ip_mod_head/1, + ip_mod_all/1, + ip_load_light/1, + ip_load_medium/1, + ip_load_heavy/1, + ip_dos_hostname/1, + ip_time_test/1, + ip_block_disturbing_idle/1, + ip_block_non_disturbing_idle/1, + ip_block_503/1, + ip_block_disturbing_active/1, + ip_block_non_disturbing_active/1, ip_block_disturbing_active_timeout_not_released/1, ip_block_disturbing_active_timeout_released/1, ip_block_non_disturbing_active_timeout_not_released/1, ip_block_non_disturbing_active_timeout_released/1, ip_block_disturbing_blocker_dies/1, ip_block_non_disturbing_blocker_dies/1, - ip_restart_no_block/1, ip_restart_disturbing_block/1, + ip_restart_no_block/1, + ip_restart_disturbing_block/1, ip_restart_non_disturbing_block/1 ]). --export([ssl_mod_alias/1, ssl_mod_actions/1, ssl_mod_security/1, - ssl_mod_auth/1, ssl_mod_auth_api/1, - ssl_mod_auth_mnesia_api/1, ssl_mod_htaccess/1, - ssl_mod_cgi/1, ssl_mod_esi/1, ssl_mod_get/1, ssl_mod_head/1, - ssl_mod_all/1, ssl_load_light/1, ssl_load_medium/1, - ssl_load_heavy/1, ssl_dos_hostname/1, ssl_time_test/1, - ssl_restart_no_block/1, ssl_restart_disturbing_block/1, - ssl_restart_non_disturbing_block/1, ssl_block_disturbing_idle/1, - ssl_block_non_disturbing_idle/1, ssl_block_503/1, - ssl_block_disturbing_active/1, ssl_block_non_disturbing_active/1, - ssl_block_disturbing_active_timeout_not_released/1, - ssl_block_disturbing_active_timeout_released/1, - ssl_block_non_disturbing_active_timeout_not_released/1, - ssl_block_non_disturbing_active_timeout_released/1, - ssl_block_disturbing_blocker_dies/1, - ssl_block_non_disturbing_blocker_dies/1]). +-export([ + pssl_mod_alias/1, + ossl_mod_alias/1, + essl_mod_alias/1, + + pssl_mod_actions/1, + ossl_mod_actions/1, + essl_mod_actions/1, + + pssl_mod_security/1, + ossl_mod_security/1, + essl_mod_security/1, + + pssl_mod_auth/1, + ossl_mod_auth/1, + essl_mod_auth/1, + + pssl_mod_auth_api/1, + ossl_mod_auth_api/1, + essl_mod_auth_api/1, + + pssl_mod_auth_mnesia_api/1, + ossl_mod_auth_mnesia_api/1, + essl_mod_auth_mnesia_api/1, + + pssl_mod_htaccess/1, + ossl_mod_htaccess/1, + essl_mod_htaccess/1, + + pssl_mod_cgi/1, + ossl_mod_cgi/1, + essl_mod_cgi/1, + + pssl_mod_esi/1, + ossl_mod_esi/1, + essl_mod_esi/1, + + pssl_mod_get/1, + ossl_mod_get/1, + essl_mod_get/1, + + pssl_mod_head/1, + ossl_mod_head/1, + essl_mod_head/1, + + pssl_mod_all/1, + ossl_mod_all/1, + essl_mod_all/1, + + pssl_load_light/1, + ossl_load_light/1, + essl_load_light/1, + + pssl_load_medium/1, + ossl_load_medium/1, + essl_load_medium/1, + + pssl_load_heavy/1, + ossl_load_heavy/1, + essl_load_heavy/1, + + pssl_dos_hostname/1, + ossl_dos_hostname/1, + essl_dos_hostname/1, + + pssl_time_test/1, + ossl_time_test/1, + essl_time_test/1, + + pssl_restart_no_block/1, + ossl_restart_no_block/1, + essl_restart_no_block/1, + + pssl_restart_disturbing_block/1, + ossl_restart_disturbing_block/1, + essl_restart_disturbing_block/1, + + pssl_restart_non_disturbing_block/1, + ossl_restart_non_disturbing_block/1, + essl_restart_non_disturbing_block/1, + + pssl_block_disturbing_idle/1, + ossl_block_disturbing_idle/1, + essl_block_disturbing_idle/1, + + pssl_block_non_disturbing_idle/1, + ossl_block_non_disturbing_idle/1, + essl_block_non_disturbing_idle/1, + + pssl_block_503/1, + ossl_block_503/1, + essl_block_503/1, + + pssl_block_disturbing_active/1, + ossl_block_disturbing_active/1, + essl_block_disturbing_active/1, + + pssl_block_non_disturbing_active/1, + ossl_block_non_disturbing_active/1, + essl_block_non_disturbing_active/1, + + pssl_block_disturbing_active_timeout_not_released/1, + ossl_block_disturbing_active_timeout_not_released/1, + essl_block_disturbing_active_timeout_not_released/1, + + pssl_block_disturbing_active_timeout_released/1, + ossl_block_disturbing_active_timeout_released/1, + essl_block_disturbing_active_timeout_released/1, + + pssl_block_non_disturbing_active_timeout_not_released/1, + ossl_block_non_disturbing_active_timeout_not_released/1, + essl_block_non_disturbing_active_timeout_not_released/1, + + pssl_block_non_disturbing_active_timeout_released/1, + ossl_block_non_disturbing_active_timeout_released/1, + essl_block_non_disturbing_active_timeout_released/1, + + pssl_block_disturbing_blocker_dies/1, + ossl_block_disturbing_blocker_dies/1, + essl_block_disturbing_blocker_dies/1, + + pssl_block_non_disturbing_blocker_dies/1, + ossl_block_non_disturbing_blocker_dies/1, + essl_block_non_disturbing_blocker_dies/1 + ]). %%% HTTP 1.1 tests -export([ip_host/1, ip_chunked/1, ip_expect/1, ip_range/1, @@ -103,8 +235,8 @@ %% Seconds before successful auths timeout. -define(AUTH_TIMEOUT,5). --record(httpd_user, {user_name, password, user_data}). --record(httpd_group,{group_name, userlist}). +-record(httpd_user, {user_name, password, user_data}). +-record(httpd_group, {group_name, userlist}). %%-------------------------------------------------------------------- @@ -197,9 +329,9 @@ init_per_testcase2(Case, Config) -> "~n Config: ~p" "~n", [?MODULE, Case, Config]), - IpNormal = integer_to_list(?IP_PORT) ++ ".conf", - IpHtacess = integer_to_list(?IP_PORT) ++ "htacess.conf", - SslNormal = integer_to_list(?SSL_PORT) ++ ".conf", + IpNormal = integer_to_list(?IP_PORT) ++ ".conf", + IpHtacess = integer_to_list(?IP_PORT) ++ "htacess.conf", + SslNormal = integer_to_list(?SSL_PORT) ++ ".conf", SslHtacess = integer_to_list(?SSL_PORT) ++ "htacess.conf", DataDir = ?config(data_dir, Config), @@ -210,8 +342,8 @@ init_per_testcase2(Case, Config) -> "~n DataDir: ~p" "~n", [?MODULE, Case, SuiteTopDir, DataDir]), - TcTopDir = filename:join(SuiteTopDir, Case), - ?line ok = file:make_dir(TcTopDir), + TcTopDir = filename:join(SuiteTopDir, Case), + ?line ok = file:make_dir(TcTopDir), io:format(user, "~w:init_per_testcase2(~w) -> " "~n TcTopDir: ~p" @@ -267,9 +399,21 @@ init_per_testcase2(Case, Config) -> %% To be used by SSL test cases io:format(user, "~w:init_per_testcase2(~w) -> ssl testcase setups~n", [?MODULE, Case]), - create_config([{port, ?SSL_PORT}, {sock_type, ssl} | NewConfig], + SocketType = + case atom_to_list(Case) of + [X, $s, $s, $l | _] -> + case X of + $p -> ssl; + $o -> ossl; + $e -> essl + end; + _ -> + ssl + end, + + create_config([{port, ?SSL_PORT}, {sock_type, SocketType} | NewConfig], normal_acess, SslNormal), - create_config([{port, ?SSL_PORT}, {sock_type, ssl} | NewConfig], + create_config([{port, ?SSL_PORT}, {sock_type, SocketType} | NewConfig], mod_htaccess, SslHtacess), %% To be used by IPv6 test cases. Case-clause is so that @@ -300,8 +444,14 @@ init_per_testcase3(Case, Config) -> io:format(user, "~w:init_per_testcase3(~w) -> entry with" "~n Config: ~p", [?MODULE, Case, Config]), + +%% %% Create a new fresh node to be used by the server in this test-case + +%% NodeName = list_to_atom(atom_to_list(Case) ++ "_httpd"), +%% Node = inets_test_lib:start_node(NodeName), + %% Clean up (we do not want this clean up in end_per_testcase - %% if init_per_testcase crases for some testcase it will + %% if init_per_testcase crashes for some testcase it will %% have contaminated the environment and there will be no clean up.) %% This init can take a few different paths so that one crashes %% does not mean that all invocations will. @@ -310,15 +460,26 @@ init_per_testcase3(Case, Config) -> application:stop(inets), application:stop(ssl), cleanup_mnesia(), - - %% TraceLevel = max, - TraceLevel = 70, - TraceDest = io, - inets:enable_trace(TraceLevel, TraceDest), + %% Set trace + case lists:reverse(atom_to_list(Case)) of + "tset_emit" ++ _Rest -> % test-cases ending with time_test + io:format(user, "~w:init_per_testcase3(~w) -> disabling trace", + [?MODULE, Case]), + inets:disable_trace(); + _ -> + %% TraceLevel = max, + io:format(user, "~w:init_per_testcase3(~w) -> enabling trace", + [?MODULE, Case]), + TraceLevel = 70, + TraceDest = io, + inets:enable_trace(TraceLevel, TraceDest, httpd) + end, + %% Start initialization io:format(user, "~w:init_per_testcase3(~w) -> start init", [?MODULE, Case]), + Dog = test_server:timetrap(inets_test_lib:minutes(10)), NewConfig = lists:keydelete(watchdog, 1, Config), @@ -351,22 +512,35 @@ init_per_testcase3(Case, Config) -> filename:join(TcTopDir, integer_to_list(?IP_PORT) ++ ".conf")}]), Rest; - "ssl_mod_htaccess" -> + + [X, $s, $s, $l, $_, $m, $o, $d, $_, $h, $t, $a, $c, $c, $e, $s, $s] -> + SslTag = + case X of + $p -> ssl; % plain + $o -> ossl; % OpenSSL based ssl + $e -> essl % Erlang based ssl + end, case inets_test_lib:start_http_server_ssl( filename:join(TcTopDir, integer_to_list(?SSL_PORT) ++ - "htacess.conf")) of + "htacess.conf"), SslTag) of ok -> "mod_htaccess"; Other -> error_logger:info_report("Other: ~p~n", [Other]), {skip, "SSL does not seem to be supported"} end; - "ssl_" ++ Rest -> + [X, $s, $s, $l, $_ | Rest] -> + SslTag = + case X of + $p -> ssl; + $o -> ossl; + $e -> essl + end, case inets_test_lib:start_http_server_ssl( filename:join(TcTopDir, integer_to_list(?SSL_PORT) ++ - ".conf")) of + ".conf"), SslTag) of ok -> Rest; Other -> @@ -431,6 +605,7 @@ end_per_testcase2(Case, Config) -> application:unset_env(inets, services), application:stop(inets), application:stop(ssl), + application:stop(crypto), % used by the new ssl (essl test cases) cleanup_mnesia(), io:format(user, "~w:end_per_testcase2(~w) -> done~n", [?MODULE, Case]), @@ -461,6 +636,9 @@ ip(suite) -> ip_load_heavy, ip_dos_hostname, ip_time_test, + ip_restart_no_block, + ip_restart_disturbing_block, + ip_restart_non_disturbing_block, ip_block_disturbing_idle, ip_block_non_disturbing_idle, ip_block_503, @@ -471,10 +649,7 @@ ip(suite) -> ip_block_non_disturbing_active_timeout_not_released, ip_block_non_disturbing_active_timeout_released, ip_block_disturbing_blocker_dies, - ip_block_non_disturbing_blocker_dies, - ip_restart_no_block, - ip_restart_disturbing_block, - ip_restart_non_disturbing_block + ip_block_non_disturbing_blocker_dies ]. %%------------------------------------------------------------------------- @@ -482,39 +657,124 @@ ssl(doc) -> ["HTTP test using SSL"]; ssl(suite) -> [ - ssl_mod_alias, - ssl_mod_actions, - ssl_mod_security, - ssl_mod_auth, - ssl_mod_auth_api, - ssl_mod_auth_mnesia_api, - ssl_mod_htaccess, - ssl_mod_cgi, - ssl_mod_esi, - ssl_mod_get, - ssl_mod_head, - ssl_mod_all, - ssl_load_light, - ssl_load_medium, - ssl_load_heavy, - ssl_dos_hostname, - ssl_time_test, - ssl_restart_no_block, - ssl_restart_disturbing_block, - ssl_restart_non_disturbing_block, - ssl_block_disturbing_idle, - ssl_block_non_disturbing_idle, - ssl_block_503, - ssl_block_disturbing_active, - ssl_block_non_disturbing_active, - ssl_block_disturbing_active_timeout_not_released, - ssl_block_disturbing_active_timeout_released, - ssl_block_non_disturbing_active_timeout_not_released, - ssl_block_non_disturbing_active_timeout_released, - ssl_block_disturbing_blocker_dies, - ssl_block_non_disturbing_blocker_dies + pssl, + ossl, + essl + ]. + + +pssl(doc) -> + ["HTTP test using SSL - using old way of configuring SSL"]; +pssl(suite) -> + [ + pssl_mod_alias, + pssl_mod_actions, + pssl_mod_security, + pssl_mod_auth, + pssl_mod_auth_api, + pssl_mod_auth_mnesia_api, + pssl_mod_htaccess, + pssl_mod_cgi, + pssl_mod_esi, + pssl_mod_get, + pssl_mod_head, + pssl_mod_all, + pssl_load_light, + pssl_load_medium, + pssl_load_heavy, + pssl_dos_hostname, + pssl_time_test, + pssl_restart_no_block, + pssl_restart_disturbing_block, + pssl_restart_non_disturbing_block, + pssl_block_disturbing_idle, + pssl_block_non_disturbing_idle, + pssl_block_503, + pssl_block_disturbing_active, + pssl_block_non_disturbing_active, + pssl_block_disturbing_active_timeout_not_released, + pssl_block_disturbing_active_timeout_released, + pssl_block_non_disturbing_active_timeout_not_released, + pssl_block_non_disturbing_active_timeout_released, + pssl_block_disturbing_blocker_dies, + pssl_block_non_disturbing_blocker_dies + ]. + +ossl(doc) -> + ["HTTP test using SSL - using new way of configuring usage of old SSL"]; +ossl(suite) -> + [ + ossl_mod_alias, + ossl_mod_actions, + ossl_mod_security, + ossl_mod_auth, + ossl_mod_auth_api, + ossl_mod_auth_mnesia_api, + ossl_mod_htaccess, + ossl_mod_cgi, + ossl_mod_esi, + ossl_mod_get, + ossl_mod_head, + ossl_mod_all, + ossl_load_light, + ossl_load_medium, + ossl_load_heavy, + ossl_dos_hostname, + ossl_time_test, + ossl_restart_no_block, + ossl_restart_disturbing_block, + ossl_restart_non_disturbing_block, + ossl_block_disturbing_idle, + ossl_block_non_disturbing_idle, + ossl_block_503, + ossl_block_disturbing_active, + ossl_block_non_disturbing_active, + ossl_block_disturbing_active_timeout_not_released, + ossl_block_disturbing_active_timeout_released, + ossl_block_non_disturbing_active_timeout_not_released, + ossl_block_non_disturbing_active_timeout_released, + ossl_block_disturbing_blocker_dies, + ossl_block_non_disturbing_blocker_dies ]. +essl(doc) -> + ["HTTP test using SSL - using new way of configuring usage of new SSL"]; +essl(suite) -> + [ + essl_mod_alias, + essl_mod_actions, + essl_mod_security, + essl_mod_auth, + essl_mod_auth_api, + essl_mod_auth_mnesia_api, + essl_mod_htaccess, + essl_mod_cgi, + essl_mod_esi, + essl_mod_get, + essl_mod_head, + essl_mod_all, + essl_load_light, + essl_load_medium, + essl_load_heavy, + essl_dos_hostname, + essl_time_test, + essl_restart_no_block, + essl_restart_disturbing_block, + essl_restart_non_disturbing_block, + essl_block_disturbing_idle, + essl_block_non_disturbing_idle, + essl_block_503, + essl_block_disturbing_active, + essl_block_non_disturbing_active, + essl_block_disturbing_active_timeout_not_released, + essl_block_disturbing_active_timeout_released, + essl_block_non_disturbing_active_timeout_not_released, + essl_block_non_disturbing_active_timeout_released, + essl_block_disturbing_blocker_dies, + essl_block_non_disturbing_blocker_dies + ]. + + %%------------------------------------------------------------------------- http_1_1_ip(doc) -> ["HTTP/1.1"]; @@ -721,6 +981,8 @@ ip_load_heavy(Config) when is_list(Config) -> ?config(node, Config), get_nof_clients(ip_comm, heavy)), ok. + + %%------------------------------------------------------------------------- ip_dos_hostname(doc) -> ["Denial Of Service (DOS) attack test case"]; @@ -730,6 +992,8 @@ ip_dos_hostname(Config) when is_list(Config) -> dos_hostname(ip_comm, ?IP_PORT, ?config(host, Config), ?config(node, Config), ?MAX_HEADER_SIZE), ok. + + %%------------------------------------------------------------------------- ip_time_test(doc) -> [""]; @@ -966,352 +1230,1042 @@ ip_restart_non_disturbing_block(Config) when is_list(Config) -> ok. %%------------------------------------------------------------------------- -ssl_mod_alias(doc) -> - ["Module test: mod_alias"]; -ssl_mod_alias(suite) -> + +pssl_mod_alias(doc) -> + ["Module test: mod_alias - old SSL config"]; +pssl_mod_alias(suite) -> + []; +pssl_mod_alias(Config) when is_list(Config) -> + ssl_mod_alias(ssl, Config). + +ossl_mod_alias(doc) -> + ["Module test: mod_alias - using new of configure old SSL"]; +ossl_mod_alias(suite) -> []; -ssl_mod_alias(Config) when is_list(Config) -> - httpd_mod:alias(ssl, ?SSL_PORT, +ossl_mod_alias(Config) when is_list(Config) -> + ssl_mod_alias(ossl, Config). + +essl_mod_alias(doc) -> + ["Module test: mod_alias - using new of configure new SSL"]; +essl_mod_alias(suite) -> + []; +essl_mod_alias(Config) when is_list(Config) -> + ssl_mod_alias(essl, Config). + + +ssl_mod_alias(Tag, Config) -> + httpd_mod:alias(Tag, ?SSL_PORT, ?config(host, Config), ?config(node, Config)), ok. + + %%------------------------------------------------------------------------- -ssl_mod_actions(doc) -> - ["Module test: mod_actions"]; -ssl_mod_actions(suite) -> + +pssl_mod_actions(doc) -> + ["Module test: mod_actions - old SSL config"]; +pssl_mod_actions(suite) -> []; -ssl_mod_actions(Config) when is_list(Config) -> - httpd_mod:actions(ssl, ?SSL_PORT, - ?config(host, Config), ?config(node, Config)), +pssl_mod_actions(Config) when is_list(Config) -> + ssl_mod_actions(ssl, Config). + +ossl_mod_actions(doc) -> + ["Module test: mod_actions - using new of configure old SSL"]; +ossl_mod_actions(suite) -> + []; +ossl_mod_actions(Config) when is_list(Config) -> + ssl_mod_actions(ossl, Config). + +essl_mod_actions(doc) -> + ["Module test: mod_actions - using new of configure new SSL"]; +essl_mod_actions(suite) -> + []; +essl_mod_actions(Config) when is_list(Config) -> + ssl_mod_actions(essl, Config). + + +ssl_mod_actions(Tag, Config) -> + httpd_mod:actions(Tag, + ?SSL_PORT, + ?config(host, Config), + ?config(node, Config)), ok. + + %%------------------------------------------------------------------------- -ssl_mod_security(doc) -> - ["Module test: mod_security"]; -ssl_mod_security(suite) -> + +pssl_mod_security(doc) -> + ["Module test: mod_security - old SSL config"]; +pssl_mod_security(suite) -> + []; +pssl_mod_security(Config) when is_list(Config) -> + ssl_mod_security(ssl, Config). + +ossl_mod_security(doc) -> + ["Module test: mod_security - using new of configure old SSL"]; +ossl_mod_security(suite) -> + []; +ossl_mod_security(Config) when is_list(Config) -> + ssl_mod_security(ossl, Config). + +essl_mod_security(doc) -> + ["Module test: mod_security - using new of configure new SSL"]; +essl_mod_security(suite) -> []; -ssl_mod_security(Config) when is_list(Config) -> +essl_mod_security(Config) when is_list(Config) -> + ssl_mod_security(essl, Config). + +ssl_mod_security(Tag, Config) -> ServerRoot = ?config(server_root, Config), - httpd_mod:security(ServerRoot, ssl, ?SSL_PORT, - ?config(host, Config), ?config(node, Config)), + httpd_mod:security(ServerRoot, + Tag, + ?SSL_PORT, + ?config(host, Config), + ?config(node, Config)), ok. + + %%------------------------------------------------------------------------- -ssl_mod_auth(doc) -> - ["Module test: mod_auth"]; -ssl_mod_auth(suite) -> + +pssl_mod_auth(doc) -> + ["Module test: mod_auth - old SSL config"]; +pssl_mod_auth(suite) -> []; -ssl_mod_auth(Config) when is_list(Config) -> - httpd_mod:auth(ssl, ?SSL_PORT, - ?config(host, Config), ?config(node, Config)), +pssl_mod_auth(Config) when is_list(Config) -> + ssl_mod_auth(ssl, Config). + +ossl_mod_auth(doc) -> + ["Module test: mod_auth - using new of configure old SSL"]; +ossl_mod_auth(suite) -> + []; +ossl_mod_auth(Config) when is_list(Config) -> + ssl_mod_auth(ossl, Config). + +essl_mod_auth(doc) -> + ["Module test: mod_auth - using new of configure new SSL"]; +essl_mod_auth(suite) -> + []; +essl_mod_auth(Config) when is_list(Config) -> + ssl_mod_auth(essl, Config). + +ssl_mod_auth(Tag, Config) -> + httpd_mod:auth(Tag, + ?SSL_PORT, + ?config(host, Config), + ?config(node, Config)), ok. + + %%------------------------------------------------------------------------- -ssl_mod_auth_api(doc) -> - ["Module test: mod_auth"]; -ssl_mod_auth_api(suite) -> + +pssl_mod_auth_api(doc) -> + ["Module test: mod_auth - old SSL config"]; +pssl_mod_auth_api(suite) -> + []; +pssl_mod_auth_api(Config) when is_list(Config) -> + ssl_mod_auth_api(ssl, Config). + +ossl_mod_auth_api(doc) -> + ["Module test: mod_auth - using new of configure old SSL"]; +ossl_mod_auth_api(suite) -> + []; +ossl_mod_auth_api(Config) when is_list(Config) -> + ssl_mod_auth_api(ossl, Config). + +essl_mod_auth_api(doc) -> + ["Module test: mod_auth - using new of configure new SSL"]; +essl_mod_auth_api(suite) -> []; -ssl_mod_auth_api(Config) when is_list(Config) -> +essl_mod_auth_api(Config) when is_list(Config) -> + ssl_mod_auth_api(essl, Config). + +ssl_mod_auth_api(Tag, Config) -> ServerRoot = ?config(server_root, Config), - Host = ?config(host, Config), - Node = ?config(node, Config), - httpd_mod:auth_api(ServerRoot, "", ssl, ?SSL_PORT, Host, Node), - httpd_mod:auth_api(ServerRoot, "dets_", ssl, ?SSL_PORT, Host, Node), - httpd_mod:auth_api(ServerRoot, "mnesia_", ssl, ?SSL_PORT, Host, Node), + Host = ?config(host, Config), + Node = ?config(node, Config), + httpd_mod:auth_api(ServerRoot, "", Tag, ?SSL_PORT, Host, Node), + httpd_mod:auth_api(ServerRoot, "dets_", Tag, ?SSL_PORT, Host, Node), + httpd_mod:auth_api(ServerRoot, "mnesia_", Tag, ?SSL_PORT, Host, Node), ok. + %%------------------------------------------------------------------------- -ssl_mod_auth_mnesia_api(doc) -> - ["Module test: mod_auth_mnesia_api"]; -ssl_mod_auth_mnesia_api(suite) -> + +pssl_mod_auth_mnesia_api(doc) -> + ["Module test: mod_auth_mnesia_api - old SSL config"]; +pssl_mod_auth_mnesia_api(suite) -> []; -ssl_mod_auth_mnesia_api(Config) when is_list(Config) -> - httpd_mod:auth_mnesia_api(ssl, ?SSL_PORT, - ?config(host, Config), ?config(node, Config)), +pssl_mod_auth_mnesia_api(Config) when is_list(Config) -> + ssl_mod_auth_mnesia_api(ssl, Config). + +ossl_mod_auth_mnesia_api(doc) -> + ["Module test: mod_auth_mnesia_api - using new of configure old SSL"]; +ossl_mod_auth_mnesia_api(suite) -> + []; +ossl_mod_auth_mnesia_api(Config) when is_list(Config) -> + ssl_mod_auth_mnesia_api(ossl, Config). + +essl_mod_auth_mnesia_api(doc) -> + ["Module test: mod_auth_mnesia_api - using new of configure new SSL"]; +essl_mod_auth_mnesia_api(suite) -> + []; +essl_mod_auth_mnesia_api(Config) when is_list(Config) -> + ssl_mod_auth_mnesia_api(essl, Config). + +ssl_mod_auth_mnesia_api(Tag, Config) -> + httpd_mod:auth_mnesia_api(Tag, + ?SSL_PORT, + ?config(host, Config), + ?config(node, Config)), ok. + + %%------------------------------------------------------------------------- -ssl_mod_htaccess(doc) -> - ["Module test: mod_htaccess"]; -ssl_mod_htaccess(suite) -> + +pssl_mod_htaccess(doc) -> + ["Module test: mod_htaccess - old SSL config"]; +pssl_mod_htaccess(suite) -> []; -ssl_mod_htaccess(Config) when is_list(Config) -> - httpd_mod:htaccess(ssl, ?SSL_PORT, - ?config(host, Config), ?config(node, Config)), +pssl_mod_htaccess(Config) when is_list(Config) -> + ssl_mod_htaccess(ssl, Config). + +ossl_mod_htaccess(doc) -> + ["Module test: mod_htaccess - using new of configure old SSL"]; +ossl_mod_htaccess(suite) -> + []; +ossl_mod_htaccess(Config) when is_list(Config) -> + ssl_mod_htaccess(ossl, Config). + +essl_mod_htaccess(doc) -> + ["Module test: mod_htaccess - using new of configure new SSL"]; +essl_mod_htaccess(suite) -> + []; +essl_mod_htaccess(Config) when is_list(Config) -> + ssl_mod_htaccess(essl, Config). + +ssl_mod_htaccess(Tag, Config) -> + httpd_mod:htaccess(Tag, + ?SSL_PORT, + ?config(host, Config), + ?config(node, Config)), ok. + + %%------------------------------------------------------------------------- -ssl_mod_cgi(doc) -> - ["Module test: mod_cgi"]; -ssl_mod_cgi(suite) -> + +pssl_mod_cgi(doc) -> + ["Module test: mod_cgi - old SSL config"]; +pssl_mod_cgi(suite) -> + []; +pssl_mod_cgi(Config) when is_list(Config) -> + ssl_mod_cgi(ssl, Config). + +ossl_mod_cgi(doc) -> + ["Module test: mod_cgi - using new of configure old SSL"]; +ossl_mod_cgi(suite) -> + []; +ossl_mod_cgi(Config) when is_list(Config) -> + ssl_mod_cgi(ossl, Config). + +essl_mod_cgi(doc) -> + ["Module test: mod_cgi - using new of configure new SSL"]; +essl_mod_cgi(suite) -> []; -ssl_mod_cgi(Config) when is_list(Config) -> +essl_mod_cgi(Config) when is_list(Config) -> + ssl_mod_cgi(essl, Config). + +ssl_mod_cgi(Tag, Config) -> case test_server:os_type() of vxworks -> {skip, cgi_not_supported_on_vxwoks}; _ -> - httpd_mod:cgi(ssl, ?SSL_PORT, - ?config(host, Config), ?config(node, Config)), + httpd_mod:cgi(Tag, + ?SSL_PORT, + ?config(host, Config), + ?config(node, Config)), ok end. + + %%------------------------------------------------------------------------- -ssl_mod_esi(doc) -> - ["Module test: mod_esi"]; -ssl_mod_esi(suite) -> + +pssl_mod_esi(doc) -> + ["Module test: mod_esi - old SSL config"]; +pssl_mod_esi(suite) -> []; -ssl_mod_esi(Config) when is_list(Config) -> - httpd_mod:esi(ssl, ?SSL_PORT, - ?config(host, Config), ?config(node, Config)), +pssl_mod_esi(Config) when is_list(Config) -> + ssl_mod_esi(ssl, Config). + +ossl_mod_esi(doc) -> + ["Module test: mod_esi - using new of configure old SSL"]; +ossl_mod_esi(suite) -> + []; +ossl_mod_esi(Config) when is_list(Config) -> + ssl_mod_esi(ossl, Config). + +essl_mod_esi(doc) -> + ["Module test: mod_esi - using new of configure new SSL"]; +essl_mod_esi(suite) -> + []; +essl_mod_esi(Config) when is_list(Config) -> + ssl_mod_esi(essl, Config). + +ssl_mod_esi(Tag, Config) -> + httpd_mod:esi(Tag, + ?SSL_PORT, + ?config(host, Config), + ?config(node, Config)), ok. + %%------------------------------------------------------------------------- -ssl_mod_get(doc) -> - ["Module test: mod_get"]; -ssl_mod_get(suite) -> + +pssl_mod_get(doc) -> + ["Module test: mod_get - old SSL config"]; +pssl_mod_get(suite) -> []; -ssl_mod_get(Config) when is_list(Config) -> - httpd_mod:get(ssl, ?SSL_PORT, - ?config(host, Config), ?config(node, Config)), +pssl_mod_get(Config) when is_list(Config) -> + ssl_mod_get(ssl, Config). + +ossl_mod_get(doc) -> + ["Module test: mod_get - using new of configure old SSL"]; +ossl_mod_get(suite) -> + []; +ossl_mod_get(Config) when is_list(Config) -> + ssl_mod_get(ossl, Config). + +essl_mod_get(doc) -> + ["Module test: mod_get - using new of configure new SSL"]; +essl_mod_get(suite) -> + []; +essl_mod_get(Config) when is_list(Config) -> + ssl_mod_get(essl, Config). + +ssl_mod_get(Tag, Config) -> + httpd_mod:get(Tag, + ?SSL_PORT, + ?config(host, Config), + ?config(node, Config)), ok. + + %%------------------------------------------------------------------------- -ssl_mod_head(doc) -> - ["Module test: mod_head"]; -ssl_mod_head(suite) -> + +pssl_mod_head(doc) -> + ["Module test: mod_head - old SSL config"]; +pssl_mod_head(suite) -> []; -ssl_mod_head(Config) when is_list(Config) -> - httpd_mod:head(ssl, ?SSL_PORT, - ?config(host, Config), ?config(node, Config)), +pssl_mod_head(Config) when is_list(Config) -> + ssl_mod_head(ssl, Config). + +ossl_mod_head(doc) -> + ["Module test: mod_head - using new of configure old SSL"]; +ossl_mod_head(suite) -> + []; +ossl_mod_head(Config) when is_list(Config) -> + ssl_mod_head(ossl, Config). + +essl_mod_head(doc) -> + ["Module test: mod_head - using new of configure new SSL"]; +essl_mod_head(suite) -> + []; +essl_mod_head(Config) when is_list(Config) -> + ssl_mod_head(essl, Config). + +ssl_mod_head(Tag, Config) -> + httpd_mod:head(Tag, + ?SSL_PORT, + ?config(host, Config), + ?config(node, Config)), ok. + + %%------------------------------------------------------------------------- -ssl_mod_all(doc) -> - ["All modules test"]; -ssl_mod_all(suite) -> + +pssl_mod_all(doc) -> + ["All modules test - old SSL config"]; +pssl_mod_all(suite) -> []; -ssl_mod_all(Config) when is_list(Config) -> - httpd_mod:all(ssl, ?SSL_PORT, - ?config(host, Config), ?config(node, Config)), +pssl_mod_all(Config) when is_list(Config) -> + ssl_mod_all(ssl, Config). + +ossl_mod_all(doc) -> + ["All modules test - using new of configure old SSL"]; +ossl_mod_all(suite) -> + []; +ossl_mod_all(Config) when is_list(Config) -> + ssl_mod_all(ossl, Config). + +essl_mod_all(doc) -> + ["All modules test - using new of configure new SSL"]; +essl_mod_all(suite) -> + []; +essl_mod_all(Config) when is_list(Config) -> + ssl_mod_all(essl, Config). + +ssl_mod_all(Tag, Config) -> + httpd_mod:all(Tag, + ?SSL_PORT, + ?config(host, Config), + ?config(node, Config)), ok. + %%------------------------------------------------------------------------- -ssl_load_light(doc) -> - ["Test light load"]; -ssl_load_light(suite) -> + +pssl_load_light(doc) -> + ["Test light load - old SSL config"]; +pssl_load_light(suite) -> + []; +pssl_load_light(Config) when is_list(Config) -> + ssl_load_light(ssl, Config). + +ossl_load_light(doc) -> + ["Test light load - using new of configure old SSL"]; +ossl_load_light(suite) -> []; -ssl_load_light(Config) when is_list(Config) -> - httpd_load:load_test(ssl, ?SSL_PORT, ?config(host, Config), +ossl_load_light(Config) when is_list(Config) -> + ssl_load_light(ossl, Config). + +essl_load_light(doc) -> + ["Test light load - using new of configure new SSL"]; +essl_load_light(suite) -> + []; +essl_load_light(Config) when is_list(Config) -> + ssl_load_light(essl, Config). + +ssl_load_light(Tag, Config) -> + httpd_load:load_test(Tag, + ?SSL_PORT, + ?config(host, Config), ?config(node, Config), get_nof_clients(ssl, light)), ok. + %%------------------------------------------------------------------------- -ssl_load_medium(doc) -> - ["Test medium load"]; -ssl_load_medium(suite) -> + +pssl_load_medium(doc) -> + ["Test medium load - old SSL config"]; +pssl_load_medium(suite) -> + []; +pssl_load_medium(Config) when is_list(Config) -> + ssl_load_medium(ssl, Config). + +ossl_load_medium(doc) -> + ["Test medium load - using new of configure old SSL"]; +ossl_load_medium(suite) -> + []; +ossl_load_medium(Config) when is_list(Config) -> + ssl_load_medium(ossl, Config). + +essl_load_medium(doc) -> + ["Test medium load - using new of configure new SSL"]; +essl_load_medium(suite) -> []; -ssl_load_medium(Config) when is_list(Config) -> +essl_load_medium(Config) when is_list(Config) -> + ssl_load_medium(essl, Config). + +ssl_load_medium(Tag, Config) -> %% <CONDITIONAL-SKIP> Skippable = [win32], Condition = fun() -> ?OS_BASED_SKIP(Skippable) end, ?NON_PC_TC_MAYBE_SKIP(Config, Condition), %% </CONDITIONAL-SKIP> - httpd_load:load_test(ssl, ?SSL_PORT, ?config(host, Config), + httpd_load:load_test(Tag, + ?SSL_PORT, + ?config(host, Config), ?config(node, Config), get_nof_clients(ssl, medium)), ok. + %%------------------------------------------------------------------------- -ssl_load_heavy(doc) -> - ["Test heavy load"]; -ssl_load_heavy(suite) -> + +pssl_load_heavy(doc) -> + ["Test heavy load - old SSL config"]; +pssl_load_heavy(suite) -> + []; +pssl_load_heavy(Config) when is_list(Config) -> + ssl_load_heavy(ssl, Config). + +ossl_load_heavy(doc) -> + ["Test heavy load - using new of configure old SSL"]; +ossl_load_heavy(suite) -> []; -ssl_load_heavy(Config) when is_list(Config) -> +ossl_load_heavy(Config) when is_list(Config) -> + ssl_load_heavy(ossl, Config). + +essl_load_heavy(doc) -> + ["Test heavy load - using new of configure new SSL"]; +essl_load_heavy(suite) -> + []; +essl_load_heavy(Config) when is_list(Config) -> + ssl_load_heavy(essl, Config). + +ssl_load_heavy(Tag, Config) -> %% <CONDITIONAL-SKIP> Skippable = [win32], Condition = fun() -> ?OS_BASED_SKIP(Skippable) end, ?NON_PC_TC_MAYBE_SKIP(Config, Condition), %% </CONDITIONAL-SKIP> - httpd_load:load_test(ssl, ?SSL_PORT, ?config(host, Config), + httpd_load:load_test(Tag, + ?SSL_PORT, + ?config(host, Config), ?config(node, Config), get_nof_clients(ssl, heavy)), ok. + %%------------------------------------------------------------------------- -ssl_dos_hostname(doc) -> - ["Denial Of Service (DOS) attack test case"]; -ssl_dos_hostname(suite) -> + +pssl_dos_hostname(doc) -> + ["Denial Of Service (DOS) attack test case - old SSL config"]; +pssl_dos_hostname(suite) -> []; -ssl_dos_hostname(Config) when is_list(Config) -> - dos_hostname(ssl, ?SSL_PORT, ?config(host, Config), - ?config(node, Config), ?MAX_HEADER_SIZE), +pssl_dos_hostname(Config) when is_list(Config) -> + ssl_dos_hostname(ssl, Config). + +ossl_dos_hostname(doc) -> + ["Denial Of Service (DOS) attack test case - using new of configure old SSL"]; +ossl_dos_hostname(suite) -> + []; +ossl_dos_hostname(Config) when is_list(Config) -> + ssl_dos_hostname(ossl, Config). + +essl_dos_hostname(doc) -> + ["Denial Of Service (DOS) attack test case - using new of configure new SSL"]; +essl_dos_hostname(suite) -> + []; +essl_dos_hostname(Config) when is_list(Config) -> + ssl_dos_hostname(essl, Config). + +ssl_dos_hostname(Tag, Config) -> + dos_hostname(Tag, + ?SSL_PORT, + ?config(host, Config), + ?config(node, Config), + ?MAX_HEADER_SIZE), ok. + + %%------------------------------------------------------------------------- -ssl_time_test(doc) -> - [""]; -ssl_time_test(suite) -> + +pssl_time_test(doc) -> + ["old SSL config"]; +pssl_time_test(suite) -> + []; +pssl_time_test(Config) when is_list(Config) -> + ssl_time_test(ssl, Config). + +ossl_time_test(doc) -> + ["using new of configure old SSL"]; +ossl_time_test(suite) -> []; -ssl_time_test(Config) when is_list(Config) -> +ossl_time_test(Config) when is_list(Config) -> + ssl_time_test(ossl, Config). + +essl_time_test(doc) -> + ["using new of configure new SSL"]; +essl_time_test(suite) -> + []; +essl_time_test(Config) when is_list(Config) -> + ssl_time_test(essl, Config). + +ssl_time_test(Tag, Config) when is_list(Config) -> %% <CONDITIONAL-SKIP> - Condition = fun() -> true end, + Skippable = [win32], + Condition = fun() -> ?OS_BASED_SKIP(Skippable) end, ?NON_PC_TC_MAYBE_SKIP(Config, Condition), %% </CONDITIONAL-SKIP> - httpd_time_test:t(ssl, ?config(host, Config), ?SSL_PORT), + httpd_time_test:t(Tag, + ?config(host, Config), + ?SSL_PORT), ok. + %%------------------------------------------------------------------------- -ssl_block_503(doc) -> + +pssl_block_503(doc) -> ["Check that you will receive status code 503 when the server" - " is blocked and 200 when its not blocked."]; -ssl_block_503(suite) -> + " is blocked and 200 when its not blocked - old SSL config."]; +pssl_block_503(suite) -> + []; +pssl_block_503(Config) when is_list(Config) -> + ssl_block_503(ssl, Config). + +ossl_block_503(doc) -> + ["Check that you will receive status code 503 when the server" + " is blocked and 200 when its not blocked - using new of configure old SSL."]; +ossl_block_503(suite) -> + []; +ossl_block_503(Config) when is_list(Config) -> + ssl_block_503(ossl, Config). + +essl_block_503(doc) -> + ["Check that you will receive status code 503 when the server" + " is blocked and 200 when its not blocked - using new of configure new SSL."]; +essl_block_503(suite) -> []; -ssl_block_503(Config) when is_list(Config) -> - httpd_block:block_503(ssl, ?SSL_PORT, ?config(host, Config), +essl_block_503(Config) when is_list(Config) -> + ssl_block_503(essl, Config). + +ssl_block_503(Tag, Config) -> + httpd_block:block_503(Tag, + ?SSL_PORT, + ?config(host, Config), ?config(node, Config)), ok. + + %%------------------------------------------------------------------------- -ssl_block_disturbing_idle(doc) -> + +pssl_block_disturbing_idle(doc) -> ["Check that you can block/unblock an idle server. The strategy " - "distribing does not really make a difference in this case."]; -ssl_block_disturbing_idle(suite) -> + "distribing does not really make a difference in this case." + "Old SSL config"]; +pssl_block_disturbing_idle(suite) -> + []; +pssl_block_disturbing_idle(Config) when is_list(Config) -> + ssl_block_disturbing_idle(ssl, Config). + +ossl_block_disturbing_idle(doc) -> + ["Check that you can block/unblock an idle server. The strategy " + "distribing does not really make a difference in this case." + "Using new of configure old SSL"]; +ossl_block_disturbing_idle(suite) -> + []; +ossl_block_disturbing_idle(Config) when is_list(Config) -> + ssl_block_disturbing_idle(ossl, Config). + +essl_block_disturbing_idle(doc) -> + ["Check that you can block/unblock an idle server. The strategy " + "distribing does not really make a difference in this case." + "Using new of configure new SSL"]; +essl_block_disturbing_idle(suite) -> []; -ssl_block_disturbing_idle(Config) when is_list(Config) -> - httpd_block:block_disturbing_idle(ssl, ?SSL_PORT, +essl_block_disturbing_idle(Config) when is_list(Config) -> + ssl_block_disturbing_idle(essl, Config). + +ssl_block_disturbing_idle(Tag, Config) -> + httpd_block:block_disturbing_idle(Tag, + ?SSL_PORT, ?config(host, Config), ?config(node, Config)), ok. + + %%------------------------------------------------------------------------- -ssl_block_non_disturbing_idle(doc) -> + +pssl_block_non_disturbing_idle(doc) -> ["Check that you can block/unblock an idle server. The strategy " - "non distribing does not really make a difference in this case."]; -ssl_block_non_disturbing_idle(suite) -> + "non distribing does not really make a difference in this case." + "Old SSL config"]; +pssl_block_non_disturbing_idle(suite) -> []; -ssl_block_non_disturbing_idle(Config) when is_list(Config) -> - httpd_block:block_non_disturbing_idle(ssl, ?SSL_PORT, +pssl_block_non_disturbing_idle(Config) when is_list(Config) -> + ssl_block_non_disturbing_idle(ssl, Config). + +ossl_block_non_disturbing_idle(doc) -> + ["Check that you can block/unblock an idle server. The strategy " + "non distribing does not really make a difference in this case." + "Using new of configure old SSL"]; +ossl_block_non_disturbing_idle(suite) -> + []; +ossl_block_non_disturbing_idle(Config) when is_list(Config) -> + ssl_block_non_disturbing_idle(ossl, Config). + +essl_block_non_disturbing_idle(doc) -> + ["Check that you can block/unblock an idle server. The strategy " + "non distribing does not really make a difference in this case." + "Using new of configure new SSL"]; +essl_block_non_disturbing_idle(suite) -> + []; +essl_block_non_disturbing_idle(Config) when is_list(Config) -> + ssl_block_non_disturbing_idle(essl, Config). + +ssl_block_non_disturbing_idle(Tag, Config) -> + httpd_block:block_non_disturbing_idle(Tag, + ?SSL_PORT, ?config(host, Config), ?config(node, Config)), ok. + + %%------------------------------------------------------------------------- -ssl_block_disturbing_active(doc) -> + +pssl_block_disturbing_active(doc) -> ["Check that you can block/unblock an active server. The strategy " - "distribing means ongoing requests should be terminated."]; -ssl_block_disturbing_active(suite) -> + "distribing means ongoing requests should be terminated." + "Old SSL config"]; +pssl_block_disturbing_active(suite) -> + []; +pssl_block_disturbing_active(Config) when is_list(Config) -> + ssl_block_disturbing_active(ssl, Config). + +ossl_block_disturbing_active(doc) -> + ["Check that you can block/unblock an active server. The strategy " + "distribing means ongoing requests should be terminated." + "Using new of configure old SSL"]; +ossl_block_disturbing_active(suite) -> + []; +ossl_block_disturbing_active(Config) when is_list(Config) -> + ssl_block_disturbing_active(ossl, Config). + +essl_block_disturbing_active(doc) -> + ["Check that you can block/unblock an active server. The strategy " + "distribing means ongoing requests should be terminated." + "Using new of configure new SSL"]; +essl_block_disturbing_active(suite) -> []; -ssl_block_disturbing_active(Config) when is_list(Config) -> - httpd_block:block_disturbing_active(ssl, ?SSL_PORT, +essl_block_disturbing_active(Config) when is_list(Config) -> + ssl_block_disturbing_active(essl, Config). + +ssl_block_disturbing_active(Tag, Config) -> + httpd_block:block_disturbing_active(Tag, + ?SSL_PORT, ?config(host, Config), ?config(node, Config)), ok. + + %%------------------------------------------------------------------------- -ssl_block_non_disturbing_active(doc) -> + +pssl_block_non_disturbing_active(doc) -> ["Check that you can block/unblock an idle server. The strategy " - "non distribing means the ongoing requests should be compleated."]; -ssl_block_non_disturbing_active(suite) -> + "non distribing means the ongoing requests should be compleated." + "Old SSL config"]; +pssl_block_non_disturbing_active(suite) -> + []; +pssl_block_non_disturbing_active(Config) when is_list(Config) -> + ssl_block_non_disturbing_active(ssl, Config). + +ossl_block_non_disturbing_active(doc) -> + ["Check that you can block/unblock an idle server. The strategy " + "non distribing means the ongoing requests should be compleated." + "Using new of configure old SSL"]; +ossl_block_non_disturbing_active(suite) -> + []; +ossl_block_non_disturbing_active(Config) when is_list(Config) -> + ssl_block_non_disturbing_active(ossl, Config). + +essl_block_non_disturbing_active(doc) -> + ["Check that you can block/unblock an idle server. The strategy " + "non distribing means the ongoing requests should be compleated." + "Using new of configure new SSL"]; +essl_block_non_disturbing_active(suite) -> []; -ssl_block_non_disturbing_active(Config) when is_list(Config) -> - httpd_block:block_non_disturbing_idle(ssl, ?SSL_PORT, +essl_block_non_disturbing_active(Config) when is_list(Config) -> + ssl_block_non_disturbing_active(essl, Config). + +ssl_block_non_disturbing_active(Tag, Config) -> + httpd_block:block_non_disturbing_idle(Tag, + ?SSL_PORT, ?config(host, Config), ?config(node, Config)), ok. + %%------------------------------------------------------------------------- -ssl_block_disturbing_active_timeout_not_released(doc) -> + +pssl_block_disturbing_active_timeout_not_released(doc) -> ["Check that you can block an active server. The strategy " "distribing means ongoing requests should be compleated" - "if the timeout does not occur."]; -ssl_block_disturbing_active_timeout_not_released(suite) -> + "if the timeout does not occur." + "Old SSL config"]; +pssl_block_disturbing_active_timeout_not_released(suite) -> []; -ssl_block_disturbing_active_timeout_not_released(Config) +pssl_block_disturbing_active_timeout_not_released(Config) when is_list(Config) -> - httpd_block: - block_disturbing_active_timeout_not_released(ssl, - ?SSL_PORT, - ?config(host, - Config), - ?config(node, - Config)), + ssl_block_disturbing_active_timeout_not_released(ssl, Config). + +ossl_block_disturbing_active_timeout_not_released(doc) -> + ["Check that you can block an active server. The strategy " + "distribing means ongoing requests should be compleated" + "if the timeout does not occur." + "Using new of configure old SSL"]; +ossl_block_disturbing_active_timeout_not_released(suite) -> + []; +ossl_block_disturbing_active_timeout_not_released(Config) + when is_list(Config) -> + ssl_block_disturbing_active_timeout_not_released(ossl, Config). + +essl_block_disturbing_active_timeout_not_released(doc) -> + ["Check that you can block an active server. The strategy " + "distribing means ongoing requests should be compleated" + "if the timeout does not occur." + "Using new of configure new SSL"]; +essl_block_disturbing_active_timeout_not_released(suite) -> + []; +essl_block_disturbing_active_timeout_not_released(Config) + when is_list(Config) -> + ssl_block_disturbing_active_timeout_not_released(essl, Config). + +ssl_block_disturbing_active_timeout_not_released(Tag, Config) -> + Port = ?SSL_PORT, + Host = ?config(host, Config), + Node = ?config(node, Config), + httpd_block:block_disturbing_active_timeout_not_released(Tag, + Port, Host, Node), ok. + + %%------------------------------------------------------------------------- -ssl_block_disturbing_active_timeout_released(doc) -> + +pssl_block_disturbing_active_timeout_released(doc) -> ["Check that you can block an active server. The strategy " "distribing means ongoing requests should be terminated when" - "the timeout occurs."]; -ssl_block_disturbing_active_timeout_released(suite) -> + "the timeout occurs." + "Old SSL config"]; +pssl_block_disturbing_active_timeout_released(suite) -> []; -ssl_block_disturbing_active_timeout_released(Config) +pssl_block_disturbing_active_timeout_released(Config) when is_list(Config) -> - httpd_block:block_disturbing_active_timeout_released(ssl, - ?SSL_PORT, - ?config(host, - Config), - ?config(node, - Config)), + ssl_block_disturbing_active_timeout_released(ssl, Config). + +ossl_block_disturbing_active_timeout_released(doc) -> + ["Check that you can block an active server. The strategy " + "distribing means ongoing requests should be terminated when" + "the timeout occurs." + "Using new of configure old SSL"]; +ossl_block_disturbing_active_timeout_released(suite) -> + []; +ossl_block_disturbing_active_timeout_released(Config) + when is_list(Config) -> + ssl_block_disturbing_active_timeout_released(ossl, Config). + +essl_block_disturbing_active_timeout_released(doc) -> + ["Check that you can block an active server. The strategy " + "distribing means ongoing requests should be terminated when" + "the timeout occurs." + "Using new of configure new SSL"]; +essl_block_disturbing_active_timeout_released(suite) -> + []; +essl_block_disturbing_active_timeout_released(Config) + when is_list(Config) -> + ssl_block_disturbing_active_timeout_released(essl, Config). + +ssl_block_disturbing_active_timeout_released(Tag, Config) -> + Port = ?SSL_PORT, + Host = ?config(host, Config), + Node = ?config(node, Config), + httpd_block:block_disturbing_active_timeout_released(Tag, + Port, + Host, + Node), ok. + %%------------------------------------------------------------------------- -ssl_block_non_disturbing_active_timeout_not_released(doc) -> + +pssl_block_non_disturbing_active_timeout_not_released(doc) -> ["Check that you can block an active server. The strategy " - "non non distribing means ongoing requests should be completed."]; -ssl_block_non_disturbing_active_timeout_not_released(suite) -> + "non non distribing means ongoing requests should be completed." + "Old SSL config"]; +pssl_block_non_disturbing_active_timeout_not_released(suite) -> []; -ssl_block_non_disturbing_active_timeout_not_released(Config) +pssl_block_non_disturbing_active_timeout_not_released(Config) when is_list(Config) -> - httpd_block: - block_non_disturbing_active_timeout_not_released(ssl, - ?SSL_PORT, - ?config(host, - Config), - ?config(node, - Config)), + ssl_block_non_disturbing_active_timeout_not_released(ssl, Config). + +ossl_block_non_disturbing_active_timeout_not_released(doc) -> + ["Check that you can block an active server. The strategy " + "non non distribing means ongoing requests should be completed." + "Using new of configure old SSL"]; +ossl_block_non_disturbing_active_timeout_not_released(suite) -> + []; +ossl_block_non_disturbing_active_timeout_not_released(Config) + when is_list(Config) -> + ssl_block_non_disturbing_active_timeout_not_released(ossl, Config). + +essl_block_non_disturbing_active_timeout_not_released(doc) -> + ["Check that you can block an active server. The strategy " + "non non distribing means ongoing requests should be completed." + "Using new of configure new SSL"]; +essl_block_non_disturbing_active_timeout_not_released(suite) -> + []; +essl_block_non_disturbing_active_timeout_not_released(Config) + when is_list(Config) -> + ssl_block_non_disturbing_active_timeout_not_released(essl, Config). + +ssl_block_non_disturbing_active_timeout_not_released(Tag, Config) -> + Port = ?SSL_PORT, + Host = ?config(host, Config), + Node = ?config(node, Config), + httpd_block:block_non_disturbing_active_timeout_not_released(Tag, + Port, + Host, + Node), ok. + + %%------------------------------------------------------------------------- -ssl_block_non_disturbing_active_timeout_released(doc) -> + +pssl_block_non_disturbing_active_timeout_released(doc) -> ["Check that you can block an active server. The strategy " - "non non distribing means ongoing requests should be completed. " - "When the timeout occurs the block operation sohould be canceled." ]; -ssl_block_non_disturbing_active_timeout_released(suite) -> + "non distribing means ongoing requests should be completed. " + "When the timeout occurs the block operation sohould be canceled." + "Old SSL config"]; +pssl_block_non_disturbing_active_timeout_released(suite) -> []; -ssl_block_non_disturbing_active_timeout_released(Config) +pssl_block_non_disturbing_active_timeout_released(Config) when is_list(Config) -> - httpd_block: - block_non_disturbing_active_timeout_released(ssl, - ?SSL_PORT, - ?config(host, - Config), - ?config(node, - Config)), + ssl_block_non_disturbing_active_timeout_released(ssl, Config). + +ossl_block_non_disturbing_active_timeout_released(doc) -> + ["Check that you can block an active server. The strategy " + "non distribing means ongoing requests should be completed. " + "When the timeout occurs the block operation sohould be canceled." + "Using new of configure old SSL"]; +ossl_block_non_disturbing_active_timeout_released(suite) -> + []; +ossl_block_non_disturbing_active_timeout_released(Config) + when is_list(Config) -> + ssl_block_non_disturbing_active_timeout_released(ossl, Config). + +essl_block_non_disturbing_active_timeout_released(doc) -> + ["Check that you can block an active server. The strategy " + "non distribing means ongoing requests should be completed. " + "When the timeout occurs the block operation sohould be canceled." + "Using new of configure new SSL"]; +essl_block_non_disturbing_active_timeout_released(suite) -> + []; +essl_block_non_disturbing_active_timeout_released(Config) + when is_list(Config) -> + ssl_block_non_disturbing_active_timeout_released(essl, Config). + +ssl_block_non_disturbing_active_timeout_released(Tag, Config) + when is_list(Config) -> + Port = ?SSL_PORT, + Host = ?config(host, Config), + Node = ?config(node, Config), + httpd_block:block_non_disturbing_active_timeout_released(Tag, + Port, + Host, + Node), + ok. + %%------------------------------------------------------------------------- -ssl_block_disturbing_blocker_dies(doc) -> + +pssl_block_disturbing_blocker_dies(doc) -> + ["old SSL config"]; +pssl_block_disturbing_blocker_dies(suite) -> + []; +pssl_block_disturbing_blocker_dies(Config) when is_list(Config) -> + ssl_block_disturbing_blocker_dies(ssl, Config). + +ossl_block_disturbing_blocker_dies(doc) -> + ["using new of configure old SSL"]; +ossl_block_disturbing_blocker_dies(suite) -> []; -ssl_block_disturbing_blocker_dies(suite) -> +ossl_block_disturbing_blocker_dies(Config) when is_list(Config) -> + ssl_block_disturbing_blocker_dies(ossl, Config). + +essl_block_disturbing_blocker_dies(doc) -> + ["using new of configure new SSL"]; +essl_block_disturbing_blocker_dies(suite) -> []; -ssl_block_disturbing_blocker_dies(Config) when is_list(Config) -> - httpd_block:disturbing_blocker_dies(ssl, ?SSL_PORT, +essl_block_disturbing_blocker_dies(Config) when is_list(Config) -> + ssl_block_disturbing_blocker_dies(essl, Config). + +ssl_block_disturbing_blocker_dies(Tag, Config) -> + httpd_block:disturbing_blocker_dies(Tag, + ?SSL_PORT, ?config(host, Config), ?config(node, Config)), ok. + + %%------------------------------------------------------------------------- -ssl_block_non_disturbing_blocker_dies(doc) -> + +pssl_block_non_disturbing_blocker_dies(doc) -> + ["old SSL config"]; +pssl_block_non_disturbing_blocker_dies(suite) -> + []; +pssl_block_non_disturbing_blocker_dies(Config) when is_list(Config) -> + ssl_block_non_disturbing_blocker_dies(ssl, Config). + +ossl_block_non_disturbing_blocker_dies(doc) -> + ["using new of configure old SSL"]; +ossl_block_non_disturbing_blocker_dies(suite) -> []; -ssl_block_non_disturbing_blocker_dies(suite) -> +ossl_block_non_disturbing_blocker_dies(Config) when is_list(Config) -> + ssl_block_non_disturbing_blocker_dies(ossl, Config). + +essl_block_non_disturbing_blocker_dies(doc) -> + ["using new of configure new SSL"]; +essl_block_non_disturbing_blocker_dies(suite) -> []; -ssl_block_non_disturbing_blocker_dies(Config) when is_list(Config) -> - httpd_block:non_disturbing_blocker_dies(ssl, ?SSL_PORT, +essl_block_non_disturbing_blocker_dies(Config) when is_list(Config) -> + ssl_block_non_disturbing_blocker_dies(essl, Config). + +ssl_block_non_disturbing_blocker_dies(Tag, Config) -> + httpd_block:non_disturbing_blocker_dies(Tag, + ?SSL_PORT, ?config(host, Config), ?config(node, Config)), ok. + + %%------------------------------------------------------------------------- -ssl_restart_no_block(doc) -> - [""]; -ssl_restart_no_block(suite) -> + +pssl_restart_no_block(doc) -> + ["old SSL config"]; +pssl_restart_no_block(suite) -> + []; +pssl_restart_no_block(Config) when is_list(Config) -> + ssl_restart_no_block(ssl, Config). + +ossl_restart_no_block(doc) -> + ["using new of configure old SSL"]; +ossl_restart_no_block(suite) -> []; -ssl_restart_no_block(Config) when is_list(Config) -> - httpd_block:restart_no_block(ssl, ?SSL_PORT, ?config(host, Config), +ossl_restart_no_block(Config) when is_list(Config) -> + ssl_restart_no_block(ossl, Config). + +essl_restart_no_block(doc) -> + ["using new of configure new SSL"]; +essl_restart_no_block(suite) -> + []; +essl_restart_no_block(Config) when is_list(Config) -> + ssl_restart_no_block(essl, Config). + +ssl_restart_no_block(Tag, Config) -> + httpd_block:restart_no_block(Tag, + ?SSL_PORT, + ?config(host, Config), ?config(node, Config)), ok. + + %%------------------------------------------------------------------------- -ssl_restart_disturbing_block(doc) -> - [""]; -ssl_restart_disturbing_block(suite) -> + +pssl_restart_disturbing_block(doc) -> + ["old SSL config"]; +pssl_restart_disturbing_block(suite) -> + []; +pssl_restart_disturbing_block(Config) when is_list(Config) -> + ssl_restart_disturbing_block(ssl, Config). + +ossl_restart_disturbing_block(doc) -> + ["using new of configure old SSL"]; +ossl_restart_disturbing_block(suite) -> []; -ssl_restart_disturbing_block(Config) when is_list(Config) -> +ossl_restart_disturbing_block(Config) when is_list(Config) -> + ssl_restart_disturbing_block(ossl, Config). + +essl_restart_disturbing_block(doc) -> + ["using new of configure new SSL"]; +essl_restart_disturbing_block(suite) -> + []; +essl_restart_disturbing_block(Config) when is_list(Config) -> + ssl_restart_disturbing_block(essl, Config). + +ssl_restart_disturbing_block(Tag, Config) -> %% <CONDITIONAL-SKIP> Condition = fun() -> @@ -1336,17 +2290,36 @@ ssl_restart_disturbing_block(Config) when is_list(Config) -> ?NON_PC_TC_MAYBE_SKIP(Config, Condition), %% </CONDITIONAL-SKIP> - httpd_block:restart_disturbing_block(ssl, ?SSL_PORT, + httpd_block:restart_disturbing_block(Tag, ?SSL_PORT, ?config(host, Config), ?config(node, Config)), ok. + %%------------------------------------------------------------------------- -ssl_restart_non_disturbing_block(doc) -> - [""]; -ssl_restart_non_disturbing_block(suite) -> + +pssl_restart_non_disturbing_block(doc) -> + ["old SSL config"]; +pssl_restart_non_disturbing_block(suite) -> []; -ssl_restart_non_disturbing_block(Config) when is_list(Config) -> +pssl_restart_non_disturbing_block(Config) when is_list(Config) -> + ssl_restart_non_disturbing_block(ssl, Config). + +ossl_restart_non_disturbing_block(doc) -> + ["using new of configure old SSL"]; +ossl_restart_non_disturbing_block(suite) -> + []; +ossl_restart_non_disturbing_block(Config) when is_list(Config) -> + ssl_restart_non_disturbing_block(ossl, Config). + +essl_restart_non_disturbing_block(doc) -> + ["using new of configure new SSL"]; +essl_restart_non_disturbing_block(suite) -> + []; +essl_restart_non_disturbing_block(Config) when is_list(Config) -> + ssl_restart_non_disturbing_block(essl, Config). + +ssl_restart_non_disturbing_block(Tag, Config) -> %% <CONDITIONAL-SKIP> Condition = fun() -> @@ -1371,11 +2344,13 @@ ssl_restart_non_disturbing_block(Config) when is_list(Config) -> ?NON_PC_TC_MAYBE_SKIP(Config, Condition), %% </CONDITIONAL-SKIP> - httpd_block:restart_non_disturbing_block(ssl, ?SSL_PORT, - ?config(host, Config), - ?config(node, Config)), + httpd_block:restart_non_disturbing_block(Tag, + ?SSL_PORT, + ?config(host, Config), + ?config(node, Config)), ok. + %%------------------------------------------------------------------------- ip_host(doc) -> ["Control that the server accepts/rejects requests with/ without host"]; @@ -1665,17 +2640,29 @@ dos_hostname(Type, Port, Host, Node, Max) -> %% Other help functions create_config(Config, Access, FileName) -> ServerRoot = ?config(server_root, Config), - TcTopDir = ?config(tc_top_dir, Config), - Port = ?config(port, Config), - Type = ?config(sock_type, Config), - Host = ?config(host, Config), - Mods = io_lib:format("~p", [httpd_mod]), - Funcs = io_lib:format("~p", [ssl_password_cb]), - MaxHdrSz = io_lib:format("~p", [256]), - MaxHdrAct = io_lib:format("~p", [close]), + TcTopDir = ?config(tc_top_dir, Config), + Port = ?config(port, Config), + Type = ?config(sock_type, Config), + Host = ?config(host, Config), + Mods = io_lib:format("~p", [httpd_mod]), + Funcs = io_lib:format("~p", [ssl_password_cb]), + MaxHdrSz = io_lib:format("~p", [256]), + MaxHdrAct = io_lib:format("~p", [close]), + + io:format(user, + "create_config -> " + "~n ServerRoot: ~p" + "~n TcTopDir: ~p" + "~n Type: ~p" + "~n Port: ~p" + "~n Host: ~p" + "~n", [ServerRoot, TcTopDir, Port, Type, Host]), + SSL = - case Type of - ssl -> + if + (Type =:= ssl) orelse + (Type =:= ossl) orelse + (Type =:= essl) -> [cline(["SSLCertificateFile ", filename:join(ServerRoot, "ssl/ssl_server.pem")]), cline(["SSLCertificateKeyFile ", @@ -1686,25 +2673,25 @@ create_config(Config, Access, FileName) -> cline(["SSLPasswordCallbackFunction ", Funcs]), cline(["SSLVerifyClient 0"]), cline(["SSLVerifyDepth 1"])]; - _ -> + true -> [] end, - Mod_order = case Access of - mod_htaccess -> - "Modules mod_alias mod_htaccess mod_auth " - "mod_security " - "mod_responsecontrol mod_trace mod_esi " - "mod_actions mod_cgi mod_include mod_dir " - "mod_range mod_get " - "mod_head mod_log mod_disk_log"; - _ -> - "Modules mod_alias mod_auth mod_security " - "mod_responsecontrol mod_trace mod_esi " - "mod_actions mod_cgi mod_include mod_dir " - "mod_range mod_get " - "mod_head mod_log mod_disk_log" - end, - + ModOrder = case Access of + mod_htaccess -> + "Modules mod_alias mod_htaccess mod_auth " + "mod_security " + "mod_responsecontrol mod_trace mod_esi " + "mod_actions mod_cgi mod_include mod_dir " + "mod_range mod_get " + "mod_head mod_log mod_disk_log"; + _ -> + "Modules mod_alias mod_auth mod_security " + "mod_responsecontrol mod_trace mod_esi " + "mod_actions mod_cgi mod_include mod_dir " + "mod_range mod_get " + "mod_head mod_log mod_disk_log" + end, + %% The test suite currently does not handle an explicit BindAddress. %% They assume any has been used, that is Addr is always set to undefined! @@ -1720,7 +2707,7 @@ create_config(Config, Access, FileName) -> cline(["Port ", integer_to_list(Port)]), cline(["ServerName ", Host]), cline(["SocketType ", atom_to_list(Type)]), - cline([Mod_order]), + cline([ModOrder]), %% cline(["LogFormat ", "erlang"]), cline(["ServerAdmin [email protected]"]), cline(["BindAddress ", BindAddress]), @@ -1882,18 +2869,18 @@ start_mnesia(Node) -> ok -> ok; Other -> - test_server:fail({failed_to_cleanup_mnesia, Other}) + tsf({failed_to_cleanup_mnesia, Other}) end, - case rpc:call(Node, ?MODULE, setup_mnesia, []) of + case rpc:call(Node, ?MODULE, setup_mnesia, []) of {atomic, ok} -> ok; Other2 -> - test_server:fail({failed_to_setup_mnesia, Other2}) + tsf({failed_to_setup_mnesia, Other2}) end, ok. setup_mnesia() -> - setup_mnesia([node()]). + setup_mnesia([node()]). setup_mnesia(Nodes) -> ok = mnesia:create_schema(Nodes), @@ -2029,20 +3016,20 @@ dos_hostname_request(Host) -> get_nof_clients(Mode, Load) -> get_nof_clients(test_server:os_type(), Mode, Load). -get_nof_clients(vxworks, _, light) -> 1; +get_nof_clients(vxworks, _, light) -> 1; get_nof_clients(vxworks, ip_comm, medium) -> 3; -get_nof_clients(vxworks, ssl, medium) -> 3; +get_nof_clients(vxworks, ssl, medium) -> 3; get_nof_clients(vxworks, ip_comm, heavy) -> 5; -get_nof_clients(vxworks, ssl, heavy) -> 5; -get_nof_clients(_, ip_comm, light) -> 5; -get_nof_clients(_, ssl, light) -> 2; -get_nof_clients(_, ip_comm, medium) -> 10; -get_nof_clients(_, ssl, medium) -> 4; -get_nof_clients(_, ip_comm, heavy) -> 20; -get_nof_clients(_, ssl, heavy) -> 6. +get_nof_clients(vxworks, ssl, heavy) -> 5; +get_nof_clients(_, ip_comm, light) -> 5; +get_nof_clients(_, ssl, light) -> 2; +get_nof_clients(_, ip_comm, medium) -> 10; +get_nof_clients(_, ssl, medium) -> 4; +get_nof_clients(_, ip_comm, heavy) -> 20; +get_nof_clients(_, ssl, heavy) -> 6. %% Make a file 100 bytes long containing 012...9*10 -create_range_data(Path)-> +create_range_data(Path) -> PathAndFileName=filename:join([Path,"range.txt"]), file:write_file(PathAndFileName,list_to_binary(["12345678901234567890", "12345678901234567890", @@ -2079,3 +3066,6 @@ create_range_data(Path)-> %% {ok, Fd} = file:open(ConfigFile, [write]), %% ok = file:write(Fd, lists:flatten(HttpConfig)), %% ok = file:close(Fd). + +tsf(Reason) -> + test_server:fail(Reason). diff --git a/lib/inets/test/httpd_SUITE_data/server_root/Makefile b/lib/inets/test/httpd_SUITE_data/server_root/Makefile new file mode 100644 index 0000000000..d7a3231068 --- /dev/null +++ b/lib/inets/test/httpd_SUITE_data/server_root/Makefile @@ -0,0 +1,209 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2010. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(INETS_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/inets-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +MODULE= + +AUTH_FILES = auth/group \ + auth/passwd +CGI_FILES = cgi-bin/printenv.sh +CONF_FILES = conf/8080.conf \ + conf/8888.conf \ + conf/httpd.conf \ + conf/ssl.conf \ + conf/mime.types +OPEN_FILES = htdocs/open/dummy.html +MNESIA_OPEN_FILES = htdocs/mnesia_open/dummy.html +MISC_FILES = htdocs/misc/friedrich.html \ + htdocs/misc/oech.html +SECRET_FILES = htdocs/secret/dummy.html +MNESIA_SECRET_FILES = htdocs/mnesia_secret/dummy.html +HTDOCS_FILES = htdocs/index.html \ + htdocs/config.shtml \ + htdocs/echo.shtml \ + htdocs/exec.shtml \ + htdocs/flastmod.shtml \ + htdocs/fsize.shtml \ + htdocs/include.shtml +ICON_FILES = icons/README \ + icons/a.gif \ + icons/alert.black.gif \ + icons/alert.red.gif \ + icons/apache_pb.gif \ + icons/back.gif \ + icons/ball.gray.gif \ + icons/ball.red.gif \ + icons/binary.gif \ + icons/binhex.gif \ + icons/blank.gif \ + icons/bomb.gif \ + icons/box1.gif \ + icons/box2.gif \ + icons/broken.gif \ + icons/burst.gif \ + icons/button1.gif \ + icons/button10.gif \ + icons/button2.gif \ + icons/button3.gif \ + icons/button4.gif \ + icons/button5.gif \ + icons/button6.gif \ + icons/button7.gif \ + icons/button8.gif \ + icons/button9.gif \ + icons/buttonl.gif \ + icons/buttonr.gif \ + icons/c.gif \ + icons/comp.blue.gif \ + icons/comp.gray.gif \ + icons/compressed.gif \ + icons/continued.gif \ + icons/dir.gif \ + icons/down.gif \ + icons/dvi.gif \ + icons/f.gif \ + icons/folder.gif \ + icons/folder.open.gif \ + icons/folder.sec.gif \ + icons/forward.gif \ + icons/generic.gif \ + icons/generic.red.gif \ + icons/generic.sec.gif \ + icons/hand.right.gif \ + icons/hand.up.gif \ + icons/htdig.gif \ + icons/icon.sheet.gif \ + icons/image1.gif \ + icons/image2.gif \ + icons/image3.gif \ + icons/index.gif \ + icons/layout.gif \ + icons/left.gif \ + icons/link.gif \ + icons/movie.gif \ + icons/p.gif \ + icons/patch.gif \ + icons/pdf.gif \ + icons/pie0.gif \ + icons/pie1.gif \ + icons/pie2.gif \ + icons/pie3.gif \ + icons/pie4.gif \ + icons/pie5.gif \ + icons/pie6.gif \ + icons/pie7.gif \ + icons/pie8.gif \ + icons/portal.gif \ + icons/poweredby.gif \ + icons/ps.gif \ + icons/quill.gif \ + icons/right.gif \ + icons/screw1.gif \ + icons/screw2.gif \ + icons/script.gif \ + icons/sound1.gif \ + icons/sound2.gif \ + icons/sphere1.gif \ + icons/sphere2.gif \ + icons/star.gif \ + icons/star_blank.gif \ + icons/tar.gif \ + icons/tex.gif \ + icons/text.gif \ + icons/transfer.gif \ + icons/unknown.gif \ + icons/up.gif \ + icons/uu.gif \ + icons/uuencoded.gif \ + icons/world1.gif \ + icons/world2.gif + +SSL_FILES = ssl/ssl_client.pem \ + ssl/ssl_server.pem + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_COMPILE_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +debug opt: + +clean: + +docs: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/auth + $(INSTALL_DATA) $(AUTH_FILES) $(RELSYSDIR)/examples/server_root/auth + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/cgi-bin + $(INSTALL_SCRIPT) $(CGI_FILES) $(RELSYSDIR)/examples/server_root/cgi-bin + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/conf + $(INSTALL_DATA) $(CONF_FILES) $(RELSYSDIR)/examples/server_root/conf + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/htdocs/open + $(INSTALL_DATA) $(OPEN_FILES) \ + $(RELSYSDIR)/examples/server_root/htdocs/open + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/htdocs/mnesia_open + $(INSTALL_DATA) $(MNESIA_OPEN_FILES) \ + $(RELSYSDIR)/examples/server_root/htdocs/mnesia_open + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/htdocs/misc + $(INSTALL_DATA) $(MISC_FILES) \ + $(RELSYSDIR)/examples/server_root/htdocs/misc + $(INSTALL_DIR) \ + $(RELSYSDIR)/examples/server_root/htdocs/secret/top_secret + $(INSTALL_DIR) \ + $(RELSYSDIR)/examples/server_root/htdocs/mnesia_secret/top_secret + $(INSTALL_DATA) $(SECRET_FILES) \ + $(RELSYSDIR)/examples/server_root/htdocs/secret + $(INSTALL_DATA) $(MNESIA_SECRET_FILES) \ + $(RELSYSDIR)/examples/server_root/htdocs/mnesia_secret + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/htdocs + $(INSTALL_DATA) $(HTDOCS_FILES) $(RELSYSDIR)/examples/server_root/htdocs + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/icons + $(INSTALL_DATA) $(ICON_FILES) $(RELSYSDIR)/examples/server_root/icons + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/ssl + $(INSTALL_DATA) $(SSL_FILES) $(RELSYSDIR)/examples/server_root/ssl + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/logs + +release_docs_spec: + diff --git a/lib/inets/test/httpd_block.erl b/lib/inets/test/httpd_block.erl index f967d8172a..ac1bf43ff5 100644 --- a/lib/inets/test/httpd_block.erl +++ b/lib/inets/test/httpd_block.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -36,6 +36,7 @@ ]). %% Help functions +-export([httpd_block/3, httpd_block/4, httpd_unblock/2, httpd_restart/2]). -export([do_block_server/4, do_block_nd_server/5, do_long_poll/6]). -define(report(Label, Content), @@ -47,18 +48,24 @@ %% Test cases starts here. %%------------------------------------------------------------------------- block_disturbing_idle(_Type, Port, Host, Node) -> - unblocked = get_admin_state(Node, Host, Port), + io:format("block_disturbing_idle -> entry~n", []), + validate_admin_state(Node, Host, Port, unblocked), block_server(Node, Host, Port), - blocked = get_admin_state(Node, Host, Port), + validate_admin_state(Node, Host, Port, blocked), unblock_server(Node, Host, Port), - unblocked = get_admin_state(Node, Host, Port). + validate_admin_state(Node, Host, Port, unblocked), + io:format("block_disturbing_idle -> done~n", []), + ok. + %%-------------------------------------------------------------------- block_non_disturbing_idle(_Type, Port, Host, Node) -> unblocked = get_admin_state(Node, Host, Port), block_nd_server(Node, Host, Port), blocked = get_admin_state(Node, Host, Port), unblock_server(Node, Host, Port), - unblocked = get_admin_state(Node, Host, Port). + unblocked = get_admin_state(Node, Host, Port), + ok. + %%-------------------------------------------------------------------- block_503(Type, Port, Host, Node) -> Req = "GET / HTTP/1.0\r\ndummy-host.ericsson.se:\r\n\r\n", @@ -76,6 +83,7 @@ block_503(Type, Port, Host, Node) -> ok = httpd_test_lib:verify_request(Type, Host, Port, Node, Req, [{statuscode, 200}, {version, "HTTP/1.0"}]). + %%-------------------------------------------------------------------- block_disturbing_active(Type, Port, Host, Node) -> process_flag(trap_exit, true), @@ -87,6 +95,7 @@ block_disturbing_active(Type, Port, Host, Node) -> blocked = get_admin_state(Node, Host, Port), process_flag(trap_exit, false), ok. + %%-------------------------------------------------------------------- block_non_disturbing_active(Type, Port, Host, Node) -> process_flag(trap_exit, true), @@ -219,32 +228,91 @@ do_block_nd_server(Node, Host, Port, Timeout, Reply) -> restart_server(Node, _Host, Port) -> Addr = undefined, - rpc:call(Node, httpd, restart, [Addr, Port]). + rpc:call(Node, ?MODULE, httpd_restart, [Addr, Port]). + block_server(Node, _Host, Port) -> + io:format("block_server -> entry~n", []), Addr = undefined, - rpc:call(Node, httpd, block, [Addr, Port]). + rpc:call(Node, ?MODULE, httpd_block, [Addr, Port, disturbing]). + block_server(Node, _Host, Port, Timeout) -> Addr = undefined, - rpc:call(Node, httpd, block, [Addr, Port, disturbing, Timeout]). + rpc:call(Node, ?MODULE, httpd_block, [Addr, Port, disturbing, Timeout]). + block_nd_server(Node, _Host, Port) -> Addr = undefined, - rpc:call(Node, httpd, block, [Addr, Port, non_disturbing]). + rpc:call(Node, ?MODULE, httpd_block, [Addr, Port, non_disturbing]). block_nd_server(Node, _Host, Port, Timeout) -> Addr = undefined, - rpc:call(Node, httpd, block, [Addr, Port, non_disturbing, Timeout]). + rpc:call(Node, ?MODULE, httpd_block, [Addr, Port, non_disturbing, Timeout]). unblock_server(Node, _Host, Port) -> + io:format("~p:~p:block_server -> entry~n", [node(),self()]), Addr = undefined, - rpc:call(Node, httpd, unblock, [Addr, Port]). + rpc:call(Node, ?MODULE, httpd_unblock, [Addr, Port]). + + +httpd_block(Addr, Port, Mode) -> + io:format("~p:~p:httpd_block -> entry~n", [node(),self()]), + Name = make_name(Addr, Port), + case whereis(Name) of + Pid when is_pid(Pid) -> + httpd_manager:block(Pid, Mode); + _ -> + {error, not_started} + end. + +httpd_block(Addr, Port, Mode, Timeout) -> + Name = make_name(Addr, Port), + case whereis(Name) of + Pid when is_pid(Pid) -> + httpd_manager:block(Pid, Mode, Timeout); + _ -> + {error, not_started} + end. + +httpd_unblock(Addr, Port) -> + io:format("~p:~p:httpd_unblock -> entry~n", [node(),self()]), + Name = make_name(Addr, Port), + case whereis(Name) of + Pid when is_pid(Pid) -> + httpd_manager:unblock(Pid); + _ -> + {error, not_started} + end. + +httpd_restart(Addr, Port) -> + Name = make_name(Addr, Port), + case whereis(Name) of + Pid when is_pid(Pid) -> + httpd_manager:reload(Pid, undefined); + _ -> + {error, not_started} + end. + +make_name(Addr, Port) -> + httpd_util:make_name("httpd", Addr, Port). -get_admin_state(Node,_Host,Port) -> +get_admin_state(Node, _Host, Port) -> Addr = undefined, rpc:call(Node, httpd, get_admin_state, [Addr, Port]). +validate_admin_state(Node, Host, Port, Expect) -> + io:format("try validating server admin state: ~p~n", [Expect]), + case get_admin_state(Node, Host, Port) of + Expect -> + ok; + Unexpected -> + io:format("failed validating server admin state: ~p~n", + [Unexpected]), + exit({unexpected_admin_state, Unexpected, Expect}) + end. + + await_normal_process_exit(Pid, Name, Timeout) -> receive {'EXIT', Pid, normal} -> @@ -260,6 +328,7 @@ await_normal_process_exit(Pid, Name, Timeout) -> test_server:fail("timeout while waiting for " ++ Name) end. + await_suite_failed_process_exit(Pid, Name, Timeout, Why) -> receive {'EXIT', Pid, {suite_failed, Why}} -> diff --git a/lib/inets/test/httpd_mod.erl b/lib/inets/test/httpd_mod.erl index b03f842e7c..f2c1fd6a65 100644 --- a/lib/inets/test/httpd_mod.erl +++ b/lib/inets/test/httpd_mod.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -40,6 +40,13 @@ %% Test cases starts here. %%------------------------------------------------------------------------- alias(Type, Port, Host, Node) -> +%% io:format(user, "~w:alias -> entry with" +%% "~n Type: ~p" +%% "~n Port: ~p" +%% "~n Host: ~p" +%% "~n Node: ~p" +%% "~n", [?MODULE, Type, Port, Host, Node]), + ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /pics/icon.sheet.gif " "HTTP/1.0\r\n\r\n", @@ -82,14 +89,15 @@ actions(Type, Port, Host, Node) -> %%------------------------------------------------------------------------- security(ServerRoot, Type, Port, Host, Node) -> - io:format(user, "~w:security -> entry with" - "~n ServerRoot: ~p" - "~n Type: ~p" - "~n Port: ~p" - "~n Host: ~p" - "~n Node: ~p" - "~n", [?MODULE, ServerRoot, Type, Port, Host, Node]), +%% io:format(user, "~w:security -> entry with" +%% "~n ServerRoot: ~p" +%% "~n Type: ~p" +%% "~n Port: ~p" +%% "~n Host: ~p" +%% "~n Node: ~p" +%% "~n", [?MODULE, ServerRoot, Type, Port, Host, Node]), +%% io:format(user, "~w:security -> register~n", [?MODULE]), global:register_name(mod_security_test, self()), % Receive events test_server:sleep(5000), @@ -99,54 +107,71 @@ security(ServerRoot, Type, Port, Host, Node) -> %% Test blocking / unblocking of users. %% /open, require user one Aladdin +%% io:format(user, "~w:security -> remove user~n", [?MODULE]), remove_users(Node, ServerRoot, Host, Port, "open"), +%% io:format(user, "~w:security -> auth request~n", [?MODULE]), auth_request(Type, Host, Port, Node, "/open/", "one", "onePassword", [{statuscode, 401}]), +%% io:format(user, "~w:security -> await fail security event~n", [?MODULE]), receive_security_event({event, auth_fail, Port, OpenDir, [{user, "one"}, {password, "onePassword"}]}, Node, Port), +%% io:format(user, "~w:security -> auth request~n", [?MODULE]), auth_request(Type,Host,Port,Node,"/open/", "two", "twoPassword", [{statuscode, 401}]), +%% io:format(user, "~w:security -> await fail security event~n", [?MODULE]), receive_security_event({event, auth_fail, Port, OpenDir, [{user, "two"}, {password, "twoPassword"}]}, Node, Port), +%% io:format(user, "~w:security -> auth request~n", [?MODULE]), auth_request(Type, Host, Port, Node,"/open/", "Aladdin", "AladdinPassword", [{statuscode, 401}]), +%% io:format(user, "~w:security -> await fail security event~n", [?MODULE]), receive_security_event({event, auth_fail, Port, OpenDir, [{user, "Aladdin"}, {password, "AladdinPassword"}]}, Node, Port), +%% io:format(user, "~w:security -> add users~n", [?MODULE]), add_user(Node, ServerRoot, Port, "open", "one", "onePassword", []), add_user(Node, ServerRoot, Port, "open", "two", "twoPassword", []), +%% io:format(user, "~w:security -> auth request~n", [?MODULE]), auth_request(Type, Host, Port, Node,"/open/", "one", "WrongPassword", [{statuscode, 401}]), +%% io:format(user, "~w:security -> await fail security event~n", [?MODULE]), receive_security_event({event, auth_fail, Port, OpenDir, [{user, "one"}, {password, "WrongPassword"}]}, Node, Port), +%% io:format(user, "~w:security -> auth request~n", [?MODULE]), auth_request(Type, Host, Port, Node,"/open/", "one", "WrongPassword", [{statuscode, 401}]), +%% io:format(user, "~w:security -> await fail security event~n", [?MODULE]), receive_security_event({event, auth_fail, Port, OpenDir, [{user, "one"}, {password, "WrongPassword"}]}, Node, Port), +%% io:format(user, "~w:security -> await block security event~n", [?MODULE]), receive_security_event({event, user_block, Port, OpenDir, [{user, "one"}]}, Node, Port), +%% io:format(user, "~w:security -> unregister~n", [?MODULE]), global:unregister_name(mod_security_test), % No more events. +%% io:format(user, "~w:security -> auth request~n", [?MODULE]), auth_request(Type, Host, Port, Node,"/open/", "one", "WrongPassword", [{statuscode, 401}]), +%% io:format(user, "~w:security -> auth request~n", [?MODULE]), auth_request(Type, Host, Port, Node,"/open/", "one", "onePassword", [{statuscode, 403}]), %% User "one" should be blocked now.. %% [{"one",_, Port, OpenDir,_}] = list_blocked_users(Node,Port), +%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]), case list_blocked_users(Node, Port) of [{"one",_, Port, OpenDir,_}] -> ok; @@ -156,35 +181,54 @@ security(ServerRoot, Type, Port, Host, Node) -> exit({unexpected_blocked, Blocked}) end, +%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]), [{"one",_, Port, OpenDir,_}] = list_blocked_users(Node,Port,OpenDir), +%% io:format(user, "~w:security -> unblock user~n", [?MODULE]), true = unblock_user(Node, "one", Port, OpenDir), %% User "one" should not be blocked any more.. +%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]), [] = list_blocked_users(Node, Port), +%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]), [] = list_blocked_users(Node, Port, OpenDir), +%% io:format(user, "~w:security -> auth request~n", [?MODULE]), auth_request(Type, Host, Port, Node,"/open/", "one", "onePassword", [{statuscode, 200}]), %% Test list_auth_users & auth_timeout +%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]), ["one"] = list_auth_users(Node, Port), +%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]), ["one"] = list_auth_users(Node, Port, OpenDir), +%% io:format(user, "~w:security -> auth request~n", [?MODULE]), auth_request(Type, Host, Port, Node,"/open/", "two", "onePassword", [{statuscode, 401}]), +%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]), ["one"] = list_auth_users(Node, Port), +%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]), ["one"] = list_auth_users(Node, Port, OpenDir), +%% io:format(user, "~w:security -> auth request~n", [?MODULE]), auth_request(Type, Host, Port, Node,"/open/", "two", "twoPassword", [{statuscode, 401}]), +%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]), ["one"] = list_auth_users(Node, Port), +%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]), ["one"] = list_auth_users(Node, Port, OpenDir), %% Wait for successful auth to timeout. test_server:sleep(?AUTH_TIMEOUT*1001), +%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]), [] = list_auth_users(Node, Port), +%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]), [] = list_auth_users(Node, Port, OpenDir), %% "two" is blocked. +%% io:format(user, "~w:security -> unblock user~n", [?MODULE]), true = unblock_user(Node, "two", Port, OpenDir), %% Test explicit blocking. Block user 'two'. +%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]), [] = list_blocked_users(Node,Port,OpenDir), +%% io:format(user, "~w:security -> block user~n", [?MODULE]), true = block_user(Node, "two", Port, OpenDir, 10), +%% io:format(user, "~w:security -> auth request~n", [?MODULE]), auth_request(Type, Host, Port, Node,"/open/", "two", "twoPassword", [{statuscode, 401}]). @@ -600,6 +644,11 @@ htaccess(Type, Port, Host, Node) -> {header, "WWW-Authenticate"}]). %%-------------------------------------------------------------------- cgi(Type, Port, Host, Node) -> +%% tsp("cgi -> entry with" +%% "~n Type: ~p" +%% "~n Port: ~p" +%% "~n Host: ~p" +%% "~n Node: ~p", []), {Script, Script2, Script3} = case test_server:os_type() of {win32, _} -> @@ -609,6 +658,7 @@ cgi(Type, Port, Host, Node) -> end, %% The length (> 100) is intentional +%% tsp("cgi -> request 01 with length > 100"), ok = httpd_test_lib: verify_request(Type, Host, Port, Node, "POST /cgi-bin/" ++ Script3 ++ @@ -636,46 +686,55 @@ cgi(Type, Port, Host, Node) -> {version, "HTTP/1.0"}, {header, "content-type", "text/plain"}]), +%% tsp("cgi -> request 02"), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /cgi-bin/"++ Script ++ " HTTP/1.0\r\n\r\n", [{statuscode, 200}, {version, "HTTP/1.0"}]), +%% tsp("cgi -> request 03"), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /cgi-bin/not_there " "HTTP/1.0\r\n\r\n", [{statuscode, 404},{statuscode, 500}, {version, "HTTP/1.0"}]), +%% tsp("cgi -> request 04"), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /cgi-bin/"++ Script ++ "?Nisse:kkk?sss/lll HTTP/1.0\r\n\r\n", [{statuscode, 200}, {version, "HTTP/1.0"}]), +%% tsp("cgi -> request 04"), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "POST /cgi-bin/"++ Script ++ " HTTP/1.0\r\n\r\n", [{statuscode, 200}, {version, "HTTP/1.0"}]), +%% tsp("cgi -> request 05"), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /htbin/"++ Script ++ " HTTP/1.0\r\n\r\n", [{statuscode, 200}, {version, "HTTP/1.0"}]), +%% tsp("cgi -> request 06"), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /htbin/not_there " "HTTP/1.0\r\n\r\n", [{statuscode, 404},{statuscode, 500}, {version, "HTTP/1.0"}]), +%% tsp("cgi -> request 07"), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "GET /htbin/"++ Script ++ "?Nisse:kkk?sss/lll HTTP/1.0\r\n\r\n", [{statuscode, 200}, {version, "HTTP/1.0"}]), +%% tsp("cgi -> request 08"), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "POST /htbin/"++ Script ++ " HTTP/1.0\r\n\r\n", [{statuscode, 200}, {version, "HTTP/1.0"}]), +%% tsp("cgi -> request 09"), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "POST /htbin/"++ Script ++ " HTTP/1.0\r\n\r\n", @@ -683,19 +742,24 @@ cgi(Type, Port, Host, Node) -> {version, "HTTP/1.0"}]), %% Execute an existing, but bad CGI script.. +%% tsp("cgi -> request 10 - bad script"), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "POST /htbin/"++ Script2 ++ " HTTP/1.0\r\n\r\n", [{statuscode, 404}, {version, "HTTP/1.0"}]), +%% tsp("cgi -> request 11 - bad script"), ok = httpd_test_lib:verify_request(Type, Host, Port, Node, "POST /cgi-bin/"++ Script2 ++ " HTTP/1.0\r\n\r\n", [{statuscode, 404}, {version, "HTTP/1.0"}]), + +%% tsp("cgi -> done"), ok. + %%-------------------------------------------------------------------- esi(Type, Port, Host, Node) -> %% Check "ErlScriptAlias" and "EvalScriptAlias" directives @@ -850,25 +914,44 @@ list_users(Node, Root, _Host, Port, Dir) -> Directory = filename:join([Root, "htdocs", Dir]), rpc:call(Node, mod_auth, list_users, [Addr, Port, Directory]). + receive_security_event(Event, Node, Port) -> - io:format(user, "~w:receive_security_event -> entry with" - "~n Event: ~p" - "~n Node: ~p" - "~n Port: ~p" - "~n", [?MODULE, Event, Node, Port]), +%% io:format(user, "~w:receive_security_event -> entry with" +%% "~n Event: ~p" +%% "~n Node: ~p" +%% "~n Port: ~p" +%% "~n", [?MODULE, Event, Node, Port]), receive Event -> ok; {'EXIT', _, _} -> - receive_security_event(Event, Node, Port); - Other -> - test_server:fail({unexpected_event, - {expected, Event}, {received, Other}}) + receive_security_event(Event, Node, Port) after 5000 -> - test_server:fail(no_event_recived) + %% Flush the message queue, to see if we got something... + Msgs = inets_test_lib:flush(), + tsf({expected_event_not_received, Msgs}) end. +%% receive_security_event(Event, Node, Port) -> +%% io:format(user, "~w:receive_security_event -> entry with" +%% "~n Event: ~p" +%% "~n Node: ~p" +%% "~n Port: ~p" +%% "~n", [?MODULE, Event, Node, Port]), +%% receive +%% Event -> +%% ok; +%% {'EXIT', _, _} -> +%% receive_security_event(Event, Node, Port); +%% Other -> +%% test_server:fail({unexpected_event, +%% {expected, Event}, {received, Other}}) +%% after 5000 -> +%% test_server:fail(no_event_recived) + +%% end. + list_blocked_users(Node,Port) -> Addr = undefined, % Assumed to be on the same host rpc:call(Node, mod_security, list_blocked_users, [Addr,Port]). @@ -945,3 +1028,12 @@ check_lists_members1(L,L) -> ok; check_lists_members1(L1,L2) -> {error,{lists_not_equal,L1,L2}}. + + +%% tsp(F) -> +%% tsp(F, []). +%% tsp(F, A) -> +%% test_server:format("~p ~p:" ++ F ++ "~n", [self(), ?MODULE | A]). + +tsf(Reason) -> + test_server:fail(Reason). diff --git a/lib/inets/test/httpd_poll.erl b/lib/inets/test/httpd_poll.erl index 1cc10365a7..32335cabcf 100644 --- a/lib/inets/test/httpd_poll.erl +++ b/lib/inets/test/httpd_poll.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2000-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2000-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -27,7 +27,8 @@ %% gen_server exports -export([init/1, - handle_call/3, handle_cast/2, handle_info/2, terminate/2]). + handle_call/3, handle_cast/2, handle_info/2, terminate/2, + code_change/3]). -define(default_verbosity,error). @@ -86,8 +87,8 @@ options(Options) -> options([], Defaults, Options) -> Options ++ Defaults; -options([{Key,Val} = Opt|Opts], Defaults, Options) -> - options(Opts, lists:keydelete(Key, 1, Defaults), [Opt|Options]). +options([{Key, _Val} = Opt|Opts], Defaults, Options) -> + options(Opts, lists:keydelete(Key, 1, Defaults), [Opt | Options]). verbosity(silence) -> @@ -134,10 +135,9 @@ uris(otp) -> uri_top_index(), uri_internal_product1(), uri_internal_product2(), - uri_p7a_test_results(), + uri_r13b03_test_results(), uri_bjorn1(), - uri_bjorn2(), - uri_top_ronja() + uri_bjorn2() ]. uri_top_index() -> @@ -149,9 +149,9 @@ uri_internal_product1() -> uri_internal_product2() -> {"product internal page (2)","/product/internal"}. -uri_p7a_test_results() -> - {"test summery index page", - "/product/internal/test/test_results/progress_P7A/index.html"}. +uri_r13b03_test_results() -> + {"daily build index page", + "/product/internal/test/daily/logs.html"}. uri_bjorn1() -> {"bjorns home page (1)","/~bjorn/"}. @@ -159,9 +159,6 @@ uri_bjorn1() -> uri_bjorn2() -> {"bjorns home page (2)","/~bjorn"}. -uri_top_ronja() -> - {"ronja top page","/ronja/"}. - handle_call(stop, _From, State) -> vlog("stop request"), @@ -199,7 +196,11 @@ handle_info(Info, State) -> {noreply, State}. -terminate(Reason,State) -> +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + + +terminate(_Reason, State) -> tcancel(State#state.tref), log_close(get(log_file)), ok. @@ -287,16 +288,16 @@ trash_the_rest(Socket,N) -> end. -add(N1,N2) when integer(N1),integer(N2) -> +add(N1, N2) when is_integer(N1) andalso is_integer(N2) -> N1 + N2; -add(N1,N2) when integer(N1) -> +add(N1, _N2) when is_integer(N1) -> N1; -add(N1,N2) when integer(N2) -> +add(_N1, N2) when is_integer(N2) -> N2. -sz(L) when list(L) -> +sz(L) when is_list(L) -> length(lists:flatten(L)); -sz(B) when binary(B) -> +sz(B) when is_binary(B) -> size(B); sz(O) -> {unknown_size,O}. @@ -307,9 +308,9 @@ sz(O) -> %% Status code to printable string %% -status_to_message(L) when list(L) -> +status_to_message(L) when is_list(L) -> case (catch list_to_integer(L)) of - I when integer(I) -> + I when is_integer(I) -> status_to_message(I); _ -> io_lib:format("UNKNOWN STATUS CODE: '~p'",[L]) @@ -470,12 +471,12 @@ vlog(F,A) -> vprint(get(verbosity),log,F,A). verror(F) -> vprint(get(verbosity),error,F,[]). verror(F,A) -> vprint(get(verbosity),error,F,A). -vprint(trace,Severity,F,A) -> vprint(Severity,F,A); -vprint(debug,trace,F,A) -> ok; -vprint(debug,Severity,F,A) -> vprint(Severity,F,A); -vprint(log,log,F,A) -> vprint(log,F,A); -vprint(log,error,F,A) -> vprint(log,F,A); -vprint(error,error,F,A) -> vprint(error,F,A); +vprint(trace, Severity, F, A) -> vprint(Severity,F,A); +vprint(debug, trace, _F, _A) -> ok; +vprint(debug, Severity, F, A) -> vprint(Severity,F,A); +vprint(log, log, F, A) -> vprint(log,F,A); +vprint(log, error, F, A) -> vprint(log,F,A); +vprint(error, error, F, A) -> vprint(error,F,A); vprint(_Verbosity,_Severity,_F,_A) -> ok. vprint(Severity,F,A) -> @@ -491,6 +492,3 @@ image_of(trace) -> "TRC: ". local_time() -> calendar:local_time(). - - - diff --git a/lib/inets/test/httpd_test_data/server_root/Makefile b/lib/inets/test/httpd_test_data/server_root/Makefile new file mode 100644 index 0000000000..d7a3231068 --- /dev/null +++ b/lib/inets/test/httpd_test_data/server_root/Makefile @@ -0,0 +1,209 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2010. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(INETS_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/inets-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +MODULE= + +AUTH_FILES = auth/group \ + auth/passwd +CGI_FILES = cgi-bin/printenv.sh +CONF_FILES = conf/8080.conf \ + conf/8888.conf \ + conf/httpd.conf \ + conf/ssl.conf \ + conf/mime.types +OPEN_FILES = htdocs/open/dummy.html +MNESIA_OPEN_FILES = htdocs/mnesia_open/dummy.html +MISC_FILES = htdocs/misc/friedrich.html \ + htdocs/misc/oech.html +SECRET_FILES = htdocs/secret/dummy.html +MNESIA_SECRET_FILES = htdocs/mnesia_secret/dummy.html +HTDOCS_FILES = htdocs/index.html \ + htdocs/config.shtml \ + htdocs/echo.shtml \ + htdocs/exec.shtml \ + htdocs/flastmod.shtml \ + htdocs/fsize.shtml \ + htdocs/include.shtml +ICON_FILES = icons/README \ + icons/a.gif \ + icons/alert.black.gif \ + icons/alert.red.gif \ + icons/apache_pb.gif \ + icons/back.gif \ + icons/ball.gray.gif \ + icons/ball.red.gif \ + icons/binary.gif \ + icons/binhex.gif \ + icons/blank.gif \ + icons/bomb.gif \ + icons/box1.gif \ + icons/box2.gif \ + icons/broken.gif \ + icons/burst.gif \ + icons/button1.gif \ + icons/button10.gif \ + icons/button2.gif \ + icons/button3.gif \ + icons/button4.gif \ + icons/button5.gif \ + icons/button6.gif \ + icons/button7.gif \ + icons/button8.gif \ + icons/button9.gif \ + icons/buttonl.gif \ + icons/buttonr.gif \ + icons/c.gif \ + icons/comp.blue.gif \ + icons/comp.gray.gif \ + icons/compressed.gif \ + icons/continued.gif \ + icons/dir.gif \ + icons/down.gif \ + icons/dvi.gif \ + icons/f.gif \ + icons/folder.gif \ + icons/folder.open.gif \ + icons/folder.sec.gif \ + icons/forward.gif \ + icons/generic.gif \ + icons/generic.red.gif \ + icons/generic.sec.gif \ + icons/hand.right.gif \ + icons/hand.up.gif \ + icons/htdig.gif \ + icons/icon.sheet.gif \ + icons/image1.gif \ + icons/image2.gif \ + icons/image3.gif \ + icons/index.gif \ + icons/layout.gif \ + icons/left.gif \ + icons/link.gif \ + icons/movie.gif \ + icons/p.gif \ + icons/patch.gif \ + icons/pdf.gif \ + icons/pie0.gif \ + icons/pie1.gif \ + icons/pie2.gif \ + icons/pie3.gif \ + icons/pie4.gif \ + icons/pie5.gif \ + icons/pie6.gif \ + icons/pie7.gif \ + icons/pie8.gif \ + icons/portal.gif \ + icons/poweredby.gif \ + icons/ps.gif \ + icons/quill.gif \ + icons/right.gif \ + icons/screw1.gif \ + icons/screw2.gif \ + icons/script.gif \ + icons/sound1.gif \ + icons/sound2.gif \ + icons/sphere1.gif \ + icons/sphere2.gif \ + icons/star.gif \ + icons/star_blank.gif \ + icons/tar.gif \ + icons/tex.gif \ + icons/text.gif \ + icons/transfer.gif \ + icons/unknown.gif \ + icons/up.gif \ + icons/uu.gif \ + icons/uuencoded.gif \ + icons/world1.gif \ + icons/world2.gif + +SSL_FILES = ssl/ssl_client.pem \ + ssl/ssl_server.pem + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_COMPILE_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +debug opt: + +clean: + +docs: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/auth + $(INSTALL_DATA) $(AUTH_FILES) $(RELSYSDIR)/examples/server_root/auth + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/cgi-bin + $(INSTALL_SCRIPT) $(CGI_FILES) $(RELSYSDIR)/examples/server_root/cgi-bin + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/conf + $(INSTALL_DATA) $(CONF_FILES) $(RELSYSDIR)/examples/server_root/conf + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/htdocs/open + $(INSTALL_DATA) $(OPEN_FILES) \ + $(RELSYSDIR)/examples/server_root/htdocs/open + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/htdocs/mnesia_open + $(INSTALL_DATA) $(MNESIA_OPEN_FILES) \ + $(RELSYSDIR)/examples/server_root/htdocs/mnesia_open + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/htdocs/misc + $(INSTALL_DATA) $(MISC_FILES) \ + $(RELSYSDIR)/examples/server_root/htdocs/misc + $(INSTALL_DIR) \ + $(RELSYSDIR)/examples/server_root/htdocs/secret/top_secret + $(INSTALL_DIR) \ + $(RELSYSDIR)/examples/server_root/htdocs/mnesia_secret/top_secret + $(INSTALL_DATA) $(SECRET_FILES) \ + $(RELSYSDIR)/examples/server_root/htdocs/secret + $(INSTALL_DATA) $(MNESIA_SECRET_FILES) \ + $(RELSYSDIR)/examples/server_root/htdocs/mnesia_secret + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/htdocs + $(INSTALL_DATA) $(HTDOCS_FILES) $(RELSYSDIR)/examples/server_root/htdocs + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/icons + $(INSTALL_DATA) $(ICON_FILES) $(RELSYSDIR)/examples/server_root/icons + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/ssl + $(INSTALL_DATA) $(SSL_FILES) $(RELSYSDIR)/examples/server_root/ssl + $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/logs + +release_docs_spec: + diff --git a/lib/inets/test/httpd_test_lib.erl b/lib/inets/test/httpd_test_lib.erl index 6abee5be2c..3189a758a5 100644 --- a/lib/inets/test/httpd_test_lib.erl +++ b/lib/inets/test/httpd_test_lib.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2001-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -72,6 +72,8 @@ 'last-modified', other=[] % list() - Key/Value list with other headers }). + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%-------------------------------------------------------------------- @@ -81,7 +83,8 @@ verify_request(SocketType, Host, Port, Node, RequestStr, Options) -> verify_request(SocketType, Host, Port, Node, RequestStr, Options, 30000). verify_request(SocketType, Host, Port, Node, RequestStr, Options, TimeOut) -> {ok, Socket} = inets_test_lib:connect_bin(SocketType, Host, Port), - inets_test_lib:send(SocketType, Socket, RequestStr), + + _SendRes = inets_test_lib:send(SocketType, Socket, RequestStr), State = case inets_regexp:match(RequestStr, "printenv") of nomatch -> @@ -90,18 +93,26 @@ verify_request(SocketType, Host, Port, Node, RequestStr, Options, TimeOut) -> #state{print = true} end, - case request(State#state{request = RequestStr, socket = Socket}, TimeOut) of - {error, Reson} -> - {error, Reson}; + case request(State#state{request = RequestStr, + socket = Socket}, TimeOut) of + {error, Reason} -> + tsp("request failed: " + "~n Reason: ~p", [Reason]), + {error, Reason}; NewState -> + tsp("validate reply: " + "~n NewState: ~p", [NewState]), ValidateResult = validate(RequestStr, NewState, Options, Node, Port), + tsp("validation result: " + "~n ~p", [ValidateResult]), inets_test_lib:close(SocketType, Socket), ValidateResult end. request(#state{mfa = {Module, Function, Args}, request = RequestStr, socket = Socket} = State, TimeOut) -> + HeadRequest = lists:sublist(RequestStr, 1, 4), receive {tcp, Socket, Data} -> @@ -109,12 +120,12 @@ request(#state{mfa = {Module, Function, Args}, case Module:Function([Data | Args]) of {ok, Parsed} -> handle_http_msg(Parsed, State); - {_, whole_body, _} when HeadRequest == "HEAD" -> + {_, whole_body, _} when HeadRequest =:= "HEAD" -> State#state{body = <<>>}; NewMFA -> request(State#state{mfa = NewMFA}, TimeOut) end; - {tcp_closed, Socket} when Function == whole_body -> + {tcp_closed, Socket} when Function =:= whole_body -> print(tcp, "closed", State), State#state{body = hd(Args)}; {tcp_closed, Socket} -> @@ -126,12 +137,12 @@ request(#state{mfa = {Module, Function, Args}, case Module:Function([Data | Args]) of {ok, Parsed} -> handle_http_msg(Parsed, State); - {_, whole_body, _} when HeadRequest == "HEAD" -> + {_, whole_body, _} when HeadRequest =:= "HEAD" -> State#state{body = <<>>}; NewMFA -> request(State#state{mfa = NewMFA}, TimeOut) end; - {ssl_closed, Socket} when Function == whole_body -> + {ssl_closed, Socket} when Function =:= whole_body -> print(ssl, "closed", State), State#state{body = hd(Args)}; {ssl_closed, Socket} -> @@ -330,3 +341,9 @@ print(Proto, Data, #state{print = true}) -> print(_, _, #state{print = false}) -> ok. + +%% tsp(F) -> +%% tsp(F, []). +tsp(F, A) -> + test_server:format("~p ~p:" ++ F ++ "~n", [self(), ?MODULE | A]). + diff --git a/lib/inets/test/httpd_time_test.erl b/lib/inets/test/httpd_time_test.erl index 7d6aa08542..f39f9faff0 100644 --- a/lib/inets/test/httpd_time_test.erl +++ b/lib/inets/test/httpd_time_test.erl @@ -1,25 +1,25 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2001-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% -module(httpd_time_test). --export([t/3, t1/2, t2/2]). +-export([t/3, t1/2, t2/2, t3/2, t4/2]). -export([do/1, do/2, do/3, do/4, do/5]). @@ -29,6 +29,9 @@ -record(stat, {pid, time = undefined, count = undefined, res}). +%% -define(NUM_POLLERS, 10). +-define(NUM_POLLERS, 1). + %%% ----------------------------------------------------------------- %%% Test suite interface @@ -42,9 +45,17 @@ t2(Host, Port) -> t(ssl, Host, Port). +t3(Host, Port) -> + t(ossl, Host, Port). + + +t4(Host, Port) -> + t(essl, Host, Port). + + t(SocketType, Host, Port) -> %% put(dbg,true), - main(1, SocketType, Host, Port, 60000). + main(?NUM_POLLERS, SocketType, Host, Port, 60000). @@ -111,28 +122,40 @@ loop(Pollers, Timeout) -> "~n Timeout: ~p", [Timeout]), Start = t(), receive - {'EXIT', Pid, {poller_stat_failure, Time, Reason}} -> + {'EXIT', Pid, {poller_stat_failure, SocketType, Host, Port, Time, Reason}} -> case is_poller(Pid, Pollers) of true -> error_msg("received unexpected exit from poller ~p~n" "befor completion of test " - "(after ~p micro sec):~n" - "~p~n", [Pid,Time,Reason]), - exit({fail, {poller_exit, Pid, Reason}}); + "after ~p micro sec" + "~n SocketType: ~p" + "~n Host: ~p" + "~n Port: ~p" + "~n~p~n", + [Pid, SocketType, Host, Port, Time, Reason]), + exit({fail, {poller_exit, Pid, Time, Reason}}); false -> error_msg("received unexpected ~p from ~p" "befor completion of test", [Reason, Pid]), loop(Pollers, to(Timeout, Start)) end; - {poller_stat_failure, Pid, {Time, Reason}} -> + {poller_stat_failure, Pid, {SocketType, Host, Port, Time, Reason}} -> error_msg("received stat failure ~p from poller ~p after ~p " - "befor completion of test", [Reason, Pid, Time]), - exit({fail, {poller_failure, Pid, Reason}}); - - {poller_stat_failure, Pid, Reason} -> + "befor completion of test" + "~n SocketType: ~p" + "~n Host: ~p" + "~n Port: ~p", + [Reason, Pid, Time, SocketType, Host, Port]), + exit({fail, {poller_failure, Pid, Time, Reason}}); + + {poller_stat_failure, Pid, SocketType, Host, Port, Reason} -> error_msg("received stat failure ~p from poller ~p " - "befor completion of test", [Reason, Pid]), + "befor completion of test" + "~n SocketType: ~p" + "~n Host: ~p" + "~n Port: ~p", + [Reason, Pid, SocketType, Host, Port]), exit({fail, {poller_failure, Pid, Reason}}); Any -> @@ -250,16 +273,16 @@ is_poller(Pid, [_|Rest]) -> poller_main(Parent, SocketType, Host, Port) -> process_flag(trap_exit,true), - put(sname,poller), + put(sname, poller), case timer:tc(?MODULE, poller_loop, [SocketType, Host, Port, uris()]) of {Time, Count} when is_integer(Time) andalso is_integer(Count) -> Parent ! {poller_statistics, self(), {Time, Count}}; {Time, {'EXIT', Reason}} when is_integer(Time) -> - exit({poller_stat_failure, Time, Reason}); + exit({poller_stat_failure, SocketType, Host, Port, Time, Reason}); {Time, Other} when is_integer(Time) -> - Parent ! {poller_stat_failure, self(), {Time, Other}}; + Parent ! {poller_stat_failure, self(), {SocketType, Host, Port, Time, Other}}; Else -> - Parent ! {poller_stat_failure, self(), Else} + Parent ! {poller_stat_failure, self(), SocketType, Host, Port, Else} end. diff --git a/lib/inets/test/inets_sup_SUITE.erl b/lib/inets/test/inets_sup_SUITE.erl index ba41e0960c..1e701bc074 100644 --- a/lib/inets/test/inets_sup_SUITE.erl +++ b/lib/inets/test/inets_sup_SUITE.erl @@ -372,11 +372,11 @@ httpc_subtree(Config) when is_list(Config) -> "~n Config: ~p", [Config]), tsp("httpc_subtree -> start inets service httpc with profile foo"), - {ok, Foo} = inets:start(httpc, [{profile, foo}]), + {ok, _Foo} = inets:start(httpc, [{profile, foo}]), tsp("httpc_subtree -> " "start stand-alone inets service httpc with profile bar"), - {ok, Bar} = inets:start(httpc, [{profile, bar}], stand_alone), + {ok, _Bar} = inets:start(httpc, [{profile, bar}], stand_alone), tsp("httpc_subtree -> retreive list of httpc instances"), HttpcChildren = supervisor:which_children(httpc_profile_sup), diff --git a/lib/inets/test/inets_test_lib.erl b/lib/inets/test/inets_test_lib.erl index 6af2ad32f7..707b8c026a 100644 --- a/lib/inets/test/inets_test_lib.erl +++ b/lib/inets/test/inets_test_lib.erl @@ -1,28 +1,30 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2001-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% -module(inets_test_lib). -include("inets_test_lib.hrl"). +-include_lib("inets/src/http_lib/http_internal.hrl"). %% Various small utility functions --export([start_http_server/1, start_http_server_ssl/1]). +-export([start_http_server/1, start_http_server/2]). +-export([start_http_server_ssl/1, start_http_server_ssl/2]). -export([hostname/0]). -export([connect_bin/3, connect_byte/3, send/3, close/2]). -export([copy_file/3, copy_files/2, copy_dirs/2, del_dirs/1]). @@ -30,15 +32,99 @@ -export([check_body/1]). -export([millis/0, millis_diff/2, hours/1, minutes/1, seconds/1, sleep/1]). -export([non_pc_tc_maybe_skip/4, os_based_skip/1]). +-export([flush/0]). +-export([start_node/1, stop_node/1]). + +%% -- Misc node operation wrapper functions -- + +start_node(Name) -> + Pa = filename:dirname(code:which(?MODULE)), + Args = case init:get_argument('CC_TEST') of + {ok, [[]]} -> + " -pa /clearcase/otp/libraries/snmp/ebin "; + {ok, [[Path]]} -> + " -pa " ++ Path; + error -> + "" + end, + A = Args ++ " -pa " ++ Pa, + Opts = [{cleanup,false}, {args, A}], + case (catch test_server:start_node(Name, slave, Opts)) of + {ok, Node} -> + Node; + Else -> + exit({failed_starting_node, Name, Else}) + end. + +stop_node(Node) -> + rpc:cast(Node, erlang, halt, []), + await_stopped(Node, 5). + +await_stopped(_, 0) -> + ok; +await_stopped(Node, N) -> + Nodes = erlang:nodes(), + case lists:member(Node, Nodes) of + true -> + sleep(1000), + await_stopped(Node, N-1); + false -> + ok + end. + + +%% ---------------------------------------------------------------- +%% HTTPD starter functions +%% start_http_server(Conf) -> + start_http_server(Conf, ?HTTP_DEFAULT_SSL_KIND). + +start_http_server(Conf, essl = _SslTag) -> + application:start(crypto), + do_start_http_server(Conf); +start_http_server(Conf, _SslTag) -> + do_start_http_server(Conf). + +do_start_http_server(Conf) -> + tsp("start http server with " + "~n Conf: ~p" + "~n", [Conf]), application:load(inets), - ok = application:set_env(inets, services, [{httpd, Conf}]), - ok = application:start(inets). - + case application:set_env(inets, services, [{httpd, Conf}]) of + ok -> + case application:start(inets) of + ok -> + ok; + Error1 -> + test_server:format("<ERROR> Failed starting application: " + "~n Error: ~p" + "~n", [Error1]), + Error1 + end; + Error2 -> + test_server:format("<ERROR> Failed set application env: " + "~n Error: ~p" + "~n", [Error2]), + Error2 + end. + start_http_server_ssl(FileName) -> + start_http_server_ssl(FileName, ?HTTP_DEFAULT_SSL_KIND). + +start_http_server_ssl(FileName, essl = _SslTag) -> + application:start(crypto), + do_start_http_server_ssl(FileName); +start_http_server_ssl(FileName, _SslTag) -> + do_start_http_server_ssl(FileName). + +do_start_http_server_ssl(FileName) -> + tsp("start (ssl) http server with " + "~n FileName: ~p" + "~n", [FileName]), application:start(ssl), - catch start_http_server(FileName). + catch do_start_http_server(FileName). + %% ---------------------------------------------------------------------- %% print functions @@ -84,27 +170,17 @@ copy_files(FromDir, ToDir) -> copy_dirs(FromDirRoot, ToDirRoot) -> -%% io:format("~w:copy_dirs -> entry with" -%% "~n FromDirRoot: ~p" -%% "~n ToDirRoot: ~p" -%% "~n", [?MODULE, FromDirRoot, ToDirRoot]), {ok, Files} = file:list_dir(FromDirRoot), lists:foreach( fun(FileOrDir) -> %% Check if it's a directory or a file -%% io:format("~w:copy_dirs -> check ~p" -%% "~n", [?MODULE, FileOrDir]), case filelib:is_dir(filename:join(FromDirRoot, FileOrDir)) of true -> -%% io:format("~w:copy_dirs -> ~p is a directory" -%% "~n", [?MODULE, FileOrDir]), FromDir = filename:join([FromDirRoot, FileOrDir]), ToDir = filename:join([ToDirRoot, FileOrDir]), ok = file:make_dir(ToDir), copy_dirs(FromDir, ToDir); false -> -%% io:format("~w:copy_dirs -> ~p is a file" -%% "~n", [?MODULE, FileOrDir]), copy_file(FileOrDir, FromDirRoot, ToDirRoot) end end, Files). @@ -133,8 +209,8 @@ check_body(Body) -> 0 -> case string:rstr(Body, "</HTML>") of 0 -> - test_server:format("Body ~p~n", [Body]), - test_server:fail(did_not_receive_whole_body); + tsp("Body ~p", [Body]), + tsf(did_not_receive_whole_body); _ -> ok end; @@ -204,9 +280,31 @@ os_based_skip(_) -> %% Port -> integer() connect_bin(ssl, Host, Port) -> + connect(ssl, Host, Port, [binary, {packet,0}]); +connect_bin(ossl, Host, Port) -> + connect(ssl, Host, Port, [{ssl_imp, old}, binary, {packet,0}]); +connect_bin(essl, Host, Port) -> + connect(ssl, Host, Port, [{ssl_imp, new}, binary, {packet,0}, {reuseaddr, true}]); +connect_bin(ip_comm, Host, Port) -> + Opts = [inet6, binary, {packet,0}], + connect(ip_comm, Host, Port, Opts). + + +connect_byte(ssl, Host, Port) -> + connect(ssl, Host, Port, [{packet,0}]); +connect_byte(ossl, Host, Port) -> + connect(ssl, Host, Port, [{ssl_imp, old}, {packet,0}]); +connect_byte(essl, Host, Port) -> + connect(ssl, Host, Port, [{ssl_imp, new}, {packet,0}]); +connect_byte(ip_comm, Host, Port) -> + Opts = [inet6, {packet,0}], + connect(ip_comm, Host, Port, Opts). + + +connect(ssl, Host, Port, Opts) -> ssl:start(), %% Does not support ipv6 in old ssl - case ssl:connect(Host, Port, [binary, {packet,0}]) of + case ssl:connect(Host, Port, Opts) of {ok, Socket} -> {ok, Socket}; {error, Reason} -> @@ -214,61 +312,48 @@ connect_bin(ssl, Host, Port) -> Error -> Error end; -connect_bin(ip_comm, Host, Port) -> - Opts = [inet6, binary, {packet,0}], - connect(ip_comm, Host, Port, Opts). - - connect(ip_comm, Host, Port, Opts) -> - test_server:format("gen_tcp:connect(~p, ~p, ~p) ~n", [Host, Port, Opts]), case gen_tcp:connect(Host,Port, Opts) of {ok, Socket} -> - test_server:format("connect success~n", []), + %% tsp("connect success"), {ok, Socket}; {error, nxdomain} -> - test_server:format("nxdomain opts: ~p~n", [Opts]), + tsp("nxdomain opts: ~p", [Opts]), connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); {error, eafnosupport} -> - test_server:format("eafnosupport opts: ~p~n", [Opts]), + tsp("eafnosupport opts: ~p", [Opts]), connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); {error, {enfile,_}} -> - test_server:format("Error enfile~n", []), + tsp("Error enfile"), {error, enfile}; Error -> - test_server:format("Unexpected error: " - "~n Error: ~p" - "~nwhen" - "~n Host: ~p" - "~n Port: ~p" - "~n Opts: ~p" - "~n", [Error, Host, Port, Opts]), + tsp("Unexpected error: " + "~n Error: ~p" + "~nwhen" + "~n Host: ~p" + "~n Port: ~p" + "~n Opts: ~p" + "~n", [Error, Host, Port, Opts]), Error end. -connect_byte(ip_comm, Host, Port) -> - Opts = [inet6, {packet,0}], - connect(ip_comm, Host, Port, Opts); - -connect_byte(ssl, Host, Port) -> - ssl:start(), - %% Does not support ipv6 in old ssl - case ssl:connect(Host,Port,[{packet,0}]) of - {ok,Socket} -> - {ok,Socket}; - {error,{enfile,_}} -> - {error, enfile}; - Error -> - Error - end. send(ssl, Socket, Data) -> ssl:send(Socket, Data); +send(ossl, Socket, Data) -> + ssl:send(Socket, Data); +send(essl, Socket, Data) -> + ssl:send(Socket, Data); send(ip_comm,Socket,Data) -> gen_tcp:send(Socket,Data). close(ssl,Socket) -> catch ssl:close(Socket); +close(ossl,Socket) -> + catch ssl:close(Socket); +close(essl,Socket) -> + catch ssl:close(Socket); close(ip_comm,Socket) -> catch gen_tcp:close(Socket). @@ -300,3 +385,20 @@ sleep(MSecs) -> skip(Reason, File, Line) -> exit({skipped, {Reason, File, Line}}). + +flush() -> + receive + Msg -> + [Msg | flush()] + after 1000 -> + [] + end. + + +tsp(F) -> + tsp(F, []). +tsp(F, A) -> + test_server:format("~p ~p:" ++ F ++ "~n", [self(), ?MODULE | A]). + +tsf(Reason) -> + test_server:fail(Reason). diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk index ac20fa7bb7..57c87e7036 100644 --- a/lib/inets/vsn.mk +++ b/lib/inets/vsn.mk @@ -18,11 +18,16 @@ # %CopyrightEnd% APPLICATION = inets -INETS_VSN = 5.3.3 +INETS_VSN = 5.4 PRE_VSN = APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)" -TICKETS = OTP-8609 OTP-8610 OTP-8624 +TICKETS = OTP-7907 OTP-8564 OTP-8573 + +TICKETS_5_3_3 = \ + OTP-8609 \ + OTP-8610 \ + OTP-8624 TICKETS_5_3_2 = \ OTP-8542 \ diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml index 382262d1ee..a9ceac0bcf 100644 --- a/lib/kernel/doc/src/file.xml +++ b/lib/kernel/doc/src/file.xml @@ -603,7 +603,7 @@ f.txt: {person, "kalle", 25}. <type> <v>Filename = name()</v> <v>Modes = [Mode]</v> - <v> Mode = read | write | append | raw | binary | {delayed_write, Size, Delay} | delayed_write | {read_ahead, Size} | read_ahead | compressed</v> + <v> Mode = read | write | append | exclusive | raw | binary | {delayed_write, Size, Delay} | delayed_write | {read_ahead, Size} | read_ahead | compressed</v> <v> Size = Delay = int()</v> <v>IoDevice = io_device()</v> <v>Reason = ext_posix() | system_limit</v> @@ -630,6 +630,17 @@ f.txt: {person, "kalle", 25}. file opened with <c>append</c> will take place at the end of the file.</p> </item> + <tag><c>exclusive</c></tag> + <item> + <p>The file, when opened for writing, is created if it + does not exist. If the file exists, open will return + <c>{error, eexist}</c>.</p> + <warning><p>This option does not guarantee exclusiveness on + file systems that do not support O_EXCL properly, + such as NFS. Do not depend on this option unless you + know that the file system supports it (in general, local + file systems should be safe).</p></warning> + </item> <tag><c>raw</c></tag> <item> <p>The <c>raw</c> option allows faster access to a file, diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index 4f49371970..cfdd7045bd 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -84,7 +84,7 @@ -type mode() :: 'read' | 'write' | 'append' | 'raw' | 'binary' | {'delayed_write', non_neg_integer(), non_neg_integer()} | 'delayed_write' | {'read_ahead', pos_integer()} | - 'read_ahead' | 'compressed'. + 'read_ahead' | 'compressed' | 'exclusive'. -type name() :: string() | atom() | [name()]. -type posix() :: atom(). -type bindings() :: any(). diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl index 15bab0dccd..17c47f871d 100644 --- a/lib/kernel/test/file_SUITE.erl +++ b/lib/kernel/test/file_SUITE.erl @@ -53,7 +53,7 @@ -export([file_info/1, file_info_basic_file/1, file_info_basic_directory/1, file_info_bad/1, file_info_times/1, file_write_file_info/1]). -export([rename/1, access/1, truncate/1, datasync/1, sync/1, - read_write/1, pread_write/1, append/1]). + read_write/1, pread_write/1, append/1, exclusive/1]). -export([errors/1, e_delete/1, e_rename/1, e_make_dir/1, e_del_dir/1]). -export([otp_5814/1]). @@ -466,7 +466,7 @@ files(suite) -> sync,datasync,advise]. open(suite) -> [open1,old_modes,new_modes,path_open,close,access,read_write, - pread_write,append,open_errors]. + pread_write,append,open_errors,exclusive]. open1(suite) -> []; open1(doc) -> []; @@ -840,6 +840,22 @@ open_errors(Config) when is_list(Config) -> ?line test_server:timetrap_cancel(Dog), ok. +exclusive(suite) -> []; +exclusive(doc) -> "Test exclusive access to a file."; +exclusive(Config) when is_list(Config) -> + ?line Dog = test_server:timetrap(test_server:seconds(5)), + ?line RootDir = ?config(priv_dir,Config), + ?line NewDir = filename:join(RootDir, + atom_to_list(?MODULE) + ++"_exclusive"), + ?line ok = ?FILE_MODULE:make_dir(NewDir), + ?line Name = filename:join(NewDir, "ex_file.txt"), + ?line {ok, Fd} = ?FILE_MODULE:open(Name, [write, exclusive]), + ?line {error, eexist} = ?FILE_MODULE:open(Name, [write, exclusive]), + ?line ok = ?FILE_MODULE:close(Fd), + ?line test_server:timetrap_cancel(Dog), + ok. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% pos(suite) -> [pos1,pos2]. diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl index 21bdc06fdc..1688ec45ca 100644 --- a/lib/kernel/test/prim_file_SUITE.erl +++ b/lib/kernel/test/prim_file_SUITE.erl @@ -35,7 +35,7 @@ file_write_file_info_a/1, file_write_file_info_b/1]). -export([rename_a/1, rename_b/1, access/1, truncate/1, datasync/1, sync/1, - read_write/1, pread_write/1, append/1]). + read_write/1, pread_write/1, append/1, exclusive/1]). -export([errors/1, e_delete/1, e_rename/1, e_make_dir/1, e_del_dir/1]). -export([compression/1, read_not_really_compressed/1, @@ -385,7 +385,7 @@ win_cur_dir_1(_Config, Handle) -> files(suite) -> [open,pos,file_info,truncate,sync,datasync,advise]. open(suite) -> [open1,modes,close,access,read_write, - pread_write,append]. + pread_write,append,exclusive]. open1(suite) -> []; open1(doc) -> []; @@ -610,6 +610,22 @@ append(Config) when is_list(Config) -> ?line test_server:timetrap_cancel(Dog), ok. +exclusive(suite) -> []; +exclusive(doc) -> "Test exclusive access to a file."; +exclusive(Config) when is_list(Config) -> + ?line Dog = test_server:timetrap(test_server:seconds(5)), + ?line RootDir = ?config(priv_dir,Config), + ?line NewDir = filename:join(RootDir, + atom_to_list(?MODULE) + ++"_exclusive"), + ?line ok = ?PRIM_FILE:make_dir(NewDir), + ?line Name = filename:join(NewDir, "ex_file.txt"), + ?line {ok,Fd} = ?PRIM_FILE:open(Name, [write, exclusive]), + ?line {error, eexist} = ?PRIM_FILE:open(Name, [write, exclusive]), + ?line ok = ?PRIM_FILE:close(Fd), + ?line test_server:timetrap_cancel(Dog), + ok. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% pos(suite) -> [pos1,pos2]. diff --git a/lib/mnesia/examples/mnesia_meter.erl b/lib/mnesia/examples/mnesia_meter.erl index ea74d8691b..68094c4431 100644 --- a/lib/mnesia/examples/mnesia_meter.erl +++ b/lib/mnesia/examples/mnesia_meter.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -407,7 +407,7 @@ run(Nodes, Config, FunOverhead) -> stop(Nodes), Res. -run_meter(M, Nodes, FunOverhead) when record(M, meter) -> +run_meter(M, Nodes, FunOverhead) when is_record(M, meter) -> io:format(".", []), case catch init_records(M#meter.init, ?TIMES) of {atomic, ok} -> diff --git a/lib/public_key/doc/src/notes.xml b/lib/public_key/doc/src/notes.xml index 33a424f432..13a9151869 100644 --- a/lib/public_key/doc/src/notes.xml +++ b/lib/public_key/doc/src/notes.xml @@ -33,6 +33,35 @@ <rev>A</rev> <file>notes.xml</file> </header> + +<section><title>Public_Key 0.7</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Certificates without any extensions could not be handled + by public_key.</p> + <p> + Own Id: OTP-8626</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Code cleanup and minor bugfixes.</p> + <p> + Own Id: OTP-8649</p> + </item> + </list> + </section> + +</section> + <section><title>Public_Key 0.6</title> <section><title>Improvements and New Features</title> diff --git a/lib/public_key/src/public_key.appup.src b/lib/public_key/src/public_key.appup.src index 46e5ecca33..2eb5750923 100644 --- a/lib/public_key/src/public_key.appup.src +++ b/lib/public_key/src/public_key.appup.src @@ -1,39 +1,43 @@ %% -*- erlang -*- {"%VSN%", [ - {"0.5", + {"0.6", [ + {update, 'OTP-PUB-KEY', soft, soft_purge, soft_purge, []}, {update, public_key, soft, soft_purge, soft_purge, []}, - {update, pubkey_crypto, soft, soft_purge, soft_purge, []}, {update, pubkey_pem, soft, soft_purge, soft_purge, []}, + {update, pubkey_cert_records, soft, soft_purge, soft_purge, []} {update, pubkey_cert, soft, soft_purge, soft_purge, []} ] }, - {"0.4", + {"0.5", [ + {update, 'OTP-PUB-KEY', soft, soft_purge, soft_purge, []}, {update, public_key, soft, soft_purge, soft_purge, []}, - {update, pubkey_cert_records, soft, soft_purge, soft_purge, []}, {update, pubkey_crypto, soft, soft_purge, soft_purge, []}, {update, pubkey_pem, soft, soft_purge, soft_purge, []}, + {update, pubkey_cert_records, soft, soft_purge, soft_purge, []}, {update, pubkey_cert, soft, soft_purge, soft_purge, []} - ] + ] } ], [ - {"0.5", + {"0.6", [ + {update, 'OTP-PUB-KEY', soft, soft_purge, soft_purge, []}, {update, public_key, soft, soft_purge, soft_purge, []}, - {update, pubkey_crypto, soft, soft_purge, soft_purge, []}, {update, pubkey_pem, soft, soft_purge, soft_purge, []}, + {update, pubkey_cert_records, soft, soft_purge, soft_purge, []} {update, pubkey_cert, soft, soft_purge, soft_purge, []} ] }, - {"0.4", + {"0.5", [ + {update, 'OTP-PUB-KEY', soft, soft_purge, soft_purge, []}, {update, public_key, soft, soft_purge, soft_purge, []}, - {update, pubkey_cert_records, soft, soft_purge, soft_purge, []}, {update, pubkey_crypto, soft, soft_purge, soft_purge, []}, {update, pubkey_pem, soft, soft_purge, soft_purge, []}, + {update, pubkey_cert_records, soft, soft_purge, soft_purge, []}, {update, pubkey_cert, soft, soft_purge, soft_purge, []} ] } diff --git a/lib/public_key/test/pkey_test.erl b/lib/public_key/test/pkey_test.erl index 9d596eee4f..4cf20f0174 100644 --- a/lib/public_key/test/pkey_test.erl +++ b/lib/public_key/test/pkey_test.erl @@ -271,7 +271,7 @@ publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) -> #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}. validity(Opts) -> - DefFrom0 = date(), + DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1), DefTo0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())+7), {DefFrom, DefTo} = proplists:get_value(validity, Opts, {DefFrom0, DefTo0}), Format = fun({Y,M,D}) -> lists:flatten(io_lib:format("~w~2..0w~2..0w000000Z",[Y,M,D])) end, diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl index 6a3d6bfcf5..dc1015969a 100644 --- a/lib/public_key/test/public_key_SUITE.erl +++ b/lib/public_key/test/public_key_SUITE.erl @@ -320,12 +320,12 @@ pkix_path_validation(Config) when is_list(Config) -> {org_unit, "testing dep"} ]} ]), - ok = pkey_test:write_pem("/tmp", "cacert", CaK), + ok = pkey_test:write_pem("./", "public_key_cacert", CaK), CertK1 = {Cert1, _} = pkey_test:make_cert([{issuer, CaK}]), CertK2 = {Cert2,_} = pkey_test:make_cert([{issuer, CertK1}, {digest, md5}, {extensions, false}]), - ok = pkey_test:write_pem("/tmp", "cert", CertK2), - + ok = pkey_test:write_pem("./", "public_key_cert", CertK2), + {ok, _} = public_key:pkix_path_validation(Trusted, [Cert1], []), {error, {bad_cert,invalid_issuer}} = public_key:pkix_path_validation(Trusted, [Cert2], []), diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk index 8c4e4127b2..4b3071a85b 100644 --- a/lib/public_key/vsn.mk +++ b/lib/public_key/vsn.mk @@ -1,6 +1,6 @@ PUBLIC_KEY_VSN = 0.7 -TICKETS = OTP-8626 +TICKETS = OTP-8626 OTP-8649 #TICKETS_0.6 = OTP-7046 \ # OTP-8553 diff --git a/lib/ssl/doc/src/new_ssl.xml b/lib/ssl/doc/src/new_ssl.xml index 4ffaa9d96a..69298759bd 100644 --- a/lib/ssl/doc/src/new_ssl.xml +++ b/lib/ssl/doc/src/new_ssl.xml @@ -22,7 +22,6 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>ssl</title> <prepared>Ingela Anderton Andin</prepared> <responsible>Ingela Anderton Andin</responsible> @@ -83,7 +82,7 @@ meaningless pid.</item> <item>New API functions are ssl:shutdown/2, ssl:cipher_suites/[0,1] and - ssl:versions/0</item> + ssl:versions/0, ssl:renegotiate/1</item> <item>CRL and policy certificate extensions are not supported yet. </item> <item>Supported SSL/TLS-versions are SSL-3.0 and TLS-1.0 </item> @@ -408,6 +407,17 @@ end </desc> </func> + <func> + <name>format_error(Reason) -> string()</name> + <fsummary>Return an error string.</fsummary> + <type> + <v>Reason = term()</v> + </type> + <desc> + <p>Presents the error returned by an ssl function as a printable string.</p> + </desc> + </func> + <func> <name>getopts(Socket) -> </name> <name>getopts(Socket, OptionNames) -> diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml index 9d13427677..8028e94484 100644 --- a/lib/ssl/doc/src/notes.xml +++ b/lib/ssl/doc/src/notes.xml @@ -30,6 +30,73 @@ </header> <p>This document describes the changes made to the SSL application. </p> + + <section><title>SSL 3.11.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed handling of several ssl/tls packets arriving at the + same time. This was broken during a refactoring of the + code.</p> + <p> + Own Id: OTP-8679</p> + </item> + </list> + </section> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Added missing checks for padding and Mac value. Removed + code for export ciphers and DH certificates as we decided + not to support them.</p> + <p> + Own Id: OTP-7047</p> + </item> + <item> + <p> + New ssl will no longer return esslerrssl to be backwards + compatible with old ssl as this hids infomation from the + user. format_error/1 has been updated to support new ssl.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7049</p> + </item> + <item> + <p> + New ssl now supports secure renegotiation as described by + RFC 5746.</p> + <p> + Own Id: OTP-8568</p> + </item> + <item> + <p> + New ssl now support client/server-certificates signed by + dsa keys.</p> + <p> + Own Id: OTP-8587</p> + </item> + <item> + <p> + Alert handling has been improved to better handle + unexpected but valid messages and the implementation is + also changed to avoid timing related issues that could + cause different error messages depending on network + latency. Packet handling was sort of broken but would + mostly work as expected when socket was in binary mode. + This has now been fixed.</p> + <p> + Own Id: OTP-8588</p> + </item> + </list> + </section> + +</section> + <section><title>SSL 3.11</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl index 37d5646673..9aa31ae8a4 100644 --- a/lib/ssl/src/ssl_certificate.erl +++ b/lib/ssl/src/ssl_certificate.erl @@ -34,7 +34,13 @@ -export([trusted_cert_and_path/3, certificate_chain/2, file_to_certificats/1, - validate_extensions/6]). + validate_extensions/6, + is_valid_extkey_usage/2, + is_valid_key_usage/2, + select_extension/2, + extensions_list/1, + signature_type/1 + ]). %%==================================================================== %% Internal application API @@ -112,7 +118,28 @@ validate_extensions([Extension | Rest], ValidationState, UnknownExtensions, Verify, AccErr, Role) -> validate_extensions(Rest, ValidationState, [Extension | UnknownExtensions], Verify, AccErr, Role). - + +is_valid_key_usage(KeyUse, Use) -> + lists:member(Use, KeyUse). + + select_extension(_, []) -> + undefined; +select_extension(Id, [#'Extension'{extnID = Id} = Extension | _]) -> + Extension; +select_extension(Id, [_ | Extensions]) -> + select_extension(Id, Extensions). + +extensions_list(asn1_NOVALUE) -> + []; +extensions_list(Extensions) -> + Extensions. + +signature_type(RSA) when RSA == ?sha1WithRSAEncryption; + RSA == ?md5WithRSAEncryption -> + rsa; +signature_type(?'id-dsa-with-sha1') -> + dsa. + %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- @@ -188,9 +215,6 @@ is_valid_extkey_usage(KeyUse, server) -> %% Server wants to verify client is_valid_key_usage(KeyUse, ?'id-kp-clientAuth'). -is_valid_key_usage(KeyUse, Use) -> - lists:member(Use, KeyUse). - not_valid_extension(Error, true, _) -> throw(Error); not_valid_extension(Error, false, AccErrors) -> diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index f425886ce5..2a71df8ee1 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -30,11 +30,12 @@ -include("ssl_cipher.hrl"). -include("ssl_alert.hrl"). -include("ssl_debug.hrl"). +-include_lib("public_key/include/public_key.hrl"). -export([security_parameters/2, suite_definition/1, decipher/5, cipher/4, suite/1, suites/1, - openssl_suite/1, openssl_suite_name/1]). + openssl_suite/1, openssl_suite_name/1, filter/2]). -compile(inline). @@ -240,7 +241,7 @@ suite_definition(?TLS_RSA_WITH_3DES_EDE_CBC_SHA) -> suite_definition(?TLS_DHE_DSS_WITH_DES_CBC_SHA) -> {dhe_dss, des_cbc, sha}; suite_definition(?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA) -> - {dhe_dss, '3des_ede_cbc'}; + {dhe_dss, '3des_ede_cbc', sha}; suite_definition(?TLS_DHE_RSA_WITH_DES_CBC_SHA) -> {dhe_rsa, des_cbc, sha}; suite_definition(?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA) -> @@ -260,25 +261,6 @@ suite_definition(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA) -> suite_definition(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA) -> {dhe_rsa, aes_256_cbc, sha}. -%% TODO: support kerbos key exchange? -%% TSL V1.1 KRB SUITES -%% suite_definition(?TLS_KRB5_WITH_DES_CBC_SHA) -> -%% {krb5, des_cbc, sha}; -%% suite_definition(?TLS_KRB5_WITH_3DES_EDE_CBC_SHA) -> -%% {krb5, '3des_ede_cbc', sha}; -%% suite_definition(?TLS_KRB5_WITH_RC4_128_SHA) -> -%% {krb5, rc4_128, sha}; -%% suite_definition(?TLS_KRB5_WITH_IDEA_CBC_SHA) -> -%% {krb5, idea_cbc, sha}; -%% suite_definition(?TLS_KRB5_WITH_DES_CBC_MD5) -> -%% {krb5, des_cbc, md5}; -%% suite_definition(?TLS_KRB5_WITH_3DES_EDE_CBC_MD5) -> -%% {krb5, '3des_ede_cbc', md5}; -%% suite_definition(?TLS_KRB5_WITH_RC4_128_MD5) -> -%% {krb5, rc4_128, md5}; -%% suite_definition(?TLS_KRB5_WITH_IDEA_CBC_MD5) -> -%% {krb5, idea_cbc, md5}; - %% TLS v1.1 suites %%suite({rsa, null, md5}) -> %% ?TLS_RSA_WITH_NULL_MD5; @@ -312,8 +294,8 @@ suite({dhe_rsa, '3des_ede_cbc', sha}) -> %%% TSL V1.1 AES suites suite({rsa, aes_128_cbc, sha}) -> ?TLS_RSA_WITH_AES_128_CBC_SHA; -%% suite({dhe_dss, aes_128_cbc, sha}) -> -%% ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA; +suite({dhe_dss, aes_128_cbc, sha}) -> + ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA; suite({dhe_rsa, aes_128_cbc, sha}) -> ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA; %% suite({dh_anon, aes_128_cbc, sha}) -> @@ -327,29 +309,8 @@ suite({dhe_rsa, aes_256_cbc, sha}) -> %% suite({dh_anon, aes_256_cbc, sha}) -> %% ?TLS_DH_anon_WITH_AES_256_CBC_SHA. -%% TODO: support kerbos key exchange? -%% TSL V1.1 KRB SUITES -%% suite({krb5, des_cbc, sha}) -> -%% ?TLS_KRB5_WITH_DES_CBC_SHA; -%% suite({krb5_cbc, '3des_ede_cbc', sha}) -> -%% ?TLS_KRB5_WITH_3DES_EDE_CBC_SHA; -%% suite({krb5, rc4_128, sha}) -> -%% ?TLS_KRB5_WITH_RC4_128_SHA; -%% suite({krb5_cbc, idea_cbc, sha}) -> -%% ?TLS_KRB5_WITH_IDEA_CBC_SHA; -%% suite({krb5_cbc, md5}) -> -%% ?TLS_KRB5_WITH_DES_CBC_MD5; -%% suite({krb5_ede_cbc, des_cbc, md5}) -> -%% ?TLS_KRB5_WITH_3DES_EDE_CBC_MD5; -%% suite({krb5_128, rc4_128, md5}) -> -%% ?TLS_KRB5_WITH_RC4_128_MD5; -%% suite({krb5, idea_cbc, md5}) -> -%% ?TLS_KRB5_WITH_IDEA_CBC_MD5; %% translate constants <-> openssl-strings -%% TODO: Is there a pattern in the nameing -%% that is useable to make a nicer function defention? - openssl_suite("DHE-RSA-AES256-SHA") -> ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA; openssl_suite("DHE-DSS-AES256-SHA") -> @@ -368,17 +329,12 @@ openssl_suite("DHE-DSS-AES128-SHA") -> ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA; openssl_suite("AES128-SHA") -> ?TLS_RSA_WITH_AES_128_CBC_SHA; -%% TODO: Do we want to support this? -%% openssl_suite("DHE-DSS-RC4-SHA") -> -%% ?TLS_DHE_DSS_WITH_RC4_128_SHA; %%openssl_suite("IDEA-CBC-SHA") -> %% ?TLS_RSA_WITH_IDEA_CBC_SHA; openssl_suite("RC4-SHA") -> ?TLS_RSA_WITH_RC4_128_SHA; openssl_suite("RC4-MD5") -> ?TLS_RSA_WITH_RC4_128_MD5; -%% openssl_suite("DHE-DSS-RC4-SHA") -> -%% ?TLS_DHE_DSS_WITH_RC4_128_SHA; openssl_suite("EDH-RSA-DES-CBC-SHA") -> ?TLS_DHE_RSA_WITH_DES_CBC_SHA; openssl_suite("DES-CBC-SHA") -> @@ -412,14 +368,22 @@ openssl_suite_name(?TLS_DHE_RSA_WITH_DES_CBC_SHA) -> "EDH-RSA-DES-CBC-SHA"; openssl_suite_name(?TLS_RSA_WITH_DES_CBC_SHA) -> "DES-CBC-SHA"; - -%% openssl_suite_name(?TLS_DHE_DSS_WITH_RC4_128_SHA) -> -%% "DHE-DSS-RC4-SHA"; - %% No oppenssl name openssl_suite_name(Cipher) -> suite_definition(Cipher). +filter(undefined, Ciphers) -> + Ciphers; +filter(DerCert, Ciphers) -> + {ok, OtpCert} = public_key:pkix_decode_cert(DerCert, otp), + SigAlg = OtpCert#'OTPCertificate'.signatureAlgorithm, + case ssl_certificate:signature_type(SigAlg#'SignatureAlgorithm'.algorithm) of + rsa -> + filter_rsa(OtpCert, Ciphers -- dsa_signed_suites()); + dsa -> + Ciphers -- rsa_signed_suites() + end. + %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- @@ -567,3 +531,53 @@ next_iv(Bin, IV) -> <<_:FirstPart/binary, NextIV:IVSz/binary>> = Bin, NextIV. +rsa_signed_suites() -> + dhe_rsa_suites() ++ rsa_suites(). + +dhe_rsa_suites() -> + [?TLS_DHE_RSA_WITH_AES_256_CBC_SHA, + ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, + ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA, + ?TLS_DHE_RSA_WITH_DES_CBC_SHA]. + +rsa_suites() -> + [?TLS_RSA_WITH_AES_256_CBC_SHA, + ?TLS_RSA_WITH_3DES_EDE_CBC_SHA, + ?TLS_RSA_WITH_AES_128_CBC_SHA, + %%?TLS_RSA_WITH_IDEA_CBC_SHA, + ?TLS_RSA_WITH_RC4_128_SHA, + ?TLS_RSA_WITH_RC4_128_MD5, + ?TLS_RSA_WITH_DES_CBC_SHA]. + +dsa_signed_suites() -> + dhe_dss_suites(). + +dhe_dss_suites() -> + [?TLS_DHE_DSS_WITH_AES_256_CBC_SHA, + ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, + ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA, + ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA]. + +filter_rsa(OtpCert, RsaCiphers) -> + TBSCert = OtpCert#'OTPCertificate'.tbsCertificate, + TBSExtensions = TBSCert#'OTPTBSCertificate'.extensions, + Extensions = ssl_certificate:extensions_list(TBSExtensions), + case ssl_certificate:select_extension(?'id-ce-keyUsage', Extensions) of + undefined -> + RsaCiphers; + #'Extension'{extnValue = KeyUse} -> + Result = filter_rsa_suites(keyEncipherment, + KeyUse, RsaCiphers, rsa_suites()), + filter_rsa_suites(digitalSignature, + KeyUse, Result, dhe_rsa_suites()) + end. + +filter_rsa_suites(Use, KeyUse, CipherSuits, RsaSuites) -> + case ssl_certificate:is_valid_key_usage(KeyUse, Use) of + true -> + CipherSuits; + false -> + CipherSuits -- RsaSuites + end. + + diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 644c2772b2..abd1b59011 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -65,13 +65,14 @@ ssl_options, % #ssl_options{} socket_options, % #socket_options{} connection_states, % #connection_states{} from ssl_record.hrl + tls_packets = [], % Not yet handled decode ssl/tls packets. tls_record_buffer, % binary() buffer of incomplete records tls_handshake_buffer, % binary() buffer of incomplete handshakes %% {{md5_hash, sha_hash}, {prev_md5, prev_sha}} (binary()) tls_handshake_hashes, % see above tls_cipher_texts, % list() received but not deciphered yet own_cert, % binary() - session, % #session{} from ssl_handshake.erl + session, % #session{} from ssl_handshake.hrl session_cache, % session_cache_cb, % negotiated_version, % #protocol_version{} @@ -280,12 +281,12 @@ start_link(Role, Host, Port, Socket, Options, User, CbInfo) -> %% gen_fsm:start_link/3,4, this function is called by the new process to %% initialize. %%-------------------------------------------------------------------- -init([Role, Host, Port, Socket, {SSLOpts, _} = Options, +init([Role, Host, Port, Socket, {SSLOpts0, _} = Options, User, CbInfo]) -> State0 = initial_state(Role, Host, Port, Socket, Options, User, CbInfo), Hashes0 = ssl_handshake:init_hashes(), - try ssl_init(SSLOpts, Role) of + try ssl_init(SSLOpts0, Role) of {ok, Ref, CacheRef, OwnCert, Key, DHParams} -> State = State0#state{tls_handshake_hashes = Hashes0, own_cert = OwnCert, @@ -317,10 +318,14 @@ hello(start, #state{host = Host, port = Port, role = client, ssl_options = SslOpts, transport_cb = Transport, socket = Socket, connection_states = ConnectionStates, + own_cert = Cert, renegotiation = {Renegotiation, _}} = State0) -> + Hello = ssl_handshake:client_hello(Host, Port, - ConnectionStates, SslOpts, Renegotiation), + ConnectionStates, + SslOpts, Cert, + Renegotiation), Version = Hello#client_hello.client_version, Hashes0 = ssl_handshake:init_hashes(), @@ -401,10 +406,11 @@ hello(Hello = #client_hello{client_version = ClientVersion}, renegotiation = {Renegotiation, _}, session_cache = Cache, session_cache_cb = CacheCb, - ssl_options = SslOpts}) -> + ssl_options = SslOpts, + own_cert = Cert}) -> case ssl_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb, - ConnectionStates0}, Renegotiation) of + ConnectionStates0, Cert}, Renegotiation) of {Version, {Type, Session}, ConnectionStates} -> do_server_hello(Type, State#state{connection_states = ConnectionStates, @@ -700,13 +706,14 @@ connection(#hello_request{}, #state{host = Host, port = Port, socket = Socket, ssl_options = SslOpts, negotiated_version = Version, + own_cert = Cert, transport_cb = Transport, connection_states = ConnectionStates0, renegotiation = {Renegotiation, _}, tls_handshake_hashes = Hashes0} = State0) -> Hello = ssl_handshake:client_hello(Host, Port, - ConnectionStates0, SslOpts, Renegotiation), + ConnectionStates0, SslOpts, Cert, Renegotiation), {BinMsg, ConnectionStates1, Hashes1} = encode_handshake(Hello, Version, ConnectionStates0, Hashes0), @@ -1485,15 +1492,15 @@ handle_server_key( SecParams = ConnectionState#connection_state.security_parameters, #security_parameters{client_random = ClientRandom, server_random = ServerRandom} = SecParams, - Hash = ssl_handshake:server_key_exchange_hash(KeyAlgo, - <<ClientRandom/binary, + Plain = ssl_handshake:server_key_exchange_plain(KeyAlgo, + <<ClientRandom/binary, ServerRandom/binary, - ?UINT16(PLen), P/binary, - ?UINT16(GLen), G/binary, - ?UINT16(YLen), + ?UINT16(PLen), P/binary, + ?UINT16(GLen), G/binary, + ?UINT16(YLen), ServerPublicDhKey/binary>>), - - case verify_dh_params(Signed, Hash, PubKeyInfo) of + + case verify_dh_params(Signed, Plain, PubKeyInfo) of true -> PMpint = mpint_binary(P), GMpint = mpint_binary(G), @@ -1517,14 +1524,18 @@ handle_server_key( ?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE) end. -verify_dh_params(Signed, Hash, {?rsaEncryption, PubKey, _PubKeyparams}) -> + +verify_dh_params(Signed, Hashes, {?rsaEncryption, PubKey, _PubKeyParams}) -> case public_key:decrypt_public(Signed, PubKey, [{rsa_pad, rsa_pkcs1_padding}]) of - Hash -> + Hashes -> true; _ -> false - end. + end; +verify_dh_params(Signed, Plain, {?'id-dsa', PublicKey, PublicKeyParams}) -> + public_key:verify_signature(Plain, sha, Signed, PublicKey, PublicKeyParams). + encode_alert(#alert{} = Alert, Version, ConnectionStates) -> ?DBG_TERM(Alert), @@ -1727,9 +1738,23 @@ opposite_role(server) -> send_user(Pid, Msg) -> Pid ! Msg. +handle_tls_handshake(Handle, StateName, #state{tls_packets = [Packet]} = State) -> + FsmReturn = {next_state, StateName, State#state{tls_packets = []}}, + Handle(Packet, FsmReturn); + +handle_tls_handshake(Handle, StateName, #state{tls_packets = [Packet | Packets]} = State0) -> + FsmReturn = {next_state, StateName, State0#state{tls_packets = Packets}}, + case Handle(Packet, FsmReturn) of + {next_state, NextStateName, State} -> + handle_tls_handshake(Handle, NextStateName, State); + {stop, _,_} = Stop -> + Stop + end. + next_state(_, #alert{} = Alert, #state{negotiated_version = Version} = State) -> handle_own_alert(Alert, Version, decipher_error, State), {stop, normal, State}; + next_state(Next, no_record, State) -> {next_state, Next, State}; @@ -1764,8 +1789,8 @@ next_state(StateName, #ssl_tls{type = ?HANDSHAKE, fragment = Data}, end, try {Packets, Buf} = ssl_handshake:get_tls_handshake(Data,Buf0, KeyAlg,Version), - Start = {next_state, StateName, State0#state{tls_handshake_buffer = Buf}}, - lists:foldl(Handle, Start, Packets) + State = State0#state{tls_packets = Packets, tls_handshake_buffer = Buf}, + handle_tls_handshake(Handle, StateName, State) catch throw:#alert{} = Alert -> handle_own_alert(Alert, Version, StateName, State0), {stop, normal, State0} @@ -1802,17 +1827,19 @@ next_tls_record(Data, #state{tls_record_buffer = Buf0, Alert end. -next_record(#state{tls_cipher_texts = [], socket = Socket} = State) -> +next_record(#state{tls_packets = [], tls_cipher_texts = [], socket = Socket} = State) -> inet:setopts(Socket, [{active,once}]), {no_record, State}; -next_record(#state{tls_cipher_texts = [CT | Rest], +next_record(#state{tls_packets = [], tls_cipher_texts = [CT | Rest], connection_states = ConnStates0} = State) -> case ssl_record:decode_cipher_text(CT, ConnStates0) of {Plain, ConnStates} -> {Plain, State#state{tls_cipher_texts = Rest, connection_states = ConnStates}}; #alert{} = Alert -> {Alert, State} - end. + end; +next_record(State) -> + {no_record, State}. next_record_if_active(State = #state{socket_options = diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 454d726f0d..c8245e2fb4 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -31,11 +31,11 @@ -include("ssl_debug.hrl"). -include_lib("public_key/include/public_key.hrl"). --export([master_secret/4, client_hello/5, server_hello/4, hello/4, +-export([master_secret/4, client_hello/6, server_hello/4, hello/4, hello_request/0, certify/7, certificate/3, client_certificate_verify/6, certificate_verify/6, certificate_request/2, - key_exchange/2, server_key_exchange_hash/2, finished/4, + key_exchange/2, server_key_exchange_plain/2, finished/4, verify_connection/5, get_tls_handshake/4, server_hello_done/0, sig_alg/1, @@ -46,7 +46,7 @@ %% Internal application API %%==================================================================== %%-------------------------------------------------------------------- -%% Function: client_hello(Host, Port, ConnectionStates, SslOpts) -> +%% Function: client_hello(Host, Port, ConnectionStates, SslOpts, Cert, Renegotiation) -> %% #client_hello{} %% Host %% Port @@ -56,8 +56,8 @@ %% Description: Creates a client hello message. %%-------------------------------------------------------------------- client_hello(Host, Port, ConnectionStates, #ssl_options{versions = Versions, - ciphers = Ciphers} - = SslOpts, Renegotiation) -> + ciphers = UserSuites} + = SslOpts, Cert, Renegotiation) -> Fun = fun(Version) -> ssl_record:protocol_version(Version) @@ -65,7 +65,8 @@ client_hello(Host, Port, ConnectionStates, #ssl_options{versions = Versions, Version = ssl_record:highest_protocol_version(lists:map(Fun, Versions)), Pending = ssl_record:pending_connection_state(ConnectionStates, read), SecParams = Pending#connection_state.security_parameters, - + Ciphers = available_suites(Cert, UserSuites, Version), + Id = ssl_manager:client_session_id(Host, Port, SslOpts), #client_hello{session_id = Id, @@ -150,14 +151,14 @@ hello(#client_hello{client_version = ClientVersion, random = Random, renegotiation_info = Info} = Hello, #ssl_options{versions = Versions, secure_renegotiate = SecureRenegotation} = SslOpts, - {Port, Session0, Cache, CacheCb, ConnectionStates0}, Renegotiation) -> + {Port, Session0, Cache, CacheCb, ConnectionStates0, Cert}, Renegotiation) -> Version = select_version(ClientVersion, Versions), case ssl_record:is_acceptable_version(Version) of true -> {Type, #session{cipher_suite = CipherSuite, compression_method = Compression} = Session} = select_session(Hello, Port, Session0, Version, - SslOpts, Cache, CacheCb), + SslOpts, Cache, CacheCb, Cert), case CipherSuite of no_suite -> ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY); @@ -316,8 +317,12 @@ certificate_verify(Signature, {_, PublicKey, _}, Version, valid; _ -> ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE) - end. -%% TODO dsa clause + end; +certificate_verify(Signature, {_, PublicKey, PublicKeyParams}, Version, + MasterSecret, dhe_dss = Algorithm, {_, Hashes0}) -> + Hashes = calc_certificate_verify(Version, MasterSecret, + Algorithm, Hashes0), + public_key:verify_signature(Hashes, sha, Signature, PublicKey, PublicKeyParams). %%-------------------------------------------------------------------- %% Function: certificate_request(ConnectionStates, CertDbRef) -> @@ -356,7 +361,7 @@ key_exchange(client, {dh, <<?UINT32(Len), PublicKey:Len/binary>>}) -> dh_public = PublicKey} }; -key_exchange(server, {dh, {<<?UINT32(_), PublicKey/binary>>, _}, +key_exchange(server, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _}, #'DHParameter'{prime = P, base = G}, KeyAlgo, ClientRandom, ServerRandom, PrivateKey}) -> <<?UINT32(_), PBin/binary>> = crypto:mpint(P), @@ -365,15 +370,14 @@ key_exchange(server, {dh, {<<?UINT32(_), PublicKey/binary>>, _}, GLen = byte_size(GBin), YLen = byte_size(PublicKey), ServerDHParams = #server_dh_params{dh_p = PBin, - dh_g = GBin, dh_y = PublicKey}, - - Hash = - server_key_exchange_hash(KeyAlgo, <<ClientRandom/binary, - ServerRandom/binary, - ?UINT16(PLen), PBin/binary, - ?UINT16(GLen), GBin/binary, - ?UINT16(YLen), PublicKey/binary>>), - Signed = digitally_signed(Hash, PrivateKey), + dh_g = GBin, dh_y = PublicKey}, + Plain = + server_key_exchange_plain(KeyAlgo, <<ClientRandom/binary, + ServerRandom/binary, + ?UINT16(PLen), PBin/binary, + ?UINT16(GLen), GBin/binary, + ?UINT16(YLen), PublicKey/binary>>), + Signed = digitally_signed(Plain, PrivateKey), #server_key_exchange{params = ServerDHParams, signed_params = Signed}. @@ -524,18 +528,12 @@ path_validation_alert(_, _) -> ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE). select_session(Hello, Port, Session, Version, - #ssl_options{ciphers = UserSuites} = SslOpts, Cache, CacheCb) -> + #ssl_options{ciphers = UserSuites} = SslOpts, Cache, CacheCb, Cert) -> SuggestedSessionId = Hello#client_hello.session_id, SessionId = ssl_manager:server_session_id(Port, SuggestedSessionId, SslOpts), - Suites = case UserSuites of - [] -> - ssl_cipher:suites(Version); - _ -> - UserSuites - end, - + Suites = available_suites(Cert, UserSuites, Version), case ssl_session:is_new(SuggestedSessionId, SessionId) of true -> CipherSuite = @@ -549,7 +547,14 @@ select_session(Hello, Port, Session, Version, {resumed, CacheCb:lookup(Cache, {Port, SessionId})} end. - +available_suites(Cert, UserSuites, Version) -> + case UserSuites of + [] -> + ssl_cipher:filter(Cert, ssl_cipher:suites(Version)); + _ -> + ssl_cipher:filter(Cert, UserSuites) + end. + cipher_suites(Suites, false) -> [?TLS_EMPTY_RENEGOTIATION_INFO_SCSV | Suites]; cipher_suites(Suites, true) -> @@ -812,7 +817,7 @@ dec_hs(?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>, _, _) -> dec_hs(?SERVER_KEY_EXCHANGE, <<?UINT16(PLen), P:PLen/binary, ?UINT16(GLen), G:GLen/binary, ?UINT16(YLen), Y:YLen/binary, - ?UINT16(_), Sig/binary>>, + ?UINT16(Len), Sig:Len/binary>>, ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) -> #server_key_exchange{params = #server_dh_params{dh_p = P,dh_g = G, dh_y = Y}, @@ -820,7 +825,6 @@ dec_hs(?SERVER_KEY_EXCHANGE, <<?UINT16(PLen), P:PLen/binary, dec_hs(?CERTIFICATE_REQUEST, <<?BYTE(CertTypesLen), CertTypes:CertTypesLen/binary, ?UINT16(CertAuthsLen), CertAuths:CertAuthsLen/binary>>, _, _) -> - %% TODO: maybe we should chop up CertAuths into a list? #certificate_request{certificate_types = CertTypes, certificate_authorities = CertAuths}; dec_hs(?SERVER_HELLO_DONE, <<>>, _, _) -> @@ -1086,9 +1090,8 @@ certificate_authorities_from_db(CertDbRef, PrevKey, Acc) -> digitally_signed(Hashes, #'RSAPrivateKey'{} = Key) -> public_key:encrypt_private(Hashes, Key, [{rsa_pad, rsa_pkcs1_padding}]); -digitally_signed(Hashes, #'DSAPrivateKey'{} = Key) -> - public_key:sign(Hashes, Key). - +digitally_signed(Plain, #'DSAPrivateKey'{} = Key) -> + public_key:sign(Plain, Key). calc_master_secret({3,0}, PremasterSecret, ClientRandom, ServerRandom) -> ssl_ssl3:master_secret(PremasterSecret, ClientRandom, ServerRandom); @@ -1119,23 +1122,15 @@ calc_certificate_verify({3, N}, _, Algorithm, Hashes) when N == 1; N == 2 -> ssl_tls1:certificate_verify(Algorithm, Hashes). -server_key_exchange_hash(Algorithm, Value) when Algorithm == rsa; +server_key_exchange_plain(Algorithm, Value) when Algorithm == rsa; Algorithm == dhe_rsa -> - MD5Context = crypto:md5_init(), - NewMD5Context = crypto:md5_update(MD5Context, Value), - MD5 = crypto:md5_final(NewMD5Context), - - SHAContext = crypto:sha_init(), - NewSHAContext = crypto:sha_update(SHAContext, Value), - SHA = crypto:sha_final(NewSHAContext), - + MD5 = crypto:md5(Value), + SHA = crypto:sha(Value), <<MD5/binary, SHA/binary>>; -server_key_exchange_hash(dhe_dss, Value) -> - SHAContext = crypto:sha_init(), - NewSHAContext = crypto:sha_update(SHAContext, Value), - crypto:sha_final(NewSHAContext). - +server_key_exchange_plain(dhe_dss, Value) -> + %% Hash will be done by crypto. + Value. sig_alg(dh_anon) -> ?SIGNATURE_ANONYMOUS; diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl index 7c4b0ee959..6b7cffaa7d 100644 --- a/lib/ssl/src/ssl_record.erl +++ b/lib/ssl/src/ssl_record.erl @@ -705,7 +705,6 @@ hash_and_bump_seqno(#connection_state{sequence_number = SeqNo, is_correct_mac(Mac, Mac) -> true; is_correct_mac(_M,_H) -> - io:format("Mac ~p ~n Hash: ~p~n",[_M, _H]), false. mac_hash({_,_}, ?NULL, _MacSecret, _SeqNo, _Type, diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl index 1bf8c2b458..1cecd10e81 100644 --- a/lib/ssl/src/ssl_ssl3.erl +++ b/lib/ssl/src/ssl_ssl3.erl @@ -138,21 +138,18 @@ setup_keys(MasterSecret, ServerRandom, ClientRandom, HS, KML, _EKML, IVS) -> suites() -> [ - %% TODO: uncomment when supported ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA, - %% ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA, + ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA, ?TLS_RSA_WITH_AES_256_CBC_SHA, ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, - %% ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, + ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, ?TLS_RSA_WITH_3DES_EDE_CBC_SHA, ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA, - %% ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA, + ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA, ?TLS_RSA_WITH_AES_128_CBC_SHA, - %%?TLS_DHE_DSS_WITH_RC4_128_SHA, - %% ?TLS_RSA_WITH_IDEA_CBC_SHA, Not supported: in later openssl version than OTP requires + %% ?TLS_RSA_WITH_IDEA_CBC_SHA, ?TLS_RSA_WITH_RC4_128_SHA, ?TLS_RSA_WITH_RC4_128_MD5, - %%?TLS_DHE_DSS_WITH_RC4_128_SHA, ?TLS_RSA_WITH_DES_CBC_SHA ]. diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl index 900b8e166d..70db632835 100644 --- a/lib/ssl/src/ssl_tls1.erl +++ b/lib/ssl/src/ssl_tls1.erl @@ -134,22 +134,19 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor}, suites() -> [ - %% TODO: uncomment when supported ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA, - %%?TLS_DHE_DSS_WITH_AES_256_CBC_SHA, + ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA, ?TLS_RSA_WITH_AES_256_CBC_SHA, ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, - %%?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, + ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, ?TLS_RSA_WITH_3DES_EDE_CBC_SHA, ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA, - %%?TLS_DHE_DSS_WITH_AES_128_CBC_SHA, + ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA, ?TLS_RSA_WITH_AES_128_CBC_SHA, - %%?TLS_DHE_DSS_WITH_RC4_128_SHA, %%?TLS_RSA_WITH_IDEA_CBC_SHA, ?TLS_RSA_WITH_RC4_128_SHA, ?TLS_RSA_WITH_RC4_128_MD5, ?TLS_DHE_RSA_WITH_DES_CBC_SHA, - %%TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA ?TLS_RSA_WITH_DES_CBC_SHA ]. diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile index bd86120c98..d35cafc47b 100644 --- a/lib/ssl/test/Makefile +++ b/lib/ssl/test/Makefile @@ -1,19 +1,19 @@ # # %CopyrightBegin% -# -# Copyright Ericsson AB 1999-2009. All Rights Reserved. -# +# +# Copyright Ericsson AB 1999-2010. All Rights Reserved. +# # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in # compliance with the License. You should have received a copy of the # Erlang Public License along with this software. If not, it can be # retrieved online at http://www.erlang.org/. -# +# # Software distributed under the License is distributed on an "AS IS" # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See # the License for the specific language governing rights and limitations # under the License. -# +# # %CopyrightEnd% # @@ -50,7 +50,8 @@ MODULES = \ old_ssl_protocol_SUITE \ old_transport_accept_SUITE \ old_ssl_dist_SUITE \ - make_certs + make_certs\ + erl_make_certs ERL_FILES = $(MODULES:%=%.erl) diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl new file mode 100644 index 0000000000..1d2cea6c72 --- /dev/null +++ b/lib/ssl/test/erl_make_certs.erl @@ -0,0 +1,412 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% Create test certificates + +-module(erl_make_certs). +-include_lib("public_key/include/public_key.hrl"). + +-export([make_cert/1, gen_rsa/1, verify_signature/3, write_pem/3]). +-compile(export_all). + +%%-------------------------------------------------------------------- +%% @doc Create and return a der encoded certificate +%% Option Default +%% ------------------------------------------------------- +%% digest sha1 +%% validity {date(), date() + week()} +%% version 3 +%% subject [] list of the following content +%% {name, Name} +%% {email, Email} +%% {city, City} +%% {state, State} +%% {org, Org} +%% {org_unit, OrgUnit} +%% {country, Country} +%% {serial, Serial} +%% {title, Title} +%% {dnQualifer, DnQ} +%% issuer = {Issuer, IssuerKey} true (i.e. a ca cert is created) +%% (obs IssuerKey migth be {Key, Password} +%% key = KeyFile|KeyBin|rsa|dsa Subject PublicKey rsa or dsa generates key +%% +%% +%% (OBS: The generated keys are for testing only) +%% @spec ([{::atom(), ::term()}]) -> {Cert::binary(), Key::binary()} +%% @end +%%-------------------------------------------------------------------- + +make_cert(Opts) -> + SubjectPrivateKey = get_key(Opts), + {TBSCert, IssuerKey} = make_tbs(SubjectPrivateKey, Opts), + Cert = public_key:sign(TBSCert, IssuerKey), + true = verify_signature(Cert, IssuerKey, undef), %% verify that the keys where ok + {Cert, encode_key(SubjectPrivateKey)}. + +%%-------------------------------------------------------------------- +%% @doc Writes pem files in Dir with FileName ++ ".pem" and FileName ++ "_key.pem" +%% @spec (::string(), ::string(), {Cert,Key}) -> ok +%% @end +%%-------------------------------------------------------------------- +write_pem(Dir, FileName, {Cert, Key = {_,_,not_encrypted}}) when is_binary(Cert) -> + ok = public_key:der_to_pem(filename:join(Dir, FileName ++ ".pem"), [{cert, Cert, not_encrypted}]), + ok = public_key:der_to_pem(filename:join(Dir, FileName ++ "_key.pem"), [Key]). + +%%-------------------------------------------------------------------- +%% @doc Creates a rsa key (OBS: for testing only) +%% the size are in bytes +%% @spec (::integer()) -> {::atom(), ::binary(), ::opaque()} +%% @end +%%-------------------------------------------------------------------- +gen_rsa(Size) when is_integer(Size) -> + Key = gen_rsa2(Size), + {Key, encode_key(Key)}. + +%%-------------------------------------------------------------------- +%% @doc Creates a dsa key (OBS: for testing only) +%% the sizes are in bytes +%% @spec (::integer()) -> {::atom(), ::binary(), ::opaque()} +%% @end +%%-------------------------------------------------------------------- +gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) -> + Key = gen_dsa2(LSize, NSize), + {Key, encode_key(Key)}. + +%%-------------------------------------------------------------------- +%% @doc Verifies cert signatures +%% @spec (::binary(), ::tuple()) -> ::boolean() +%% @end +%%-------------------------------------------------------------------- +verify_signature(DerEncodedCert, DerKey, KeyParams) -> + Key = decode_key(DerKey), + case Key of + #'RSAPrivateKey'{modulus=Mod, publicExponent=Exp} -> + public_key:verify_signature(DerEncodedCert, + #'RSAPublicKey'{modulus=Mod, publicExponent=Exp}, + 'NULL'); + #'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} -> + public_key:verify_signature(DerEncodedCert, Y, #'Dss-Parms'{p=P, q=Q, g=G}); + + _ -> + public_key:verify_signature(DerEncodedCert, Key, KeyParams) + end. + +%%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +get_key(Opts) -> + case proplists:get_value(key, Opts) of + undefined -> make_key(rsa, Opts); + rsa -> make_key(rsa, Opts); + dsa -> make_key(dsa, Opts); + Key -> + Password = proplists:get_value(password, Opts, no_passwd), + decode_key(Key, Password) + end. + +decode_key({Key, Pw}) -> + decode_key(Key, Pw); +decode_key(Key) -> + decode_key(Key, no_passwd). + + +decode_key(#'RSAPublicKey'{} = Key,_) -> + Key; +decode_key(#'RSAPrivateKey'{} = Key,_) -> + Key; +decode_key(#'DSAPrivateKey'{} = Key,_) -> + Key; +decode_key(Der = {_,_,_}, Pw) -> + {ok, Key} = public_key:decode_private_key(Der, Pw), + Key; +decode_key(FileOrDer, Pw) -> + {ok, [KeyInfo]} = public_key:pem_to_der(FileOrDer), + decode_key(KeyInfo, Pw). + +encode_key(Key = #'RSAPrivateKey'{}) -> + {ok, Der} = 'OTP-PUB-KEY':encode('RSAPrivateKey', Key), + {rsa_private_key, list_to_binary(Der), not_encrypted}; +encode_key(Key = #'DSAPrivateKey'{}) -> + {ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key), + {dsa_private_key, list_to_binary(Der), not_encrypted}. + +make_tbs(SubjectKey, Opts) -> + Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))), + {Issuer, IssuerKey} = issuer(Opts, SubjectKey), + + {Algo, Parameters} = sign_algorithm(IssuerKey, Opts), + + SignAlgo = #'SignatureAlgorithm'{algorithm = Algo, + parameters = Parameters}, + + {#'OTPTBSCertificate'{serialNumber = trunc(random:uniform()*100000000)*10000 + 1, + signature = SignAlgo, + issuer = Issuer, + validity = validity(Opts), + subject = subject(proplists:get_value(subject, Opts),false), + subjectPublicKeyInfo = publickey(SubjectKey), + version = Version, + extensions = extensions(Opts) + }, IssuerKey}. + +issuer(Opts, SubjectKey) -> + IssuerProp = proplists:get_value(issuer, Opts, true), + case IssuerProp of + true -> %% Self signed + {subject(proplists:get_value(subject, Opts), true), SubjectKey}; + {Issuer, IssuerKey} when is_binary(Issuer) -> + {issuer_der(Issuer), decode_key(IssuerKey)}; + {File, IssuerKey} when is_list(File) -> + {ok, [{cert, Cert, _}|_]} = public_key:pem_to_der(File), + {issuer_der(Cert), decode_key(IssuerKey)} + end. + +issuer_der(Issuer) -> + {ok, Decoded} = public_key:pkix_decode_cert(Issuer, otp), + #'OTPCertificate'{tbsCertificate=Tbs} = Decoded, + #'OTPTBSCertificate'{subject=Subject} = Tbs, + Subject. + +subject(undefined, IsCA) -> + User = if IsCA -> "CA"; true -> os:getenv("USER") end, + Opts = [{email, User ++ "@erlang.org"}, + {name, User}, + {city, "Stockholm"}, + {country, "SE"}, + {org, "erlang"}, + {org_unit, "testing dep"}], + subject(Opts); +subject(Opts, _) -> + subject(Opts). + +subject(SubjectOpts) when is_list(SubjectOpts) -> + Encode = fun(Opt) -> + {Type,Value} = subject_enc(Opt), + [#'AttributeTypeAndValue'{type=Type, value=Value}] + end, + {rdnSequence, [Encode(Opt) || Opt <- SubjectOpts]}. + +%% Fill in the blanks +subject_enc({name, Name}) -> {?'id-at-commonName', {printableString, Name}}; +subject_enc({email, Email}) -> {?'id-emailAddress', Email}; +subject_enc({city, City}) -> {?'id-at-localityName', {printableString, City}}; +subject_enc({state, State}) -> {?'id-at-stateOrProvinceName', {printableString, State}}; +subject_enc({org, Org}) -> {?'id-at-organizationName', {printableString, Org}}; +subject_enc({org_unit, OrgUnit}) -> {?'id-at-organizationalUnitName', {printableString, OrgUnit}}; +subject_enc({country, Country}) -> {?'id-at-countryName', Country}; +subject_enc({serial, Serial}) -> {?'id-at-serialNumber', Serial}; +subject_enc({title, Title}) -> {?'id-at-title', {printableString, Title}}; +subject_enc({dnQualifer, DnQ}) -> {?'id-at-dnQualifier', DnQ}; +subject_enc(Other) -> Other. + + +extensions(Opts) -> + case proplists:get_value(extensions, Opts, []) of + false -> + asn1_NOVALUE; + Exts -> + lists:flatten([extension(Ext) || Ext <- default_extensions(Exts)]) + end. + +default_extensions(Exts) -> + Def = [{key_usage,undefined}, + {subject_altname, undefined}, + {issuer_altname, undefined}, + {basic_constraints, default}, + {name_constraints, undefined}, + {policy_constraints, undefined}, + {ext_key_usage, undefined}, + {inhibit_any, undefined}, + {auth_key_id, undefined}, + {subject_key_id, undefined}, + {policy_mapping, undefined}], + Filter = fun({Key, _}, D) -> lists:keydelete(Key, 1, D) end, + Exts ++ lists:foldl(Filter, Def, Exts). + +extension({_, undefined}) -> []; +extension({basic_constraints, Data}) -> + case Data of + default -> + #'Extension'{extnID = ?'id-ce-basicConstraints', + extnValue = #'BasicConstraints'{cA=true}, + critical=true}; + false -> + []; + Len when is_integer(Len) -> + #'Extension'{extnID = ?'id-ce-basicConstraints', + extnValue = #'BasicConstraints'{cA=true, pathLenConstraint=Len}, + critical=true}; + _ -> + #'Extension'{extnID = ?'id-ce-basicConstraints', + extnValue = Data} + end; +extension({Id, Data, Critical}) -> + #'Extension'{extnID = Id, extnValue = Data, critical = Critical}. + + +publickey(#'RSAPrivateKey'{modulus=N, publicExponent=E}) -> + Public = #'RSAPublicKey'{modulus=N, publicExponent=E}, + Algo = #'PublicKeyAlgorithm'{algorithm= ?rsaEncryption, parameters='NULL'}, + #'OTPSubjectPublicKeyInfo'{algorithm = Algo, + subjectPublicKey = Public}; +publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) -> + Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-dsa', + parameters=#'Dss-Parms'{p=P, q=Q, g=G}}, + #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}. + +validity(Opts) -> + DefFrom0 = date(), + DefTo0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())+7), + {DefFrom, DefTo} = proplists:get_value(validity, Opts, {DefFrom0, DefTo0}), + Format = fun({Y,M,D}) -> lists:flatten(io_lib:format("~w~2..0w~2..0w000000Z",[Y,M,D])) end, + #'Validity'{notBefore={generalTime, Format(DefFrom)}, + notAfter ={generalTime, Format(DefTo)}}. + +sign_algorithm(#'RSAPrivateKey'{}, Opts) -> + Type = case proplists:get_value(digest, Opts, sha1) of + sha1 -> ?'sha1WithRSAEncryption'; + sha512 -> ?'sha512WithRSAEncryption'; + sha384 -> ?'sha384WithRSAEncryption'; + sha256 -> ?'sha256WithRSAEncryption'; + md5 -> ?'md5WithRSAEncryption'; + md2 -> ?'md2WithRSAEncryption' + end, + {Type, 'NULL'}; +sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) -> + {?'id-dsa-with-sha1', #'Dss-Parms'{p=P, q=Q, g=G}}. + +make_key(rsa, _Opts) -> + %% (OBS: for testing only) + gen_rsa2(64); +make_key(dsa, _Opts) -> + gen_dsa2(128, 20). %% Bytes i.e. {1024, 160} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% RSA key generation (OBS: for testing only) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +-define(SMALL_PRIMES, [65537,97,89,83,79,73,71,67,61,59,53, + 47,43,41,37,31,29,23,19,17,13,11,7,5,3]). + +gen_rsa2(Size) -> + P = prime(Size), + Q = prime(Size), + N = P*Q, + Tot = (P - 1) * (Q - 1), + [E|_] = lists:dropwhile(fun(Candidate) -> (Tot rem Candidate) == 0 end, ?SMALL_PRIMES), + {D1,D2} = extended_gcd(E, Tot), + D = erlang:max(D1,D2), + case D < E of + true -> + gen_rsa2(Size); + false -> + {Co1,Co2} = extended_gcd(Q, P), + Co = erlang:max(Co1,Co2), + #'RSAPrivateKey'{version = 'two-prime', + modulus = N, + publicExponent = E, + privateExponent = D, + prime1 = P, + prime2 = Q, + exponent1 = D rem (P-1), + exponent2 = D rem (Q-1), + coefficient = Co + } + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% DSA key generation (OBS: for testing only) +%% See http://en.wikipedia.org/wiki/Digital_Signature_Algorithm +%% and the fips_186-3.pdf +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +gen_dsa2(LSize, NSize) -> + Q = prime(NSize), %% Choose N-bit prime Q + X0 = prime(LSize), + P0 = prime((LSize div 2) +1), + + %% Choose L-bit prime modulus P such that p–1 is a multiple of q. + case dsa_search(X0 div (2*Q*P0), P0, Q, 1000) of + error -> + gen_dsa2(LSize, NSize); + P -> + G = crypto:mod_exp(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q. + %% such that This may be done by setting g = h^(p–1)/q mod p, commonly h=2 is used. + + X = prime(20), %% Choose x by some random method, where 0 < x < q. + Y = crypto:mod_exp(G, X, P), %% Calculate y = g^x mod p. + + #'DSAPrivateKey'{version=0, p=P, q=Q, g=G, y=Y, x=X} + end. + +%% See fips_186-3.pdf +dsa_search(T, P0, Q, Iter) when Iter > 0 -> + P = 2*T*Q*P0 + 1, + case is_prime(crypto:mpint(P), 50) of + true -> P; + false -> dsa_search(T+1, P0, Q, Iter-1) + end; +dsa_search(_,_,_,_) -> + error. + + +%%%%%%% Crypto Math %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +prime(ByteSize) -> + Rand = odd_rand(ByteSize), + crypto:erlint(prime_odd(Rand, 0)). + +prime_odd(Rand, N) -> + case is_prime(Rand, 50) of + true -> + Rand; + false -> + NotPrime = crypto:erlint(Rand), + prime_odd(crypto:mpint(NotPrime+2), N+1) + end. + +%% see http://en.wikipedia.org/wiki/Fermat_primality_test +is_prime(_, 0) -> true; +is_prime(Candidate, Test) -> + CoPrime = odd_rand(<<0,0,0,4, 10000:32>>, Candidate), + case crypto:mod_exp(CoPrime, Candidate, Candidate) of + CoPrime -> is_prime(Candidate, Test-1); + _ -> false + end. + +odd_rand(Size) -> + Min = 1 bsl (Size*8-1), + Max = (1 bsl (Size*8))-1, + odd_rand(crypto:mpint(Min), crypto:mpint(Max)). + +odd_rand(Min,Max) -> + Rand = <<Sz:32, _/binary>> = crypto:rand_uniform(Min,Max), + BitSkip = (Sz+4)*8-1, + case Rand of + Odd = <<_:BitSkip, 1:1>> -> Odd; + Even = <<_:BitSkip, 0:1>> -> + crypto:mpint(crypto:erlint(Even)+1) + end. + +extended_gcd(A, B) -> + case A rem B of + 0 -> + {0, 1}; + N -> + {X, Y} = extended_gcd(B, N), + {Y, X-Y*(A div B)} + end. diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index ad87cfcba1..0d9a912e30 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -53,11 +53,15 @@ init_per_suite(Config) -> crypto:start(), ssl:start(), + + %% make rsa certs using oppenssl Result = (catch make_certs:all(?config(data_dir, Config), ?config(priv_dir, Config))), test_server:format("Make certs ~p~n", [Result]), - ssl_test_lib:cert_options(Config). + + NewConfig = ssl_test_lib:make_dsa_cert(Config), + ssl_test_lib:cert_options(NewConfig). %%-------------------------------------------------------------------- %% Function: end_per_suite(Config) -> _ @@ -105,8 +109,10 @@ init_per_testcase(no_authority_key_identifier, Config) -> ssl:start(), Config; -init_per_testcase(TestCase, Config) when TestCase == ciphers_ssl3; - TestCase == ciphers_ssl3_openssl_names -> +init_per_testcase(TestCase, Config) when TestCase == ciphers_rsa_signed_certs_ssl3; + TestCase == ciphers_rsa_signed_certs_openssl_names_ssl3; + TestCase == ciphers_dsa_signed_certs_ssl3; + TestCase == ciphers_dsa_signed_certs_openssl_names_ssl3 -> ssl:stop(), application:load(ssl), application:set_env(ssl, protocol_version, sslv3), @@ -124,7 +130,6 @@ init_per_testcase(protocol_versions, Config) -> init_per_testcase(empty_protocol_versions, Config) -> ssl:stop(), application:load(ssl), - %% For backwards compatibility sslv2 should be filtered out. application:set_env(ssl, protocol_version, []), ssl:start(), Config; @@ -165,8 +170,10 @@ end_per_testcase(session_cache_process_mnesia, Config) -> end_per_testcase(reuse_session_expired, Config) -> application:unset_env(ssl, session_lifetime), end_per_testcase(default_action, Config); -end_per_testcase(TestCase, Config) when TestCase == ciphers_ssl3; - TestCase == ciphers_ssl3_openssl_names; +end_per_testcase(TestCase, Config) when TestCase == ciphers_rsa_signed_certs_ssl3; + TestCase == ciphers_rsa_signed_certs_openssl_names_ssl3; + TestCase == ciphers_dsa_signed_certs_ssl3; + TestCase == ciphers_dsa_signed_certs_openssl_names_ssl3; TestCase == protocol_versions; TestCase == empty_protocol_versions-> application:unset_env(ssl, protocol_version), @@ -193,30 +200,37 @@ all(doc) -> all(suite) -> [app, alerts, connection_info, protocol_versions, - empty_protocol_versions, controlling_process, controller_dies, - client_closes_socket, peercert, connect_dist, peername, sockname, - socket_options, misc_ssl_options, versions, cipher_suites, - upgrade, upgrade_with_timeout, tcp_connect, ipv6, ekeyfile, - ecertfile, ecacertfile, eoptions, shutdown, shutdown_write, - shutdown_both, shutdown_error, ciphers, ciphers_ssl3, - ciphers_openssl_names, send_close, - close_transport_accept, dh_params, server_verify_peer_passive, - server_verify_peer_active, server_verify_peer_active_once, - server_verify_none_passive, server_verify_none_active, - server_verify_none_active_once, server_verify_no_cacerts, - server_require_peer_cert_ok, server_require_peer_cert_fail, - server_verify_client_once_passive, - server_verify_client_once_active, - server_verify_client_once_active_once, client_verify_none_passive, - client_verify_none_active, client_verify_none_active_once, - session_cache_process_list, session_cache_process_mnesia, - reuse_session, reuse_session_expired, - server_does_not_want_to_reuse_session, client_renegotiate, - server_renegotiate, client_renegotiate_reused_session, - server_renegotiate_reused_session, client_no_wrap_sequence_number, - server_no_wrap_sequence_number, extended_key_usage, - validate_extensions_fun, no_authority_key_identifier, - invalid_signature_client, invalid_signature_server, cert_expired + empty_protocol_versions, controlling_process, controller_dies, + client_closes_socket, peercert, connect_dist, peername, sockname, + socket_options, misc_ssl_options, versions, cipher_suites, + upgrade, upgrade_with_timeout, tcp_connect, ipv6, ekeyfile, + ecertfile, ecacertfile, eoptions, shutdown, shutdown_write, + shutdown_both, shutdown_error, + ciphers_rsa_signed_certs, ciphers_rsa_signed_certs_ssl3, + ciphers_rsa_signed_certs_openssl_names, + ciphers_rsa_signed_certs_openssl_names_ssl3, + ciphers_dsa_signed_certs, + ciphers_dsa_signed_certs_ssl3, + ciphers_dsa_signed_certs_openssl_names, + ciphers_dsa_signed_certs_openssl_names_ssl3, + send_close, + close_transport_accept, dh_params, server_verify_peer_passive, + server_verify_peer_active, server_verify_peer_active_once, + server_verify_none_passive, server_verify_none_active, + server_verify_none_active_once, server_verify_no_cacerts, + server_require_peer_cert_ok, server_require_peer_cert_fail, + server_verify_client_once_passive, + server_verify_client_once_active, + server_verify_client_once_active_once, client_verify_none_passive, + client_verify_none_active, client_verify_none_active_once, + session_cache_process_list, session_cache_process_mnesia, + reuse_session, reuse_session_expired, + server_does_not_want_to_reuse_session, client_renegotiate, + server_renegotiate, client_renegotiate_reused_session, + server_renegotiate_reused_session, client_no_wrap_sequence_number, + server_no_wrap_sequence_number, extended_key_usage, + validate_extensions_fun, no_authority_key_identifier, + invalid_signature_client, invalid_signature_server, cert_expired ]. %% Test cases starts here. @@ -1394,66 +1408,129 @@ shutdown_error(Config) when is_list(Config) -> {error, closed} = ssl:shutdown(Listen, read_write). %%------------------------------------------------------------------- -ciphers(doc) -> - ["Test all ssl cipher suites in highest support ssl/tls version"]; +ciphers_rsa_signed_certs(doc) -> + ["Test all rsa ssl cipher suites in highest support ssl/tls version"]; -ciphers(suite) -> +ciphers_rsa_signed_certs(suite) -> []; -ciphers(Config) when is_list(Config) -> +ciphers_rsa_signed_certs(Config) when is_list(Config) -> Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), - Ciphers = ssl:cipher_suites(), + Ciphers = ssl_test_lib:rsa_suites(), test_server:format("tls1 erlang cipher suites ~p~n", [Ciphers]), - Result = lists:map(fun(Cipher) -> - cipher(Cipher, Version, Config) end, - Ciphers), - case lists:flatten(Result) of - [] -> - ok; - Error -> - test_server:format("Cipher suite errors: ~p~n", [Error]), - test_server:fail(cipher_suite_failed_see_test_case_log) - end. + run_suites(Ciphers, Version, Config, rsa). -ciphers_ssl3(doc) -> - ["Test all ssl cipher suites in ssl3"]; +ciphers_rsa_signed_certs_ssl3(doc) -> + ["Test all rsa ssl cipher suites in ssl3"]; -ciphers_ssl3(suite) -> +ciphers_rsa_signed_certs_ssl3(suite) -> []; -ciphers_ssl3(Config) when is_list(Config) -> +ciphers_rsa_signed_certs_ssl3(Config) when is_list(Config) -> Version = ssl_record:protocol_version({3,0}), - Ciphers = ssl:cipher_suites(), + Ciphers = ssl_test_lib:rsa_suites(), test_server:format("ssl3 erlang cipher suites ~p~n", [Ciphers]), - Result = lists:map(fun(Cipher) -> - cipher(Cipher, Version, Config) end, - Ciphers), - case lists:flatten(Result) of - [] -> - ok; - Error -> - test_server:format("Cipher suite errors: ~p~n", [Error]), - test_server:fail(cipher_suite_failed_see_test_case_log) - end. + run_suites(Ciphers, Version, Config, rsa). + +ciphers_rsa_signed_certs_openssl_names(doc) -> + ["Test all rsa ssl cipher suites in highest support ssl/tls version"]; + +ciphers_rsa_signed_certs_openssl_names(suite) -> + []; + +ciphers_rsa_signed_certs_openssl_names(Config) when is_list(Config) -> + Version = + ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + Ciphers = ssl_test_lib:openssl_rsa_suites(), + test_server:format("tls1 openssl cipher suites ~p~n", [Ciphers]), + run_suites(Ciphers, Version, Config, rsa). -ciphers_openssl_names(doc) -> - ["Test all ssl cipher suites in highest support ssl/tls version"]; + +ciphers_rsa_signed_certs_openssl_names_ssl3(doc) -> + ["Test all dsa ssl cipher suites in ssl3"]; -ciphers_openssl_names(suite) -> +ciphers_rsa_signed_certs_openssl_names_ssl3(suite) -> []; -ciphers_openssl_names(Config) when is_list(Config) -> +ciphers_rsa_signed_certs_openssl_names_ssl3(Config) when is_list(Config) -> + Version = ssl_record:protocol_version({3,0}), + Ciphers = ssl_test_lib:openssl_rsa_suites(), + run_suites(Ciphers, Version, Config, rsa). + + +ciphers_dsa_signed_certs(doc) -> + ["Test all dsa ssl cipher suites in highest support ssl/tls version"]; + +ciphers_dsa_signed_certs(suite) -> + []; + +ciphers_dsa_signed_certs(Config) when is_list(Config) -> Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), - Ciphers = ssl:cipher_suites(openssl), + Ciphers = ssl_test_lib:dsa_suites(), + test_server:format("tls1 erlang cipher suites ~p~n", [Ciphers]), + run_suites(Ciphers, Version, Config, dsa). + +ciphers_dsa_signed_certs_ssl3(doc) -> + ["Test all dsa ssl cipher suites in ssl3"]; + +ciphers_dsa_signed_certs_ssl3(suite) -> + []; + +ciphers_dsa_signed_certs_ssl3(Config) when is_list(Config) -> + Version = + ssl_record:protocol_version({3,0}), + + Ciphers = ssl_test_lib:dsa_suites(), + test_server:format("ssl3 erlang cipher suites ~p~n", [Ciphers]), + run_suites(Ciphers, Version, Config, dsa). + + +ciphers_dsa_signed_certs_openssl_names(doc) -> + ["Test all dsa ssl cipher suites in highest support ssl/tls version"]; + +ciphers_dsa_signed_certs_openssl_names(suite) -> + []; + +ciphers_dsa_signed_certs_openssl_names(Config) when is_list(Config) -> + Version = + ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + + Ciphers = ssl_test_lib:openssl_dsa_suites(), test_server:format("tls1 openssl cipher suites ~p~n", [Ciphers]), + run_suites(Ciphers, Version, Config, dsa). + + +ciphers_dsa_signed_certs_openssl_names_ssl3(doc) -> + ["Test all dsa ssl cipher suites in ssl3"]; + +ciphers_dsa_signed_certs_openssl_names_ssl3(suite) -> + []; + +ciphers_dsa_signed_certs_openssl_names_ssl3(Config) when is_list(Config) -> + Version = ssl_record:protocol_version({3,0}), + Ciphers = ssl_test_lib:openssl_dsa_suites(), + run_suites(Ciphers, Version, Config, dsa). + + +run_suites(Ciphers, Version, Config, Type) -> + {ClientOpts, ServerOpts} = + case Type of + rsa -> + {?config(client_opts, Config), + ?config(server_opts, Config)}; + dsa -> + {?config(client_opts, Config), + ?config(server_dsa_opts, Config)} + end, + Result = lists:map(fun(Cipher) -> - cipher(Cipher, Version, Config) end, + cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end, Ciphers), case lists:flatten(Result) of [] -> @@ -1463,12 +1540,14 @@ ciphers_openssl_names(Config) when is_list(Config) -> test_server:fail(cipher_suite_failed_see_test_case_log) end. +erlang_cipher_suite(Suite) when is_list(Suite)-> + ssl_cipher:suite_definition(ssl_cipher:openssl_suite(Suite)); +erlang_cipher_suite(Suite) -> + Suite. -cipher(CipherSuite, Version, Config) -> +cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> process_flag(trap_exit, true), test_server:format("Testing CipherSuite ~p~n", [CipherSuite]), - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, @@ -1507,11 +1586,6 @@ cipher(CipherSuite, Version, Config) -> [{ErlangCipherSuite, Error}] end. -erlang_cipher_suite(Suite) when is_list(Suite)-> - ssl_cipher:suite_definition(ssl_cipher:openssl_suite(Suite)); -erlang_cipher_suite(Suite) -> - Suite. - %%-------------------------------------------------------------------- reuse_session(doc) -> ["Test reuse of sessions (short handshake)"]; @@ -2664,7 +2738,7 @@ invalid_signature_client(Config) when is_list(Config) -> {host, Hostname}, {from, self()}, {options, NewClientOpts}]), - + tcp_delivery_workaround(Server, {error, "bad certificate"}, Client, {error,"bad certificate"}). @@ -2971,4 +3045,3 @@ erlang_ssl_receive(Socket, Data) -> after ?SLEEP * 3 -> test_server:fail({did_not_get, Data}) end. - diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index 46b6eb401d..d11acc8130 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -318,6 +318,25 @@ cert_options(Config) -> | Config]. +make_dsa_cert(Config) -> + ServerCaInfo = {ServerCaCert, _} = erl_make_certs:make_cert([{key, dsa}]), + {ServerCert, ServerCertKey} = erl_make_certs:make_cert([{key, dsa}, {issuer, ServerCaInfo}]), + ServerCaCertFile = filename:join([?config(priv_dir, Config), + "server", "dsa_cacerts.pem"]), + ServerCertFile = filename:join([?config(priv_dir, Config), + "server", "dsa_cert.pem"]), + ServerKeyFile = filename:join([?config(priv_dir, Config), + "server", "dsa_key.pem"]), + + public_key:der_to_pem(ServerCaCertFile, [{cert, ServerCaCert, not_encrypted}]), + public_key:der_to_pem(ServerCertFile, [{cert, ServerCert, not_encrypted}]), + public_key:der_to_pem(ServerKeyFile, [ServerCertKey]), + + [{server_dsa_opts, [{ssl_imp, new},{reuseaddr, true}, + {cacertfile, ServerCaCertFile}, + {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]} | Config]. + + start_upgrade_server(Args) -> Result = spawn_link(?MODULE, run_upgrade_server, [Args]), receive @@ -529,3 +548,42 @@ send_selected_port(Pid, 0, Socket) -> Pid ! {self(), {port, NewPort}}; send_selected_port(_,_,_) -> ok. + +rsa_suites() -> + lists:filter(fun({dhe_dss, _, _}) -> + false; + (_) -> + true + end, + ssl:cipher_suites()). + +dsa_suites() -> + lists:filter(fun({dhe_dss, _, _}) -> + true; + (_) -> + false + end, + ssl:cipher_suites()). + + +openssl_rsa_suites() -> + Ciphers = ssl:cipher_suites(openssl), + lists:filter(fun(Str) -> + case re:run(Str,"DSS",[]) of + nomatch -> + true; + _ -> + false + end + end, Ciphers). + +openssl_dsa_suites() -> + Ciphers = ssl:cipher_suites(openssl), + lists:filter(fun(Str) -> + case re:run(Str,"DSS",[]) of + nomatch -> + false; + _ -> + true + end + end, Ciphers). diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index 1c18f10038..e4c77b2fb4 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -56,7 +56,8 @@ init_per_suite(Config) -> (catch make_certs:all(?config(data_dir, Config), ?config(priv_dir, Config))), test_server:format("Make certs ~p~n", [Result]), - ssl_test_lib:cert_options(Config) + NewConfig = ssl_test_lib:make_dsa_cert(Config), + ssl_test_lib:cert_options(NewConfig) end. %%-------------------------------------------------------------------- @@ -142,6 +143,7 @@ all(doc) -> all(suite) -> [erlang_client_openssl_server, erlang_server_openssl_client, + erlang_server_openssl_client_dsa_cert, erlang_server_openssl_client_reuse_session, erlang_client_openssl_server_renegotiate, erlang_client_openssl_server_no_wrap_sequence_number, @@ -157,7 +159,8 @@ all(suite) -> tls1_erlang_client_openssl_server_client_cert, tls1_erlang_server_openssl_client_client_cert, tls1_erlang_server_erlang_client_client_cert, - ciphers, + ciphers_rsa_signed_certs, + ciphers_dsa_signed_certs, erlang_client_bad_openssl_server, expired_session, ssl2_erlang_server_openssl_client @@ -247,6 +250,43 @@ erlang_server_openssl_client(Config) when is_list(Config) -> %%-------------------------------------------------------------------- +erlang_server_openssl_client_dsa_cert(doc) -> + ["Test erlang server with openssl client"]; +erlang_server_openssl_client_dsa_cert(suite) -> + []; +erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ServerOpts = ?config(server_dsa_opts, Config), + + {_, ServerNode, _} = ssl_test_lib:run_where(Config), + + Data = "From openssl to erlang", + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ + " -host localhost -tls1 -msg", + + test_server:format("openssl cmd: ~p~n", [Cmd]), + + OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + port_command(OpenSslPort, Data), + + ssl_test_lib:check_result(Server, ok), + + ssl_test_lib:close(Server), + + close_port(OpenSslPort), + process_flag(trap_exit, false), + ok. + + +%%-------------------------------------------------------------------- + erlang_server_openssl_client_reuse_session(doc) -> ["Test erlang server with openssl client that reconnects with the" "same session id, to test reusing of sessions."]; @@ -881,19 +921,46 @@ tls1_erlang_server_erlang_client_client_cert(Config) when is_list(Config) -> ok. %%-------------------------------------------------------------------- -ciphers(doc) -> - [""]; +ciphers_rsa_signed_certs(doc) -> + ["Test cipher suites that uses rsa certs"]; + +ciphers_rsa_signed_certs(suite) -> + []; + +ciphers_rsa_signed_certs(Config) when is_list(Config) -> + Version = + ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + + Ciphers = ssl_test_lib:rsa_suites(), + run_suites(Ciphers, Version, Config, rsa). + + +ciphers_dsa_signed_certs(doc) -> + ["Test cipher suites that uses dsa certs"]; -ciphers(suite) -> +ciphers_dsa_signed_certs(suite) -> []; -ciphers(Config) when is_list(Config) -> +ciphers_dsa_signed_certs(Config) when is_list(Config) -> Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), - Ciphers = ssl:cipher_suites(), + Ciphers = ssl_test_lib:dsa_suites(), + run_suites(Ciphers, Version, Config, dsa). + +run_suites(Ciphers, Version, Config, Type) -> + {ClientOpts, ServerOpts} = + case Type of + rsa -> + {?config(client_opts, Config), + ?config(server_opts, Config)}; + dsa -> + {?config(client_opts, Config), + ?config(server_dsa_opts, Config)} + end, + Result = lists:map(fun(Cipher) -> - cipher(Cipher, Version, Config) end, + cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end, Ciphers), case lists:flatten(Result) of [] -> @@ -902,12 +969,12 @@ ciphers(Config) when is_list(Config) -> test_server:format("Cipher suite errors: ~p~n", [Error]), test_server:fail(cipher_suite_failed_see_test_case_log) end. - -cipher(CipherSuite, Version, Config) -> + + + +cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) -> process_flag(trap_exit, true), test_server:format("Testing CipherSuite ~p~n", [CipherSuite]), - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), {ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config), Port = ssl_test_lib:inet_port(node()), diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk index e3db7008e3..5d8be1cd0b 100644 --- a/lib/ssl/vsn.mk +++ b/lib/ssl/vsn.mk @@ -19,9 +19,12 @@ SSL_VSN = 3.11.1 -TICKETS = OTP-8588 \ +TICKETS = OTP-8679 \ + OTP-7047 \ + OTP-7049 \ OTP-8568 \ - OTP-7049 + OTP-8587 \ + OTP-8588 #TICKETS_3.11 = OTP-8517 \ # OTP-7046 \ diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index 6bbb52ebae..c8bbb04e9a 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -2672,7 +2672,6 @@ default_types() -> {set, 0}, {string, 0}, {term, 0}, - {tid, 0}, {timeout, 0}, {var, 1}], dict:from_list([{T, -1} || T <- DefTypes]). @@ -2694,7 +2693,6 @@ is_newly_introduced_builtin_type({gb_tree, 0}) -> true; % opaque is_newly_introduced_builtin_type({iodata, 0}) -> true; is_newly_introduced_builtin_type({queue, 0}) -> true; % opaque is_newly_introduced_builtin_type({set, 0}) -> true; % opaque -is_newly_introduced_builtin_type({tid, 0}) -> true; % opaque %% R13B01 is_newly_introduced_builtin_type({boolean, 0}) -> true; is_newly_introduced_builtin_type({Name, _}) when is_atom(Name) -> false. diff --git a/lib/stdlib/src/ets.erl b/lib/stdlib/src/ets.erl index b0a197d784..1d033f6f7b 100644 --- a/lib/stdlib/src/ets.erl +++ b/lib/stdlib/src/ets.erl @@ -42,12 +42,15 @@ -export([i/0, i/1, i/2, i/3]). --export_type([tab/0]). +-export_type([tab/0, tid/0]). -%%------------------------------------------------------------------------------ +%%----------------------------------------------------------------------------- -type tab() :: atom() | tid(). +%% a similar definition is also in erl_types +-opaque tid() :: integer(). + -type ext_info() :: 'md5sum' | 'object_count'. -type protection() :: 'private' | 'protected' | 'public'. -type type() :: 'bag' | 'duplicate_bag' | 'ordered_set' | 'set'. @@ -65,7 +68,7 @@ -type match_pattern() :: atom() | tuple(). -type match_specs() :: [{match_pattern(), [_], [_]}]. -%%------------------------------------------------------------------------------ +%%----------------------------------------------------------------------------- %% The following functions used to be found in this module, but %% are now BIFs (i.e. implemented in C). diff --git a/lib/tools/emacs/erlang-eunit.el b/lib/tools/emacs/erlang-eunit.el index 970afe2e9f..f2c0db67dd 100644 --- a/lib/tools/emacs/erlang-eunit.el +++ b/lib/tools/emacs/erlang-eunit.el @@ -23,8 +23,22 @@ (eval-when-compile (require 'cl)) -(defvar erlang-eunit-separate-src-and-test-directories t - "*Whether or not to keep source and EUnit test files in separate directories") +(defvar erlang-eunit-src-candidate-dirs '("../src" ".") + "*Name of directories which to search for source files matching +an EUnit test file. The first directory in the list will be used, +if there is no match.") + +(defvar erlang-eunit-test-candidate-dirs '("../test" ".") + "*Name of directories which to search for EUnit test files matching +a source file. The first directory in the list will be used, +if there is no match.") + +(defvar erlang-eunit-autosave nil + "*Set to non-nil to automtically save unsaved buffers before running tests. +This is useful, reducing the save-compile-load-test cycle to one keychord.") + +(defvar erlang-eunit-recent-info '((mode . nil) (module . nil) (test . nil) (cover . nil)) + "Info about the most recent running of an EUnit test representation.") ;;; ;;; Switch between src/EUnit test buffers @@ -44,7 +58,6 @@ buffer and vice versa" "Open the EUnit test file which corresponds to a src file" (find-file-other-window (erlang-eunit-test-filename src-file-path))) - ;;; ;;; Open the src file which corresponds to the an EUnit test file ;;; @@ -55,37 +68,55 @@ buffer and vice versa" ;;; Return the name and path of the EUnit test file ;;, (input may be either the source filename itself or the EUnit test filename) (defun erlang-eunit-test-filename (file-path) - (erlang-eunit-rewrite-filename file-path "test" "_tests")) + (if (erlang-eunit-test-file-p file-path) + file-path + (erlang-eunit-rewrite-filename file-path erlang-eunit-test-candidate-dirs))) ;;; Return the name and path of the source file ;;, (input may be either the source filename itself or the EUnit test filename) (defun erlang-eunit-src-filename (file-path) - (erlang-eunit-rewrite-filename file-path "src" "")) + (if (erlang-eunit-src-file-p file-path) + file-path + (erlang-eunit-rewrite-filename file-path erlang-eunit-src-candidate-dirs))) ;;; Rewrite a filename from the src or test filename to the other -(defun erlang-eunit-rewrite-filename (orig-file-path dest-dirname dest-suffix) - (let* ((root-dir-name (erlang-eunit-file-root-dir-name orig-file-path)) - (src-module-name (erlang-eunit-source-module-name orig-file-path)) - (dest-base-name (concat src-module-name dest-suffix ".erl")) - (dest-dir-name-1 (file-name-directory orig-file-path)) - (dest-dir-name-2 (filename-join root-dir-name dest-dirname)) - (dest-file-name-1 (filename-join dest-dir-name-1 dest-base-name)) - (dest-file-name-2 (filename-join dest-dir-name-2 dest-base-name))) - ;; This function tries to be a bit intelligent: - ;; * if there already is a test (or source) file in the same - ;; directory as a source (or test) file, it'll be picked - ;; * if there already is a test (or source) file in a separate - ;; test (or src) directory, it'll be picked - ;; * otherwise it'll resort to whatever alternative (same or - ;; separate directories) that the user has chosen - (cond ((file-readable-p dest-file-name-1) - dest-file-name-1) - ((file-readable-p dest-file-name-2) - dest-file-name-2) - (erlang-eunit-separate-src-and-test-directories - dest-file-name-2) - (t - dest-file-name-1)))) +(defun erlang-eunit-rewrite-filename (orig-file-path candidate-dirs) + (or (erlang-eunit-locate-buddy orig-file-path candidate-dirs) + (erlang-eunit-buddy-file-path orig-file-path (car candidate-dirs)))) + +;;; Search for a file's buddy file (a source file's EUnit test file, +;;; or an EUnit test file's source file) in a list of candidate +;;; directories. +(defun erlang-eunit-locate-buddy (orig-file-path candidate-dirs) + (when candidate-dirs + (let ((buddy-file-path (erlang-eunit-buddy-file-path + orig-file-path + (car candidate-dirs)))) + (if (file-readable-p buddy-file-path) + buddy-file-path + (erlang-eunit-locate-buddy orig-file-path (cdr candidate-dirs)))))) + +(defun erlang-eunit-buddy-file-path (orig-file-path buddy-dir-name) + (let* ((orig-dir-name (file-name-directory orig-file-path)) + (buddy-dir-name (file-truename + (filename-join orig-dir-name buddy-dir-name))) + (buddy-base-name (erlang-eunit-buddy-basename orig-file-path))) + (filename-join buddy-dir-name buddy-base-name))) + +;;; Return the basename of the buddy file: +;;; /tmp/foo/src/x.erl --> x_tests.erl +;;; /tmp/foo/test/x_tests.erl --> x.erl +(defun erlang-eunit-buddy-basename (file-path) + (let ((src-module-name (erlang-eunit-source-module-name file-path))) + (cond + ((erlang-eunit-src-file-p file-path) + (concat src-module-name "_tests.erl")) + ((erlang-eunit-test-file-p file-path) + (concat src-module-name ".erl"))))) + +;;; Checks whether a file is a source file or not +(defun erlang-eunit-src-file-p (file-path) + (not (erlang-eunit-test-file-p file-path))) ;;; Checks whether a file is a EUnit test file or not (defun erlang-eunit-test-file-p (file-path) @@ -96,11 +127,10 @@ buffer and vice versa" ;;; /tmp/foo/test/x_tests.erl --> x (defun erlang-eunit-source-module-name (file-path) (interactive) - (let* ((file-name (file-name-nondirectory file-path)) - (base-name (file-name-sans-extension file-name))) - (if (string-match "^\\(.+\\)_tests$" base-name) - (substring base-name (match-beginning 1) (match-end 1)) - base-name))) + (let ((module-name (erlang-eunit-module-name file-path))) + (if (string-match "^\\(.+\\)_tests$" module-name) + (substring module-name (match-beginning 1) (match-end 1)) + module-name))) ;;; Return the module name of the file ;;; /tmp/foo/src/x.erl --> x @@ -109,18 +139,6 @@ buffer and vice versa" (interactive) (file-name-sans-extension (file-name-nondirectory file-path))) -;;; Return the directory name which is common to both src and test -;;; /tmp/foo/src/x.erl --> /tmp/foo -;;; /tmp/foo/test/x_tests.erl --> /tmp/foo -(defun erlang-eunit-file-root-dir-name (file-path) - (erlang-eunit-dir-parent-dirname (file-name-directory file-path))) - -;;; Return the parent directory name of a directory -;;; /tmp/foo/ --> /tmp -;;; /tmp/foo --> /tmp -(defun erlang-eunit-dir-parent-dirname (dir-name) - (file-name-directory (directory-file-name dir-name))) - ;;; Older emacsen don't have string-match-p. (defun erlang-eunit-string-match-p (regexp string &optional start) (if (fboundp 'string-match-p) ;; appeared in emacs 23 @@ -135,12 +153,28 @@ buffer and vice versa" (concat dir file) (concat dir "/" file))) +;;; Get info about the most recent running of EUnit +(defun erlang-eunit-recent (key) + (cdr (assq key erlang-eunit-recent-info))) + +;;; Record info about the most recent running of EUnit +;;; Known modes are 'module-mode and 'test-mode +(defun erlang-eunit-record-recent (mode module test) + (setcdr (assq 'mode erlang-eunit-recent-info) mode) + (setcdr (assq 'module erlang-eunit-recent-info) module) + (setcdr (assq 'test erlang-eunit-recent-info) test)) + +;;; Record whether the most recent running of EUnit included cover +;;; compilation +(defun erlang-eunit-record-recent-compile (under-cover) + (setcdr (assq 'cover erlang-eunit-recent-info) under-cover)) + ;;; Determine options for EUnit. (defun erlang-eunit-opts () (if current-prefix-arg ", [verbose]" "")) ;;; Determine current test function -(defun erlang-eunit-test-name () +(defun erlang-eunit-current-test () (save-excursion (erlang-end-of-function 1) (erlang-beginning-of-function 1) @@ -152,45 +186,125 @@ buffer and vice versa" (defun erlang-eunit-test-generator-p (test-name) (if (erlang-eunit-string-match-p "^\\(.+\\)_test_$" test-name) t nil)) -;;; Run the current EUnit test -(defun erlang-eunit-run-current-test () - (let* ((module-name (erlang-add-quotes-if-needed - (erlang-eunit-module-name buffer-file-name))) - (test-name (erlang-eunit-test-name)) - (command - (cond ((erlang-eunit-simple-test-p test-name) - (format "eunit:test({%s, %s}%s)." - module-name test-name (erlang-eunit-opts))) - ((erlang-eunit-test-generator-p test-name) - (format "eunit:test({generator, %s, %s}%s)." - module-name test-name (erlang-eunit-opts))) - (t (format "%% WARNING: '%s' is not a test function" test-name))))) +;;; Run one EUnit test +(defun erlang-eunit-run-test (module-name test-name) + (let ((command + (cond ((erlang-eunit-simple-test-p test-name) + (format "eunit:test({%s, %s}%s)." + module-name test-name (erlang-eunit-opts))) + ((erlang-eunit-test-generator-p test-name) + (format "eunit:test({generator, %s, %s}%s)." + module-name test-name (erlang-eunit-opts))) + (t (format "%% WARNING: '%s' is not a test function" test-name))))) + (erlang-eunit-record-recent 'test-mode module-name test-name) (erlang-eunit-inferior-erlang-send-command command))) ;;; Run EUnit tests for the current module -(defun erlang-eunit-run-module-tests () - (let* ((module-name (erlang-add-quotes-if-needed - (erlang-eunit-source-module-name buffer-file-name))) - (command (format "eunit:test(%s%s)." module-name (erlang-eunit-opts)))) +(defun erlang-eunit-run-module-tests (module-name) + (let ((command (format "eunit:test(%s%s)." module-name (erlang-eunit-opts)))) + (erlang-eunit-record-recent 'module-mode module-name nil) (erlang-eunit-inferior-erlang-send-command command))) +(defun erlang-eunit-compile-and-run-recent () + "Compile the source and test files and repeat the most recent EUnit test run. + +With prefix arg, compiles for debug and runs tests with the verbose flag set." + (interactive) + (case (erlang-eunit-recent 'mode) + ('test-mode + (erlang-eunit-compile-and-test + 'erlang-eunit-run-test (list (erlang-eunit-recent 'module) + (erlang-eunit-recent 'test)))) + ('module-mode + (erlang-eunit-compile-and-test + 'erlang-eunit-run-module-tests (list (erlang-eunit-recent 'module)) + (erlang-eunit-recent 'cover))) + (t (error "EUnit has not yet been run. Please run a test first.")))) + +(defun erlang-eunit-cover-compile () + "Cover compile current module." + (interactive) + (let* ((erlang-compile-extra-opts + (append (list 'debug_info) erlang-compile-extra-opts)) + (module-name + (erlang-add-quotes-if-needed + (erlang-eunit-module-name buffer-file-name))) + (compile-command + (format "cover:compile_beam(%s)." module-name))) + (erlang-compile) + (if (erlang-eunit-last-compilation-successful-p) + (erlang-eunit-inferior-erlang-send-command compile-command)))) + +(defun erlang-eunit-analyze-coverage () + "Analyze the data collected by cover tool for the module in the +current buffer. + +Assumes that the module has been cover compiled prior to this +call. This function will do two things: print the number of +covered and uncovered functions in the erlang shell and display a +new buffer called *<module name> coverage* which shows the source +code along with the coverage analysis results." + (interactive) + (let* ((module-name (erlang-add-quotes-if-needed + (erlang-eunit-module-name buffer-file-name))) + (tmp-filename (make-temp-file "cover")) + (analyze-command (format "cover:analyze_to_file(%s, \"%s\"). " + module-name tmp-filename)) + (buf-name (format "*%s coverage*" module-name))) + (erlang-eunit-inferior-erlang-send-command analyze-command) + ;; The purpose of the following snippet is to get the result of the + ;; analysis from a file into a new buffer (or an old, if one with + ;; the specified name already exists). Also we want the erlang-mode + ;; *and* view-mode to be enabled. + (save-excursion + (let ((buf (get-buffer-create (format "*%s coverage*" module-name)))) + (set-buffer buf) + (setq buffer-read-only nil) + (insert-file-contents tmp-filename nil nil nil t) + (if (= (buffer-size) 0) + (kill-buffer buf) + ;; FIXME: this would be a good place to enable (emacs-mode) + ;; to get some nice syntax highlighting in the + ;; coverage report, but it doesn't play well with + ;; flymake. Leave it off for now. + (view-buffer buf)))) + (delete-file tmp-filename))) + (defun erlang-eunit-compile-and-run-current-test () "Compile the source and test files and run the current EUnit test. With prefix arg, compiles for debug and runs tests with the verbose flag set." (interactive) - (erlang-eunit-compile-and-test 'erlang-eunit-run-current-test)) + (let ((module-name (erlang-add-quotes-if-needed + (erlang-eunit-module-name buffer-file-name))) + (test-name (erlang-eunit-current-test))) + (erlang-eunit-compile-and-test + 'erlang-eunit-run-test (list module-name test-name)))) (defun erlang-eunit-compile-and-run-module-tests () "Compile the source and test files and run all EUnit tests in the module. With prefix arg, compiles for debug and runs tests with the verbose flag set." (interactive) - (erlang-eunit-compile-and-test 'erlang-eunit-run-module-tests)) + (let ((module-name (erlang-add-quotes-if-needed + (erlang-eunit-source-module-name buffer-file-name)))) + (erlang-eunit-compile-and-test + 'erlang-eunit-run-module-tests (list module-name)))) ;;; Compile source and EUnit test file and finally run EUnit tests for ;;; the current module -(defun erlang-eunit-compile-and-test (run-tests) +(defun erlang-eunit-compile-and-test (test-fun test-args &optional under-cover) + "Compile the source and test files and run the EUnit test suite. + +If under-cover is set to t, the module under test is compile for +code coverage analysis. If under-cover is left out or not set, +coverage analysis is disabled. The result of the code coverage +is both printed to the erlang shell (the number of covered vs +uncovered functions in a module) and written to a buffer called +*<module> coverage* (which shows the source code for the module +and the number of times each line is covered). +With prefix arg, compiles for debug and runs tests with the verbose flag set." + (erlang-eunit-record-recent-compile under-cover) (let ((src-filename (erlang-eunit-src-filename buffer-file-name)) (test-filename (erlang-eunit-test-filename buffer-file-name))) @@ -198,7 +312,7 @@ With prefix arg, compiles for debug and runs tests with the verbose flag set." ;; below, is to ask the question about saving buffers only once, ;; instead of possibly several: one for each file to compile, ;; for instance for both x.erl and x_tests.erl. - (save-some-buffers) + (save-some-buffers erlang-eunit-autosave) (flet ((save-some-buffers (&optional any) nil)) ;; Compilation of the source file is mandatory (the file must @@ -206,23 +320,56 @@ With prefix arg, compiles for debug and runs tests with the verbose flag set." ;; test file on the other hand, is optional, since eunit tests may ;; be placed in the source file instead. Any compilation error ;; will prevent the subsequent steps to be run (hence the `and') - (and (erlang-eunit-compile-file src-filename) + (and (erlang-eunit-compile-file src-filename under-cover) (if (file-readable-p test-filename) (erlang-eunit-compile-file test-filename) t) - (funcall run-tests))))) + (apply test-fun test-args) + (if under-cover + (save-excursion + (set-buffer (find-file-noselect src-filename)) + (erlang-eunit-analyze-coverage))))))) -(defun erlang-eunit-compile-file (file-path) +(defun erlang-eunit-compile-and-run-module-tests-under-cover () + "Compile the source and test files and run the EUnit test suite and measure +code coverage. + +With prefix arg, compiles for debug and runs tests with the verbose flag set." + (interactive) + (let ((module-name (erlang-add-quotes-if-needed + (erlang-eunit-source-module-name buffer-file-name)))) + (erlang-eunit-compile-and-test + 'erlang-eunit-run-module-tests (list module-name) t))) + +(defun erlang-eunit-compile-file (file-path &optional under-cover) (if (file-readable-p file-path) (save-excursion - (set-buffer (find-file-noselect file-path)) - (erlang-compile) - (erlang-eunit-last-compilation-successful-p)) + (set-buffer (find-file-noselect file-path)) + ;; In order to run a code coverage analysis on a + ;; module, we have two options: + ;; + ;; * either compile the module with cover:compile instead of the + ;; regular compiler + ;; + ;; * or first compile the module with the regular compiler (but + ;; *with* debug_info) and then compile it for coverage + ;; analysis using cover:compile_beam. + ;; + ;; We could accomplish the first by changing the + ;; erlang-compile-erlang-function to cover:compile, but there's + ;; a risk that that's used for other purposes. Therefore, a + ;; safer alternative (although with more steps) is to add + ;; debug_info to the list of compiler options and go for the + ;; second alternative. + (if under-cover + (erlang-eunit-cover-compile) + (erlang-compile)) + (erlang-eunit-last-compilation-successful-p)) (let ((msg (format "Could not read %s" file-path))) - (erlang-eunit-inferior-erlang-send-command + (erlang-eunit-inferior-erlang-send-command (format "%% WARNING: %s" msg)) (error msg)))) - + (defun erlang-eunit-last-compilation-successful-p () (save-excursion (set-buffer inferior-erlang-buffer) @@ -231,7 +378,7 @@ With prefix arg, compiles for debug and runs tests with the verbose flag set." (lambda (re) (let ((continue t) (result t)) (while continue ; ignore warnings, stop at errors - (if (re-search-forward re (point-max) t) + (if (re-search-forward re (point-max) t) (if (erlang-eunit-is-compilation-warning) t (setq result nil) @@ -242,7 +389,7 @@ With prefix arg, compiles for debug and runs tests with the verbose flag set." (mapcar (lambda (e) (car e)) erlang-error-regexp-alist)))) (defun erlang-eunit-is-compilation-warning () - (erlang-eunit-string-match-p + (erlang-eunit-string-match-p "[0-9]+: Warning:" (buffer-substring (line-beginning-position) (line-end-position)))) @@ -271,7 +418,11 @@ With prefix arg, compiles for debug and runs tests with the verbose flag set." (defconst erlang-eunit-key-bindings '(("\C-c\C-et" erlang-eunit-toggle-src-and-test-file-other-window) ("\C-c\C-ek" erlang-eunit-compile-and-run-module-tests) - ("\C-c\C-ej" erlang-eunit-compile-and-run-current-test))) + ("\C-c\C-ej" erlang-eunit-compile-and-run-current-test) + ("\C-c\C-el" erlang-eunit-compile-and-run-recent) + ("\C-c\C-ec" erlang-eunit-compile-and-run-module-tests-under-cover) + ("\C-c\C-ev" erlang-eunit-cover-compile) + ("\C-c\C-ea" erlang-eunit-analyze-coverage))) (defun erlang-eunit-add-key-bindings () (dolist (binding erlang-eunit-key-bindings) diff --git a/lib/xmerl/doc/src/notes.xml b/lib/xmerl/doc/src/notes.xml index 207f6fdf16..0403fbca27 100644 --- a/lib/xmerl/doc/src/notes.xml +++ b/lib/xmerl/doc/src/notes.xml @@ -50,6 +50,14 @@ Own Id: OTP-8537 </p> </item> + <item> + <p> + An empty element declared as a simpleContent was not properly validated. + </p> + <p> + Own Id: OTP-8599 + </p> + </item> </list> </section> diff --git a/lib/xmerl/src/xmerl_xsd.erl b/lib/xmerl/src/xmerl_xsd.erl index c7bca86205..1aedc9e270 100644 --- a/lib/xmerl/src/xmerl_xsd.erl +++ b/lib/xmerl/src/xmerl_xsd.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2006-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -2687,13 +2687,16 @@ check_element_type(XML=[E=#xmlElement{name=Name}|Rest], _ -> {error,{error_path(E,Name),?MODULE,{element_bad_match,E,Any,Env}}} end; -check_element_type([],CM,_Env,_Block,_S,Checked) -> +check_element_type([],CM,_Env,_Block,S,Checked) -> %% #schema_complex_type, any, #schema_group, anyType and lists are %% catched above. case CM of + #schema_simple_type{} -> + {NewVal,S2} = check_type(CM,[],unapplied,S), + {NewVal,[],S2}; {simpleType,_} -> - {error,{error_path(Checked,undefined),?MODULE, - {empty_content_not_allowed,CM}}}; + {NewVal,S2} = check_type(CM,[],unapplied,S), + {NewVal,[],S2}; _ -> {error,{error_path(Checked,undefined),?MODULE, {empty_content_not_allowed,CM}}} |