From 7cdf5fc1ca658f826ed92019bca474c66206d96c Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 27 May 2011 16:34:41 +0200 Subject: OTP-9342: FTP client doesn't work with IPv6 OTP-9342: IpFamily config option was not handled OTP-9342: Release notes remain... OTP-9342: attila rajmund nohl --- lib/inets/Makefile | 4 ++++ lib/inets/src/ftp/ftp.erl | 4 +++- lib/inets/src/inets_app/inets.appup.src | 10 ++++++++++ lib/inets/test/inets_test_lib.erl | 9 ++++++--- lib/inets/vsn.mk | 2 +- 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/lib/inets/Makefile b/lib/inets/Makefile index ec05efa461..f4c2746b0a 100644 --- a/lib/inets/Makefile +++ b/lib/inets/Makefile @@ -36,6 +36,8 @@ SPECIAL_TARGETS = # ---------------------------------------------------- include $(ERL_TOP)/make/otp_subdir.mk +.PHONY: info gclean + info: @echo "OS: $(OS)" @echo "DOCB: $(DOCB)" @@ -44,3 +46,5 @@ info: @echo "APP_VSN: $(APP_VSN)" @echo "" +gclean: + git clean -fXd diff --git a/lib/inets/src/ftp/ftp.erl b/lib/inets/src/ftp/ftp.erl index fe6cb0c191..ac72963347 100644 --- a/lib/inets/src/ftp/ftp.erl +++ b/lib/inets/src/ftp/ftp.erl @@ -1038,10 +1038,12 @@ handle_call({_, {open, ip_comm, Opts}}, From, State) -> Port = key_search(port, Opts, ?FTP_PORT), Timeout = key_search(timeout, Opts, ?CONNECTION_TIMEOUT), Progress = key_search(progress, Opts, ignore), + IpFamily = key_search(ipfamily, Opts, inet), State2 = State#state{client = From, mode = Mode, - progress = progress(Progress)}, + progress = progress(Progress), + ipfamily = IpFamily}, ?fcrd("handle_call(open) -> setup ctrl connection with", [{host, Host}, {port, Port}, {timeout, Timeout}]), diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src index 47f3fbba58..09356caa22 100644 --- a/lib/inets/src/inets_app/inets.appup.src +++ b/lib/inets/src/inets_app/inets.appup.src @@ -18,6 +18,11 @@ {"%VSN%", [ + {"5.6", + [ + {update, ftp, soft, soft_purge, soft_purge, []} + ] + }, {"5.5.2", [ {restart_application, inets} @@ -40,6 +45,11 @@ } ], [ + {"5.6", + [ + {update, ftp, soft, soft_purge, soft_purge, []} + ] + }, {"5.5.2", [ {restart_application, inets} diff --git a/lib/inets/test/inets_test_lib.erl b/lib/inets/test/inets_test_lib.erl index 6cedaf9638..57e5d482c9 100644 --- a/lib/inets/test/inets_test_lib.erl +++ b/lib/inets/test/inets_test_lib.erl @@ -303,7 +303,7 @@ connect_byte(ossl, Host, Port) -> connect_byte(essl, Host, Port) -> connect(ssl, Host, Port, [{ssl_imp, new}, {packet,0}]); connect_byte(ip_comm, Host, Port) -> - Opts = [inet6, {packet,0}], + Opts = [inet6, {packet, 0}], connect(ip_comm, Host, Port, Opts). @@ -327,10 +327,13 @@ connect(ip_comm, Host, Port, Opts) -> tsp("nxdomain opts: ~p", [Opts]), connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); {error, eafnosupport} -> - tsp("eafnosupport opts: ~p", [Opts]), + tsp("eafnosupport when opts: ~p", [Opts]), + connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); + {error, econnreset} -> + tsp("econnreset when opts: ~p", [Opts]), connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); {error, enetunreach} -> - tsp("eafnosupport opts: ~p", [Opts]), + tsp("eafnosupport when opts: ~p", [Opts]), connect(ip_comm, Host, Port, lists:delete(inet6, Opts)); {error, {enfile,_}} -> tsp("Error enfile"), diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk index c0e25a30e3..2bb4d83c49 100644 --- a/lib/inets/vsn.mk +++ b/lib/inets/vsn.mk @@ -18,7 +18,7 @@ # %CopyrightEnd% APPLICATION = inets -INETS_VSN = 5.6 +INETS_VSN = 5.6.1 PRE_VSN = APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)" -- cgit v1.2.3 From 1e69822bac15f0a3eb4084fb56beb1bb6d7decd8 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 30 May 2011 15:29:43 +0200 Subject: Peer/sockname resolv doesn't work with IPv6 addrs in HTTP. OTP-9343 --- lib/inets/doc/src/notes.xml | 41 ++++++++++++++++++++ lib/inets/src/http_lib/http_transport.erl | 64 ++++++++++++++++--------------- lib/inets/src/inets_app/inets.appup.src | 10 +++++ lib/inets/vsn.mk | 2 +- 4 files changed, 86 insertions(+), 31 deletions(-) diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml index 0926df8581..0d531affa0 100644 --- a/lib/inets/doc/src/notes.xml +++ b/lib/inets/doc/src/notes.xml @@ -32,6 +32,47 @@ notes.xml +
Inets 5.6.1 + +
Improvements and New Features +

-

+ + + +
+ +
Fixed Bugs and Malfunctions + + + + +

[httpd] Peer/sockname resolv doesn't work with IPv6 addrs + in HTTP.

+

Attila Rajmund Nohl.

+

Own Id: OTP-9343

+
+ +
+
+ +
+ +
Inets 5.6
Improvements and New Features diff --git a/lib/inets/src/http_lib/http_transport.erl b/lib/inets/src/http_lib/http_transport.erl index 01b51d531a..6c2ffc143d 100644 --- a/lib/inets/src/http_lib/http_transport.erl +++ b/lib/inets/src/http_lib/http_transport.erl @@ -500,19 +500,11 @@ close({essl, _}, Socket) -> %%------------------------------------------------------------------------- peername(ip_comm, Socket) -> case inet:peername(Socket) of - {ok,{{A, B, C, D}, Port}} -> - PeerName = integer_to_list(A)++"."++integer_to_list(B)++"."++ - integer_to_list(C)++"."++integer_to_list(D), + {ok, {Addr, Port}} when is_tuple(Addr) andalso (size(Addr) =:= 4) -> + PeerName = ipv4_name(Addr), {Port, PeerName}; - {ok,{{A, B, C, D, E, F, G, H}, Port}} -> - PeerName = http_util:integer_to_hexlist(A) ++ ":"++ - http_util:integer_to_hexlist(B) ++ ":" ++ - http_util:integer_to_hexlist(C) ++ ":" ++ - http_util:integer_to_hexlist(D) ++ ":" ++ - http_util:integer_to_hexlist(E) ++ ":" ++ - http_util:integer_to_hexlist(F) ++ ":" ++ - http_util:integer_to_hexlist(G) ++":"++ - http_util:integer_to_hexlist(H), + {ok, {Addr, Port}} when is_tuple(Addr) andalso (size(Addr) =:= 8) -> + PeerName = ipv6_name(Addr), {Port, PeerName}; {error, _} -> {-1, "unknown"} @@ -530,9 +522,11 @@ peername({essl, _}, Socket) -> peername_ssl(Socket) -> case ssl:peername(Socket) of - {ok,{{A, B, C, D}, Port}} -> - PeerName = integer_to_list(A)++"."++integer_to_list(B)++"."++ - integer_to_list(C)++"."++integer_to_list(D), + {ok, {Addr, Port}} when is_tuple(Addr) andalso (size(Addr) =:= 4) -> + PeerName = ipv4_name(Addr), + {Port, PeerName}; + {ok, {Addr, Port}} when is_tuple(Addr) andalso (size(Addr) =:= 8) -> + PeerName = ipv6_name(Addr), {Port, PeerName}; {error, _} -> {-1, "unknown"} @@ -551,19 +545,11 @@ peername_ssl(Socket) -> %%------------------------------------------------------------------------- sockname(ip_comm, Socket) -> case inet:sockname(Socket) of - {ok,{{A, B, C, D}, Port}} -> - SockName = integer_to_list(A)++"."++integer_to_list(B)++"."++ - integer_to_list(C)++"."++integer_to_list(D), + {ok, {Addr, Port}} -> + SockName = ipv4_name(Addr), {Port, SockName}; - {ok,{{A, B, C, D, E, F, G, H}, Port}} -> - SockName = http_util:integer_to_hexlist(A) ++ ":"++ - http_util:integer_to_hexlist(B) ++ ":" ++ - http_util:integer_to_hexlist(C) ++ ":" ++ - http_util:integer_to_hexlist(D) ++ ":" ++ - http_util:integer_to_hexlist(E) ++ ":" ++ - http_util:integer_to_hexlist(F) ++ ":" ++ - http_util:integer_to_hexlist(G) ++":"++ - http_util:integer_to_hexlist(H), + {ok, {Addr, Port}} -> + SockName = ipv6_name(Addr), {Port, SockName}; {error, _} -> {-1, "unknown"} @@ -581,9 +567,11 @@ sockname({essl, _}, Socket) -> sockname_ssl(Socket) -> case ssl:sockname(Socket) of - {ok,{{A, B, C, D}, Port}} -> - SockName = integer_to_list(A)++"."++integer_to_list(B)++"."++ - integer_to_list(C)++"."++integer_to_list(D), + {ok, {Addr, Port}} -> + SockName = ipv4_name(Addr), + {Port, SockName}; + {ok, {Addr, Port}} -> + SockName = ipv6_name(Addr), {Port, SockName}; {error, _} -> {-1, "unknown"} @@ -605,6 +593,22 @@ resolve() -> %%% Internal functions %%%======================================================================== +ipv4_name({A, B, C, D}) -> + integer_to_list(A) ++ "." ++ + integer_to_list(B) ++ "." ++ + integer_to_list(C) ++ "." ++ + integer_to_list(D). + +ipv6_name({A, B, C, D, E, F, G, H}) -> + http_util:integer_to_hexlist(B) ++ ":" ++ + http_util:integer_to_hexlist(C) ++ ":" ++ + http_util:integer_to_hexlist(D) ++ ":" ++ + http_util:integer_to_hexlist(E) ++ ":" ++ + http_util:integer_to_hexlist(F) ++ ":" ++ + http_util:integer_to_hexlist(G) ++ ":" ++ + http_util:integer_to_hexlist(H). + + %% Address any comes from directive: BindAddress "*" sock_opt(ip_comm, any = Addr, Opts) -> sock_opt2([{ip, Addr} | Opts]); diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src index 47f3fbba58..c432ac82eb 100644 --- a/lib/inets/src/inets_app/inets.appup.src +++ b/lib/inets/src/inets_app/inets.appup.src @@ -18,6 +18,11 @@ {"%VSN%", [ + {"5.6", + [ + {load_module, http_transport, soft_purge, soft_purge, []} + ] + }, {"5.5.2", [ {restart_application, inets} @@ -40,6 +45,11 @@ } ], [ + {"5.6", + [ + {load_module, http_transport, soft_purge, soft_purge, []} + ] + }, {"5.5.2", [ {restart_application, inets} diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk index c0e25a30e3..2bb4d83c49 100644 --- a/lib/inets/vsn.mk +++ b/lib/inets/vsn.mk @@ -18,7 +18,7 @@ # %CopyrightEnd% APPLICATION = inets -INETS_VSN = 5.6 +INETS_VSN = 5.6.1 PRE_VSN = APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)" -- cgit v1.2.3 From 7f4b3f6b9e6d2306b58bcf071a17968b43186cdd Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 31 May 2011 13:30:49 +0200 Subject: Updated release notes. --- lib/inets/doc/src/notes.xml | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml index 0926df8581..8d27dee8dd 100644 --- a/lib/inets/doc/src/notes.xml +++ b/lib/inets/doc/src/notes.xml @@ -32,6 +32,40 @@ notes.xml +
Inets 5.6.1 + +
Improvements and New Features +

-

+ + +
+ +
Fixed Bugs and Malfunctions + + + + +

[ftp] FTP client doesn't work with IPv6 host.

+

Attila Rajmund Nohl

+

Own Id: OTP-9342 Aux Id: seq11853

+
+ +
+
+ +
+ +
Inets 5.6
Improvements and New Features -- cgit v1.2.3 From 4384c7137cb016b8b3cb9dd4d8ee82870c08f98c Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 15 Jun 2011 11:41:18 +0200 Subject: Set proper version (5.7). --- lib/inets/doc/src/notes.xml | 4 ++-- lib/inets/vsn.mk | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml index 0d531affa0..9071a72266 100644 --- a/lib/inets/doc/src/notes.xml +++ b/lib/inets/doc/src/notes.xml @@ -32,7 +32,7 @@ notes.xml -
Inets 5.6.1 +
Inets 5.7
Improvements and New Features

-

@@ -70,7 +70,7 @@
-
+
Inets 5.6 diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk index 2bb4d83c49..4abc1733d3 100644 --- a/lib/inets/vsn.mk +++ b/lib/inets/vsn.mk @@ -18,7 +18,7 @@ # %CopyrightEnd% APPLICATION = inets -INETS_VSN = 5.6.1 +INETS_VSN = 5.7 PRE_VSN = APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)" -- cgit v1.2.3 From dfaf00eb4fb11cdb8470401c47b15d8068b9f8cd Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 15 Jun 2011 13:23:21 +0200 Subject: Set proper version (5.7). --- lib/inets/doc/src/notes.xml | 4 ++-- lib/inets/vsn.mk | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml index 8d27dee8dd..c058f57352 100644 --- a/lib/inets/doc/src/notes.xml +++ b/lib/inets/doc/src/notes.xml @@ -32,7 +32,7 @@ notes.xml -
Inets 5.6.1 +
Inets 5.7
Improvements and New Features

-

@@ -63,7 +63,7 @@
-
+
Inets 5.6 diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk index 2bb4d83c49..4abc1733d3 100644 --- a/lib/inets/vsn.mk +++ b/lib/inets/vsn.mk @@ -18,7 +18,7 @@ # %CopyrightEnd% APPLICATION = inets -INETS_VSN = 5.6.1 +INETS_VSN = 5.7 PRE_VSN = APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)" -- cgit v1.2.3 From e4605d7a3b9f9be9e437689a79df0f568df8fdac Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 15 Jun 2011 17:14:54 +0200 Subject: [httpc] Remove unnecessary usage of iolist_to_binary when processing body (for PUT and POST). Filipe David Manana OTP-9317 --- lib/inets/doc/src/notes.xml | 40 +++++++++++++++++++++++++++++++++ lib/inets/src/http_client/httpc.erl | 14 +++++------- lib/inets/src/inets_app/inets.appup.src | 10 +++++++++ lib/inets/vsn.mk | 2 +- 4 files changed, 57 insertions(+), 9 deletions(-) diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml index 0926df8581..c9972b6755 100644 --- a/lib/inets/doc/src/notes.xml +++ b/lib/inets/doc/src/notes.xml @@ -32,6 +32,46 @@ notes.xml +
Inets 5.7 + +
Improvements and New Features +

-

+ + +
+ +
Fixed Bugs and Malfunctions + + + + +

[httpc] Remove unnecessary usage of iolist_to_binary when + processing body (for PUT and POST).

+

Filipe David Manana

+

Own Id: OTP-9317

+
+ +
+
+ +
+ +
Inets 5.6
Improvements and New Features diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl index 6ffa5e8ba5..8aaa9ec402 100644 --- a/lib/inets/src/http_client/httpc.erl +++ b/lib/inets/src/http_client/httpc.erl @@ -518,17 +518,15 @@ mk_chunkify_fun(ProcessBody) -> eof -> {ok, <<"0\r\n\r\n">>, eof_body}; {ok, Data, NewAcc} -> - {ok, mk_chunk_bin(Data), NewAcc} + Chunk = [ + integer_to_list(iolist_size(Data), 16), + "\r\n", + Data, + "\r\n"], + {ok, Chunk, NewAcc} end end. -mk_chunk_bin(Data) -> - Bin = iolist_to_binary(Data), - iolist_to_binary([hex_size(Bin), "\r\n", Bin, "\r\n"]). - -hex_size(Bin) -> - hd(io_lib:format("~.16B", [size(Bin)])). - handle_answer(RequestId, false, _) -> {ok, RequestId}; diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src index 47f3fbba58..260a0984f2 100644 --- a/lib/inets/src/inets_app/inets.appup.src +++ b/lib/inets/src/inets_app/inets.appup.src @@ -18,6 +18,11 @@ {"%VSN%", [ + {"5.6", + [ + {load_module, httpc, soft_purge, soft_purge, []} + ] + }, {"5.5.2", [ {restart_application, inets} @@ -40,6 +45,11 @@ } ], [ + {"5.6", + [ + {load_module, httpc, soft_purge, soft_purge, []} + ] + }, {"5.5.2", [ {restart_application, inets} diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk index c0e25a30e3..4abc1733d3 100644 --- a/lib/inets/vsn.mk +++ b/lib/inets/vsn.mk @@ -18,7 +18,7 @@ # %CopyrightEnd% APPLICATION = inets -INETS_VSN = 5.6 +INETS_VSN = 5.7 PRE_VSN = APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)" -- cgit v1.2.3 From 6d3f12f6921155ffbe5e5e5b84734657be97ff1c Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 1 Jun 2011 17:23:12 +0200 Subject: SSL with IPv6 now works "in principle". --- lib/inets/doc/src/notes.xml | 10 +- lib/inets/src/http_client/httpc_handler.erl | 13 +- lib/inets/src/http_client/httpc_manager.erl | 6 +- lib/inets/src/http_lib/http_transport.erl | 193 +++++++------- lib/inets/test/httpc_SUITE.erl | 383 +++++++++++++++++++++------- lib/inets/test/inets_test_lib.erl | 11 +- lib/inets/vsn.mk | 2 +- 7 files changed, 420 insertions(+), 198 deletions(-) diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml index 0d531affa0..ed1b974771 100644 --- a/lib/inets/doc/src/notes.xml +++ b/lib/inets/doc/src/notes.xml @@ -32,7 +32,7 @@ notes.xml -
Inets 5.6.1 +
Inets 5.7
Improvements and New Features

-

@@ -61,16 +61,14 @@ -

[httpd] Peer/sockname resolv doesn't work with IPv6 addrs - in HTTP.

-

Attila Rajmund Nohl.

-

Own Id: OTP-9343

+

[httpc|httpd] Added support for IPv6 with ssl.

+

Own Id: OTP-5566

-
+
Inets 5.6 diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl index 1f0e012e7e..9ac9ee6f7b 100644 --- a/lib/inets/src/http_client/httpc_handler.erl +++ b/lib/inets/src/http_client/httpc_handler.erl @@ -515,7 +515,7 @@ handle_info({Proto, _Socket, Data}, {stop, normal, NewState} end, - ?hcri("data processed", []), + ?hcri("data processed", [{final_result, FinalResult}]), FinalResult; @@ -629,8 +629,9 @@ handle_info(timeout_queue, #state{timers = Timers} = State) -> Timers#timers{queue_timer = undefined}}}; %% Setting up the connection to the server somehow failed. -handle_info({init_error, _, ClientErrMsg}, +handle_info({init_error, Tag, ClientErrMsg}, State = #state{request = Request}) -> + ?hcrv("init error", [{tag, Tag}, {client_error, ClientErrMsg}]), NewState = answer_request(Request, ClientErrMsg, State), {stop, normal, NewState}; @@ -707,9 +708,9 @@ terminate(normal, %% And, just in case, close our side (**really** overkill) http_transport:close(SocketType, Socket); -terminate(Reason, #state{session = #session{id = Id, - socket = Socket, - socket_type = SocketType}, +terminate(Reason, #state{session = #session{id = Id, + socket = Socket, + socket_type = SocketType}, request = undefined, profile_name = ProfileName, timers = Timers, @@ -1403,7 +1404,7 @@ try_to_enable_pipeline_or_keep_alive( answer_request(#request{id = RequestId, from = From} = Request, Msg, #state{timers = Timers, profile_name = ProfileName} = State) -> - ?hcrt("answer request", [{request, Request}]), + ?hcrt("answer request", [{request, Request}, {msg, Msg}]), httpc_response:send(From, Msg), RequestTimers = Timers#timers.request_timers, TimerRef = diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl index 7f66b477eb..9015bf1ce2 100644 --- a/lib/inets/src/http_client/httpc_manager.erl +++ b/lib/inets/src/http_client/httpc_manager.erl @@ -52,7 +52,7 @@ cancel = [], % [{RequestId, HandlerPid, ClientPid}] handler_db, % ets() - Entry: #handler_info{} cookie_db, % cookie_db() - session_db, % ets() - Entry: #tcp_session{} + session_db, % ets() - Entry: #session{} profile_name, % atom() options = #options{} }). @@ -178,7 +178,7 @@ request_done(RequestId, ProfileName) -> %%-------------------------------------------------------------------- %% Function: insert_session(Session, ProfileName) -> _ -%% Session - #tcp_session{} +%% Session - #session{} %% ProfileName - atom() %% %% Description: Inserts session information into the httpc manager @@ -669,7 +669,7 @@ select_session(Method, HostPort, Scheme, SessionType, (SessionType =:= keep_alive) of true -> %% Look for handlers connecting to this host (HostPort) - %% tcp_session with record name field (tcp_session) and + %% session with record name field (session) and %% socket fields ignored. The fields id (part of: HostPort), %% client_close, scheme and type specified. %% The fields id (part of: HandlerPid) and queue_length diff --git a/lib/inets/src/http_lib/http_transport.erl b/lib/inets/src/http_lib/http_transport.erl index 6c2ffc143d..9b8190ebed 100644 --- a/lib/inets/src/http_lib/http_transport.erl +++ b/lib/inets/src/http_lib/http_transport.erl @@ -33,8 +33,8 @@ peername/2, sockname/2, resolve/0 ]). - -export([negotiate/3]). +-export([ipv4_name/1, ipv6_name/1]). -include_lib("inets/src/inets_app/inets_internal.hrl"). -include("http_internal.hrl"). @@ -142,8 +142,8 @@ connect({ossl, SslConfig}, {Host, Port}, _, Timeout) -> ERROR end; -connect({essl, SslConfig}, {Host, Port}, _, Timeout) -> - Opts = [binary, {active, false}, {ssl_imp, new}] ++ SslConfig, +connect({essl, SslConfig}, {Host, Port}, Opts0, Timeout) -> + Opts = [binary, {active, false}, {ssl_imp, new} | Opts0] ++ SslConfig, ?hlrt("connect using essl", [{host, Host}, {port, Port}, @@ -176,8 +176,8 @@ connect({essl, SslConfig}, {Host, Port}, _, Timeout) -> listen(SocketType, Port) -> listen(SocketType, undefined, Port). -listen(ip_comm = SocketType, Addr, Port) -> - listen(SocketType, Addr, Port, undefined); +listen(ip_comm = _SocketType, Addr, Port) -> + listen_ip_comm(Addr, Port, undefined); %% Wrapper for backaward compatibillity listen({ssl, SSLConfig}, Addr, Port) -> @@ -187,35 +187,33 @@ listen({ssl, SSLConfig}, Addr, Port) -> {ssl_config, SSLConfig}]), listen({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Addr, Port); -listen({ossl, SSLConfig} = Ssl, Addr, Port) -> +listen({ossl, SSLConfig}, Addr, Port) -> ?hlrt("listen (ossl)", [{addr, Addr}, {port, Port}, {ssl_config, SSLConfig}]), - Opt = sock_opt(Ssl, Addr, SSLConfig), - ?hlrt("listen options", [{opt, Opt}]), - ssl:listen(Port, [{ssl_imp, old} | Opt]); + listen_ssl(Addr, Port, [{ssl_imp, old} | SSLConfig]); -listen({essl, SSLConfig} = Ssl, Addr, Port) -> +listen({essl, SSLConfig}, Addr, Port) -> ?hlrt("listen (essl)", [{addr, Addr}, {port, Port}, {ssl_config, SSLConfig}]), - Opt = sock_opt(Ssl, Addr, SSLConfig), - ?hlrt("listen options", [{opt, Opt}]), - Opt2 = [{ssl_imp, new}, {reuseaddr, true} | Opt], - ssl:listen(Port, Opt2). + listen_ssl(Addr, Port, [{ssl_imp, new}, {reuseaddr, true} | SSLConfig]). + listen(ip_comm, Addr, Port, Fd) -> - case (catch listen_ip_comm(Addr, Port, Fd)) of + listen_ip_comm(Addr, Port, Fd). + +listen_ip_comm(Addr, Port, Fd) -> + case (catch do_listen_ip_comm(Addr, Port, Fd)) of {'EXIT', Reason} -> {error, {exit, Reason}}; Else -> Else end. - -listen_ip_comm(Addr, Port, Fd) -> +do_listen_ip_comm(Addr, Port, Fd) -> {NewPort, Opts, IpFamily} = get_socket_info(Addr, Port, Fd), case IpFamily of inet6fb4 -> @@ -248,6 +246,41 @@ listen_ip_comm(Addr, Port, Fd) -> gen_tcp:listen(NewPort, Opts2) end. + +listen_ssl(Addr, Port, Opts0) -> + IpFamily = ipfamily_default(Addr, Port), + BaseOpts = [{backlog, 128}, {reuseaddr, true} | Opts0], + Opts = sock_opts(Addr, BaseOpts), + case IpFamily of + inet6fb4 -> + Opts2 = [inet6 | Opts], + ?hlrt("try ipv6 listen", [{opts, Opts2}]), + case (catch ssl:listen(Port, Opts2)) of + {error, Reason} when ((Reason =:= nxdomain) orelse + (Reason =:= eafnosupport)) -> + Opts3 = [inet | Opts], + ?hlrt("ipv6 listen failed - try ipv4 instead", + [{reason, Reason}, {opts, Opts3}]), + ssl:listen(Port, Opts3); + + {'EXIT', Reason} -> + Opts3 = [inet | Opts], + ?hlrt("ipv6 listen exit - try ipv4 instead", + [{reason, Reason}, {opts, Opts3}]), + ssl:listen(Port, Opts3); + + Other -> + ?hlrt("ipv6 listen done", [{other, Other}]), + Other + end; + + _ -> + Opts2 = [IpFamily | Opts], + ?hlrt("listen", [{opts, Opts2}]), + ssl:listen(Port, Opts2) + end. + + ipfamily_default(Addr, Port) -> httpd_conf:lookup(Addr, Port, ipfamily, inet6fb4). @@ -257,9 +290,9 @@ get_socket_info(Addr, Port, Fd0) -> %% The presence of a file descriptor takes precedence case get_fd(Port, Fd0, IpFamilyDefault) of {Fd, IpFamily} -> - {0, sock_opt(ip_comm, Addr, [{fd, Fd} | BaseOpts]), IpFamily}; + {0, sock_opts(Addr, [{fd, Fd} | BaseOpts]), IpFamily}; undefined -> - {Port, sock_opt(ip_comm, Addr, BaseOpts), IpFamilyDefault} + {Port, sock_opts(Addr, BaseOpts), IpFamilyDefault} end. get_fd(Port, undefined = _Fd, IpFamilyDefault) -> @@ -499,38 +532,28 @@ close({essl, _}, Socket) -> %% connection, usning either gen_tcp or ssl. %%------------------------------------------------------------------------- peername(ip_comm, Socket) -> - case inet:peername(Socket) of - {ok, {Addr, Port}} when is_tuple(Addr) andalso (size(Addr) =:= 4) -> - PeerName = ipv4_name(Addr), - {Port, PeerName}; - {ok, {Addr, Port}} when is_tuple(Addr) andalso (size(Addr) =:= 8) -> - PeerName = ipv6_name(Addr), - {Port, PeerName}; - {error, _} -> - {-1, "unknown"} - end; + do_peername(inet:peername(Socket)); %% Wrapper for backaward compatibillity peername({ssl, SSLConfig}, Socket) -> peername({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket); peername({ossl, _}, Socket) -> - peername_ssl(Socket); + do_peername(ssl:peername(Socket)); peername({essl, _}, Socket) -> - peername_ssl(Socket). - -peername_ssl(Socket) -> - case ssl:peername(Socket) of - {ok, {Addr, Port}} when is_tuple(Addr) andalso (size(Addr) =:= 4) -> - PeerName = ipv4_name(Addr), - {Port, PeerName}; - {ok, {Addr, Port}} when is_tuple(Addr) andalso (size(Addr) =:= 8) -> - PeerName = ipv6_name(Addr), - {Port, PeerName}; - {error, _} -> - {-1, "unknown"} - end. + do_peername(ssl:peername(Socket)). + +do_peername({ok, {Addr, Port}}) + when is_tuple(Addr) andalso (size(Addr) =:= 4) -> + PeerName = ipv4_name(Addr), + {Port, PeerName}; +do_peername({ok, {Addr, Port}}) + when is_tuple(Addr) andalso (size(Addr) =:= 8) -> + PeerName = ipv6_name(Addr), + {Port, PeerName}; +do_peername({error, _}) -> + {-1, "unknown"}. %%------------------------------------------------------------------------- @@ -544,38 +567,28 @@ peername_ssl(Socket) -> %% other end of connection, using either gen_tcp or ssl. %%------------------------------------------------------------------------- sockname(ip_comm, Socket) -> - case inet:sockname(Socket) of - {ok, {Addr, Port}} -> - SockName = ipv4_name(Addr), - {Port, SockName}; - {ok, {Addr, Port}} -> - SockName = ipv6_name(Addr), - {Port, SockName}; - {error, _} -> - {-1, "unknown"} - end; + do_sockname(inet:sockname(Socket)); %% Wrapper for backaward compatibillity sockname({ssl, SSLConfig}, Socket) -> sockname({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket); sockname({ossl, _}, Socket) -> - sockname_ssl(Socket); + do_sockname(ssl:sockname(Socket)); sockname({essl, _}, Socket) -> - sockname_ssl(Socket). - -sockname_ssl(Socket) -> - case ssl:sockname(Socket) of - {ok, {Addr, Port}} -> - SockName = ipv4_name(Addr), - {Port, SockName}; - {ok, {Addr, Port}} -> - SockName = ipv6_name(Addr), - {Port, SockName}; - {error, _} -> - {-1, "unknown"} - end. + do_sockname(ssl:sockname(Socket)). + +do_sockname({ok, {Addr, Port}}) + when is_tuple(Addr) andalso (size(Addr) =:= 4) -> + SockName = ipv4_name(Addr), + {Port, SockName}; +do_sockname({ok, {Addr, Port}}) + when is_tuple(Addr) andalso (size(Addr) =:= 8) -> + SockName = ipv6_name(Addr), + {Port, SockName}; +do_sockname({error, _}) -> + {-1, "unknown"}. %%------------------------------------------------------------------------- @@ -589,10 +602,14 @@ resolve() -> Name. -%%%======================================================================== -%%% Internal functions -%%%======================================================================== - +%%------------------------------------------------------------------------- +%% ipv4_name(Ipv4Addr) -> string() +%% ipv6_name(Ipv6Addr) -> string() +%% Ipv4Addr = ip4_address() +%% Ipv6Addr = ip6_address() +%% +%% Description: Returns the local hostname. +%%------------------------------------------------------------------------- ipv4_name({A, B, C, D}) -> integer_to_list(A) ++ "." ++ integer_to_list(B) ++ "." ++ @@ -600,7 +617,8 @@ ipv4_name({A, B, C, D}) -> integer_to_list(D). ipv6_name({A, B, C, D, E, F, G, H}) -> - http_util:integer_to_hexlist(B) ++ ":" ++ + http_util:integer_to_hexlist(A) ++ ":"++ + http_util:integer_to_hexlist(B) ++ ":" ++ http_util:integer_to_hexlist(C) ++ ":" ++ http_util:integer_to_hexlist(D) ++ ":" ++ http_util:integer_to_hexlist(E) ++ ":" ++ @@ -609,25 +627,24 @@ ipv6_name({A, B, C, D, E, F, G, H}) -> http_util:integer_to_hexlist(H). +%%%======================================================================== +%%% Internal functions +%%%======================================================================== + +%% -- sock_opts -- %% Address any comes from directive: BindAddress "*" -sock_opt(ip_comm, any = Addr, Opts) -> - sock_opt2([{ip, Addr} | Opts]); -sock_opt(ip_comm, undefined, Opts) -> - sock_opt2(Opts); -sock_opt(_, any = _Addr, Opts) -> - sock_opt2(Opts); -sock_opt(_, undefined = _Addr, Opts) -> - sock_opt2(Opts); -sock_opt(_, {_,_,_,_} = Addr, Opts) -> - sock_opt2([{ip, Addr} | Opts]); -sock_opt(ip_comm, Addr, Opts) -> - sock_opt2([{ip, Addr} | Opts]); -sock_opt(_, Addr, Opts) -> - sock_opt2([{ip, Addr} | Opts]). - -sock_opt2(Opts) -> +sock_opts(undefined, Opts) -> + sock_opts(Opts); +sock_opts(any = Addr, Opts) -> + sock_opts([{ip, Addr} | Opts]); +sock_opts(Addr, Opts) -> + sock_opts([{ip, Addr} | Opts]). + +sock_opts(Opts) -> [{packet, 0}, {active, false} | Opts]. + +%% -- negotiate -- negotiate(ip_comm,_,_) -> ?hlrt("negotiate(ip_comm)", []), ok; diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 1998bd3950..731e330ef7 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -113,14 +113,15 @@ all() -> proxy_stream, parse_url, options, - ipv6, headers_as_is, + {group, ipv6}, {group, tickets}, initial_server_connect ]. groups() -> - [{tickets, [], [hexed_query_otp_6191, + [ + {tickets, [], [hexed_query_otp_6191, empty_body_otp_6243, empty_response_header_otp_6830, transfer_encoding_otp_6807, @@ -139,7 +140,12 @@ groups() -> {otp_8154, [], [otp_8154_1]}, {otp_8106, [], [otp_8106_pid, otp_8106_fun, - otp_8106_mfa]}]. + otp_8106_mfa]}, + %% {ipv6, [], [ipv6_ipcomm, ipv6_essl, ipv6_ossl]} + {ipv6, [], [ipv6_ipcomm, ipv6_essl]} + %% {ipv6, [], [ipv6_ipcomm]} + ]. + init_per_group(_GroupName, Config) -> @@ -261,13 +267,16 @@ init_per_testcase(Case, Timeout, Config) -> NewConfig = case atom_to_list(Case) of [$s, $s, $l | _] -> - init_per_testcase_ssl(ssl, PrivDir, SslConfFile, [{watchdog, Dog} | TmpConfig]); + init_per_testcase_ssl(ssl, PrivDir, SslConfFile, + [{watchdog, Dog} | TmpConfig]); [$o, $s, $s, $l | _] -> - init_per_testcase_ssl(ossl, PrivDir, SslConfFile, [{watchdog, Dog} | TmpConfig]); + init_per_testcase_ssl(ossl, PrivDir, SslConfFile, + [{watchdog, Dog} | TmpConfig]); [$e, $s, $s, $l | _] -> - init_per_testcase_ssl(essl, PrivDir, SslConfFile, [{watchdog, Dog} | TmpConfig]); + init_per_testcase_ssl(essl, PrivDir, SslConfFile, + [{watchdog, Dog} | TmpConfig]); "proxy_" ++ Rest -> io:format("init_per_testcase -> Rest: ~p~n", [Rest]), @@ -321,6 +330,24 @@ init_per_testcase(Case, Timeout, Config) -> [{skip, "proxy not responding"} | TmpConfig] end end; + "ipv6_" ++ _Rest -> + %% Start httpc part of inets + CryptoStartRes = application:start(crypto), + PubKeyStartRes = application:start(public_key), + SSLStartRes = application:start(ssl), + tsp("App start result: " + "~n Crypto start result: ~p" + "~n PublicKey start result: ~p" + "~n SSL start result: ~p", + [CryptoStartRes, PubKeyStartRes, SSLStartRes]), + Profile = ipv6, + {ok, ProfilePid} = + inets:start(httpc, + [{profile, Profile}, + {data_dir, PrivDir}], stand_alone), + httpc:set_options([{ipfamily, inet6}], ProfilePid), + tsp("httpc profile pid: ~p", [ProfilePid]), + [{watchdog, Dog}, {profile, ProfilePid}| TmpConfig]; _ -> TmpConfig2 = lists:keydelete(local_server, 1, TmpConfig), Server = @@ -349,13 +376,28 @@ init_per_testcase(Case, Timeout, Config) -> %% A list of key/value pairs, holding the test case configuration. %% Description: Cleanup after each test case %%-------------------------------------------------------------------- -end_per_testcase(http_save_to_file, Config) -> - PrivDir = ?config(priv_dir, Config), +end_per_testcase(http_save_to_file = Case, Config) -> + io:format(user, "~n~n*** END ~w:~w ***~n~n", + [?MODULE, Case]), + PrivDir = ?config(priv_dir, Config), FullPath = filename:join(PrivDir, "dummy.html"), file:delete(FullPath), finish(Config); -end_per_testcase(_, Config) -> +end_per_testcase(Case, Config) -> + io:format(user, "~n~n*** END ~w:~w ***~n~n", + [?MODULE, Case]), + case atom_to_list(Case) of + "ipv6_" ++ _Rest -> + application:stop(ssl), + application:stop(public_key), + application:stop(crypto), + ProfilePid = ?config(profile, Config), + inets:stop(stand_alone, ProfilePid), + ok; + _ -> + ok + end, finish(Config). finish(Config) -> @@ -565,7 +607,7 @@ http_relaxed(suite) -> http_relaxed(Config) when is_list(Config) -> ok = httpc:set_options([{ipv6, disabled}]), % also test the old option %% ok = httpc:set_options([{ipfamily, inet}]), - {DummyServerPid, Port} = dummy_server(self(), ipv4), + {DummyServerPid, Port} = dummy_server(ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/missing_reason_phrase.html", @@ -591,7 +633,7 @@ http_dummy_pipe(suite) -> []; http_dummy_pipe(Config) when is_list(Config) -> ok = httpc:set_options([{ipfamily, inet}]), - {DummyServerPid, Port} = dummy_server(self(), ipv4), + {DummyServerPid, Port} = dummy_server(ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/foobar.html", @@ -905,7 +947,7 @@ http_headers_dummy(suite) -> []; http_headers_dummy(Config) when is_list(Config) -> ok = httpc:set_options([{ipfamily, inet}]), - {DummyServerPid, Port} = dummy_server(self(), ipv4), + {DummyServerPid, Port} = dummy_server(ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy_headers.html", @@ -970,7 +1012,7 @@ http_bad_response(suite) -> []; http_bad_response(Config) when is_list(Config) -> ok = httpc:set_options([{ipfamily, inet}]), - {DummyServerPid, Port} = dummy_server(self(), ipv4), + {DummyServerPid, Port} = dummy_server(ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/missing_crlf.html", @@ -1170,7 +1212,7 @@ http_redirect(Config) when is_list(Config) -> ok = httpc:set_options([{ipfamily, inet}]), tsp("http_redirect -> start dummy server inet"), - {DummyServerPid, Port} = dummy_server(self(), ipv4), + {DummyServerPid, Port} = dummy_server(ipv4), tsp("http_redirect -> server port = ~p", [Port]), URL300 = ?URL_START ++ integer_to_list(Port) ++ "/300.html", @@ -1282,7 +1324,7 @@ http_redirect_loop(suite) -> []; http_redirect_loop(Config) when is_list(Config) -> ok = httpc:set_options([{ipfamily, inet}]), - {DummyServerPid, Port} = dummy_server(self(), ipv4), + {DummyServerPid, Port} = dummy_server(ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/redirectloop.html", @@ -1299,7 +1341,7 @@ http_internal_server_error(suite) -> []; http_internal_server_error(Config) when is_list(Config) -> ok = httpc:set_options([{ipfamily, inet}]), - {DummyServerPid, Port} = dummy_server(self(), ipv4), + {DummyServerPid, Port} = dummy_server(ipv4), URL500 = ?URL_START ++ integer_to_list(Port) ++ "/500.html", @@ -1335,7 +1377,7 @@ http_userinfo(suite) -> http_userinfo(Config) when is_list(Config) -> ok = httpc:set_options([{ipfamily, inet}]), - {DummyServerPid, Port} = dummy_server(self(), ipv4), + {DummyServerPid, Port} = dummy_server(ipv4), URLAuth = "http://alladin:sesame@localhost:" ++ integer_to_list(Port) ++ "/userinfo.html", @@ -1361,7 +1403,7 @@ http_cookie(suite) -> []; http_cookie(Config) when is_list(Config) -> ok = httpc:set_options([{cookies, enabled}, {ipfamily, inet}]), - {DummyServerPid, Port} = dummy_server(self(), ipv4), + {DummyServerPid, Port} = dummy_server(ipv4), URLStart = ?URL_START ++ integer_to_list(Port), @@ -1735,7 +1777,7 @@ http_stream_once(Config) when is_list(Config) -> p("http_stream_once -> set ipfamily to inet", []), ok = httpc:set_options([{ipfamily, inet}]), p("http_stream_once -> start dummy server", []), - {DummyServerPid, Port} = dummy_server(self(), ipv4), + {DummyServerPid, Port} = dummy_server(ipv4), PortStr = integer_to_list(Port), p("http_stream_once -> once", []), @@ -1871,28 +1913,95 @@ parse_url(Config) when is_list(Config) -> %%------------------------------------------------------------------------- -ipv6() -> - [{require,ipv6_hosts}]. -ipv6(doc) -> - ["Test ipv6."]; -ipv6(suite) -> + +ipv6_ipcomm() -> + %% [{require, ipv6_hosts}]. + []. +ipv6_ipcomm(doc) -> + ["Test ip_comm ipv6."]; +ipv6_ipcomm(suite) -> []; -ipv6(Config) when is_list(Config) -> - {ok, Hostname} = inet:gethostname(), - - case lists:member(list_to_atom(Hostname), - ct:get_config(ipv6_hosts)) of - true -> - {DummyServerPid, Port} = dummy_server(self(), ipv6), - - URL = "http://[" ++ ?IPV6_LOCAL_HOST ++ "]:" ++ +ipv6_ipcomm(Config) when is_list(Config) -> + HTTPOptions = [], + SocketType = ip_comm, + Scheme = "http", + Extra = [], + ipv6(SocketType, Scheme, HTTPOptions, Extra, Config). + + +%%------------------------------------------------------------------------- + +ipv6_essl() -> + %% [{require, ipv6_hosts}]. + []. +ipv6_essl(doc) -> + ["Test essl ipv6."]; +ipv6_essl(suite) -> + []; +ipv6_essl(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + CertFile = filename:join(DataDir, "ssl_client_cert.pem"), + SSLOptions = [{certfile, CertFile}, {keyfile, CertFile}], + SSLConfig = {essl, SSLOptions}, + tsp("ssl_ipv6 -> make request using: " + "~n SSLOptions: ~p", [SSLOptions]), + HTTPOptions = [{ssl, SSLConfig}], + SocketType = essl, + Scheme = "https", + Extra = SSLOptions, + ipv6(SocketType, Scheme, HTTPOptions, Extra, Config). + + +%%------------------------------------------------------------------------- + +%% ipv6_ossl() -> +%% %% [{require, ipv6_hosts}]. +%% []. +%% ipv6_ossl(doc) -> +%% ["Test ossl ipv6."]; +%% ipv6_ossl(suite) -> +%% []; +%% ipv6_ossl(Config) when is_list(Config) -> +%% DataDir = ?config(data_dir, Config), +%% CertFile = filename:join(DataDir, "ssl_client_cert.pem"), +%% SSLOptions = [{certfile, CertFile}, {keyfile, CertFile}], +%% SSLConfig = {ossl, SSLOptions}, +%% tsp("ossl_ipv6 -> make request using: " +%% "~n SSLOptions: ~p", [SSLOptions]), +%% HTTPOptions = [{ssl, SSLConfig}], +%% SocketType = ossl, +%% Scheme = "https", +%% ipv6(SocketType, Scheme, HTTPOptions, Config). + + +%%------------------------------------------------------------------------- + +ipv6(SocketType, Scheme, HTTPOptions, Extra, Config) -> + %% Check if we are a IPv6 host + tsp("ipv6 -> verify ipv6 support", []), + case inets_test_lib:has_ipv6_support() of + {ok, Addr} -> + tsp("ipv6 -> ipv6 supported: ~p", [Addr]), + {DummyServerPid, Port} = dummy_server(SocketType, ipv6, Extra), + Profile = ?config(profile, Config), + URL = + Scheme ++ + "://[" ++ http_transport:ipv6_name(Addr) ++ "]:" ++ integer_to_list(Port) ++ "/foobar.html", - {ok, {{_,200,_}, [_ | _], [_|_]}} = - httpc:request(get, {URL, []}, [], []), - - DummyServerPid ! stop, + tsp("ipv6 -> issue request with: " + "~n URL: ~p" + "~n HTTPOptions: ~p", [URL, HTTPOptions]), + case httpc:request(get, {URL, []}, HTTPOptions, [], Profile) of + {ok, {{_,200,_}, [_ | _], [_|_]}} -> + DummyServerPid ! stop, + ok; + {error, Reason} -> + DummyServerPid ! stop, + tsf(Reason) + end, ok; - false -> + _ -> + tsp("ipv6 -> ipv6 not supported", []), {skip, "Host does not support IPv6"} end. @@ -1945,7 +2054,7 @@ http_invalid_http(suite) -> []; http_invalid_http(Config) when is_list(Config) -> ok = httpc:set_options([{ipfamily, inet}]), - {DummyServerPid, Port} = dummy_server(self(), ipv4), + {DummyServerPid, Port} = dummy_server(ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/invalid_http.html", @@ -2002,7 +2111,7 @@ transfer_encoding_otp_6807(suite) -> []; transfer_encoding_otp_6807(Config) when is_list(Config) -> ok = httpc:set_options([{ipfamily, inet}]), - {DummyServerPid, Port} = dummy_server(self(), ipv4), + {DummyServerPid, Port} = dummy_server(ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/capital_transfer_encoding.html", @@ -2035,7 +2144,7 @@ empty_response_header_otp_6830(suite) -> []; empty_response_header_otp_6830(Config) when is_list(Config) -> ok = httpc:set_options([{ipfamily, inet}]), - {DummyServerPid, Port} = dummy_server(self(), ipv4), + {DummyServerPid, Port} = dummy_server(ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/no_headers.html", {ok, {{_,200,_}, [], [_ | _]}} = httpc:request(URL), @@ -2052,7 +2161,7 @@ no_content_204_otp_6982(suite) -> []; no_content_204_otp_6982(Config) when is_list(Config) -> ok = httpc:set_options([{ipfamily, inet}]), - {DummyServerPid, Port} = dummy_server(self(), ipv4), + {DummyServerPid, Port} = dummy_server(ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/no_content.html", {ok, {{_,204,_}, [], []}} = httpc:request(URL), @@ -2070,7 +2179,7 @@ missing_CR_otp_7304(suite) -> []; missing_CR_otp_7304(Config) when is_list(Config) -> ok = httpc:set_options([{ipfamily, inet}]), - {DummyServerPid, Port} = dummy_server(self(), ipv4), + {DummyServerPid, Port} = dummy_server(ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/missing_CR.html", {ok, {{_,200,_}, _, [_ | _]}} = httpc:request(URL), @@ -2089,7 +2198,7 @@ otp_7883_1(suite) -> otp_7883_1(Config) when is_list(Config) -> ok = httpc:set_options([{ipfamily, inet}]), - {DummyServerPid, Port} = dummy_server(self(), ipv4), + {DummyServerPid, Port} = dummy_server(ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/just_close.html", {error, socket_closed_remotely} = httpc:request(URL), @@ -2105,7 +2214,7 @@ otp_7883_2(suite) -> otp_7883_2(Config) when is_list(Config) -> ok = httpc:set_options([{ipfamily, inet}]), - {DummyServerPid, Port} = dummy_server(self(), ipv4), + {DummyServerPid, Port} = dummy_server(ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/just_close.html", Method = get, @@ -2626,7 +2735,7 @@ otp_8371(suite) -> []; otp_8371(Config) when is_list(Config) -> ok = httpc:set_options([{ipv6, disabled}]), % also test the old option - {DummyServerPid, Port} = dummy_server(self(), ipv4), + {DummyServerPid, Port} = dummy_server(ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/ensure_host_header_with_port.html", @@ -2866,73 +2975,159 @@ receive_streamed_body(RequestId, Body, Pid) -> -dummy_server(Caller, IpV) -> - Pid = spawn(httpc_SUITE, dummy_server_init, [Caller, IpV]), +dummy_server(IpV) -> + dummy_server(self(), ip_comm, IpV, []). + +dummy_server(SocketType, IpV, Extra) -> + dummy_server(self(), SocketType, IpV, Extra). + +dummy_server(Caller, SocketType, IpV, Extra) -> + Args = [Caller, SocketType, IpV, Extra], + Pid = spawn(httpc_SUITE, dummy_server_init, Args), receive {port, Port} -> {Pid, Port} end. -dummy_server_init(Caller, IpV) -> +dummy_server_init(Caller, ip_comm, IpV, _) -> + BaseOpts = [binary, {packet, 0}, {reuseaddr,true}, {active, false}], {ok, ListenSocket} = case IpV of ipv4 -> - gen_tcp:listen(0, [binary, inet, {packet, 0}, - {reuseaddr,true}, - {active, false}]); + tsp("ip_comm ipv4 listen", []), + gen_tcp:listen(0, [inet | BaseOpts]); ipv6 -> - gen_tcp:listen(0, [binary, inet6, {packet, 0}, - {reuseaddr,true}, - {active, false}]) + tsp("ip_comm ipv6 listen", []), + gen_tcp:listen(0, [inet6 | BaseOpts]) end, {ok, Port} = inet:port(ListenSocket), - tsp("dummy_server_init -> Port: ~p", [Port]), + tsp("dummy_server_init(ip_comm) -> Port: ~p", [Port]), Caller ! {port, Port}, - dummy_server_loop({httpd_request, parse, [?HTTP_MAX_HEADER_SIZE]}, - [], ListenSocket). + dummy_ipcomm_server_loop({httpd_request, parse, [?HTTP_MAX_HEADER_SIZE]}, + [], ListenSocket); +dummy_server_init(Caller, essl, IpV, SSLOptions) -> + BaseOpts = [{ssl_imp, new}, + {backlog, 128}, binary, {reuseaddr,true}, {active, false} | + SSLOptions], + dummy_ssl_server_init(Caller, BaseOpts, IpV); +dummy_server_init(Caller, ossl, IpV, SSLOptions) -> + BaseOpts = [{ssl_imp, old}, + {backlog, 128}, binary, {active, false} | SSLOptions], + dummy_ssl_server_init(Caller, BaseOpts, IpV). + +dummy_ssl_server_init(Caller, BaseOpts, IpV) -> + {ok, ListenSocket} = + case IpV of + ipv4 -> + tsp("dummy_ssl_server_init -> ssl ipv4 listen", []), + ssl:listen(0, [inet | BaseOpts]); + ipv6 -> + tsp("dummy_ssl_server_init -> ssl ipv6 listen", []), + ssl:listen(0, [inet6 | BaseOpts]) + end, + tsp("dummy_ssl_server_init -> ListenSocket: ~p", [ListenSocket]), + {ok, {_, Port}} = ssl:sockname(ListenSocket), + tsp("dummy_ssl_server_init -> Port: ~p", [Port]), + Caller ! {port, Port}, + dummy_ssl_server_loop({httpd_request, parse, [?HTTP_MAX_HEADER_SIZE]}, + [], ListenSocket). -dummy_server_loop(MFA, Handlers, ListenSocket) -> +dummy_ipcomm_server_loop(MFA, Handlers, ListenSocket) -> receive stop -> + tsp("dummy_ipcomm_server_loop -> stop handlers", []), lists:foreach(fun(Handler) -> Handler ! stop end, Handlers) after 0 -> + tsp("dummy_ipcomm_server_loop -> await accept", []), {ok, Socket} = gen_tcp:accept(ListenSocket), + tsp("dummy_ipcomm_server_loop -> accepted: ~p", [Socket]), HandlerPid = dummy_request_handler(MFA, Socket), + tsp("dummy_icomm_server_loop -> handler created: ~p", [HandlerPid]), gen_tcp:controlling_process(Socket, HandlerPid), - HandlerPid ! controller, - dummy_server_loop(MFA, [HandlerPid | Handlers], + tsp("dummy_ipcomm_server_loop -> " + "control transfered to handler", []), + HandlerPid ! ipcomm_controller, + tsp("dummy_ipcomm_server_loop -> " + "handler informed about control transfer", []), + dummy_ipcomm_server_loop(MFA, [HandlerPid | Handlers], ListenSocket) end. +dummy_ssl_server_loop(MFA, Handlers, ListenSocket) -> + receive + stop -> + tsp("dummy_ssl_server_loop -> stop handlers", []), + lists:foreach(fun(Handler) -> Handler ! stop end, Handlers) + after 0 -> + tsp("dummy_ssl_server_loop -> await accept", []), + {ok, Socket} = ssl:transport_accept(ListenSocket), + tsp("dummy_ssl_server_loop -> accepted: ~p", [Socket]), + HandlerPid = dummy_request_handler(MFA, Socket), + tsp("dummy_ssl_server_loop -> handler created: ~p", [HandlerPid]), + ssl:controlling_process(Socket, HandlerPid), + tsp("dummy_ssl_server_loop -> control transfered to handler", []), + HandlerPid ! ssl_controller, + tsp("dummy_ssl_server_loop -> " + "handler informed about control transfer", []), + dummy_ssl_server_loop(MFA, [HandlerPid | Handlers], + ListenSocket) + end. + dummy_request_handler(MFA, Socket) -> + tsp("spawn request handler", []), spawn(httpc_SUITE, dummy_request_handler_init, [MFA, Socket]). dummy_request_handler_init(MFA, Socket) -> - receive - controller -> - inet:setopts(Socket, [{active, true}]) - end, - dummy_request_handler_loop(MFA, Socket). + SockType = + receive + ipcomm_controller -> + tsp("dummy_request_handler_init -> " + "received ip_comm controller - activate", []), + inet:setopts(Socket, [{active, true}]), + ip_comm; + ssl_controller -> + tsp("dummy_request_handler_init -> " + "received ssl controller - activate", []), + ssl:setopts(Socket, [{active, true}]), + ssl + end, + dummy_request_handler_loop(MFA, SockType, Socket). -dummy_request_handler_loop({Module, Function, Args}, Socket) -> +dummy_request_handler_loop({Module, Function, Args}, SockType, Socket) -> tsp("dummy_request_handler_loop -> entry with" "~n Module: ~p" "~n Function: ~p" "~n Args: ~p", [Module, Function, Args]), receive - {tcp, _, Data} -> - tsp("dummy_request_handler_loop -> Data ~p", [Data]), - case handle_request(Module, Function, [Data | Args], Socket) of - stop -> + {Proto, _, Data} when (Proto =:= tcp) orelse (Proto =:= ssl) -> + tsp("dummy_request_handler_loop -> [~w] Data ~p", [Proto, Data]), + case handle_request(Module, Function, [Data | Args], Socket, Proto) of + stop when Proto =:= tcp -> gen_tcp:close(Socket); + stop when Proto =:= ssl -> + ssl:close(Socket); NewMFA -> - dummy_request_handler_loop(NewMFA, Socket) + dummy_request_handler_loop(NewMFA, SockType, Socket) end; - stop -> - gen_tcp:close(Socket) + stop when SockType =:= ip_comm -> + gen_tcp:close(Socket); + stop when SockType =:= ssl -> + ssl:close(Socket) end. -handle_request(Module, Function, Args, Socket) -> + +mk_close(tcp) -> fun(Sock) -> gen_tcp:close(Sock) end; +mk_close(ssl) -> fun(Sock) -> ssl:close(Sock) end. + +mk_send(tcp) -> fun(Sock, Data) -> gen_tcp:send(Sock, Data) end; +mk_send(ssl) -> fun(Sock, Data) -> ssl:send(Sock, Data) end. + +handle_request(Module, Function, Args, Socket, Proto) -> + Close = mk_close(Proto), + Send = mk_send(Proto), + handle_request(Module, Function, Args, Socket, Close, Send). + +handle_request(Module, Function, Args, Socket, Close, Send) -> tsp("handle_request -> entry with" "~n Module: ~p" "~n Function: ~p" @@ -2941,7 +3136,7 @@ handle_request(Module, Function, Args, Socket) -> {ok, Result} -> tsp("handle_request -> ok" "~n Result: ~p", [Result]), - case (catch handle_http_msg(Result, Socket)) of + case (catch handle_http_msg(Result, Socket, Close, Send)) of stop -> stop; <<>> -> @@ -2949,7 +3144,8 @@ handle_request(Module, Function, Args, Socket) -> {httpd_request, parse, [[<<>>, ?HTTP_MAX_HEADER_SIZE]]}; Data -> handle_request(httpd_request, parse, - [Data |[?HTTP_MAX_HEADER_SIZE]], Socket) + [Data |[?HTTP_MAX_HEADER_SIZE]], Socket, + Close, Send) end; NewMFA -> tsp("handle_request -> " @@ -2957,7 +3153,7 @@ handle_request(Module, Function, Args, Socket) -> NewMFA end. -handle_http_msg({_, RelUri, _, {_, Headers}, Body}, Socket) -> +handle_http_msg({_, RelUri, _, {_, Headers}, Body}, Socket, Close, Send) -> tsp("handle_http_msg -> entry with: " "~n RelUri: ~p" "~n Headers: ~p" @@ -3114,16 +3310,16 @@ handle_http_msg({_, RelUri, _, {_, Headers}, Body}, Socket) -> "Expires:Sat, 29 Oct 1994 19:43:31 GMT\r\n" ++ "Proxy-Authenticate:#1Basic" ++ "\r\n\r\n", - gen_tcp:send(Socket, Head), - gen_tcp:send(Socket, http_chunk:encode("fo")), - gen_tcp:send(Socket, http_chunk:encode("obar")), + Send(Socket, Head), + Send(Socket, http_chunk:encode("fo")), + Send(Socket, http_chunk:encode("obar")), http_chunk:encode_last(); "/capital_transfer_encoding.html" -> Head = "HTTP/1.1 200 ok\r\n" ++ "Transfer-Encoding:Chunked\r\n\r\n", - gen_tcp:send(Socket, Head), - gen_tcp:send(Socket, http_chunk:encode("fo")), - gen_tcp:send(Socket, http_chunk:encode("obar")), + Send(Socket, Head), + Send(Socket, http_chunk:encode("fo")), + Send(Socket, http_chunk:encode("obar")), http_chunk:encode_last(); "/cookie.html" -> "HTTP/1.1 200 ok\r\n" ++ @@ -3142,20 +3338,20 @@ handle_http_msg({_, RelUri, _, {_, Headers}, Body}, Socket) -> "/once_chunked.html" -> Head = "HTTP/1.1 200 ok\r\n" ++ "Transfer-Encoding:Chunked\r\n\r\n", - gen_tcp:send(Socket, Head), - gen_tcp:send(Socket, http_chunk:encode("fo")), - gen_tcp:send(Socket, + Send(Socket, Head), + Send(Socket, http_chunk:encode("fo")), + Send(Socket, http_chunk:encode("obar")), http_chunk:encode_last(); "/once.html" -> Head = "HTTP/1.1 200 ok\r\n" ++ "Content-Length:32\r\n\r\n", - gen_tcp:send(Socket, Head), - gen_tcp:send(Socket, "fo"), + Send(Socket, Head), + Send(Socket, "fo"), test_server:sleep(1000), - gen_tcp:send(Socket, "ob"), + Send(Socket, "ob"), test_server:sleep(1000), - gen_tcp:send(Socket, "ar"); + Send(Socket, "ar"); "/invalid_http.html" -> "HTTP/1.1 301\r\nDate:Sun, 09 Dec 2007 13:04:18 GMT\r\n" ++ "Transfer-Encoding:chunked\r\n\r\n"; @@ -3178,9 +3374,9 @@ handle_http_msg({_, RelUri, _, {_, Headers}, Body}, Socket) -> ok; close -> %% Nothing to send, just close - gen_tcp:close(Socket); + Close(Socket); _ when is_list(Msg) orelse is_binary(Msg) -> - gen_tcp:send(Socket, Msg) + Send(Socket, Msg) end, tsp("handle_http_msg -> done"), NextRequest. @@ -3316,3 +3512,4 @@ dummy_ssl_server_hang_loop(_) -> stop -> ok end. + diff --git a/lib/inets/test/inets_test_lib.erl b/lib/inets/test/inets_test_lib.erl index 6cedaf9638..c4b220dd2f 100644 --- a/lib/inets/test/inets_test_lib.erl +++ b/lib/inets/test/inets_test_lib.erl @@ -31,13 +31,22 @@ -export([info/4, log/4, debug/4, print/4]). -export([check_body/1]). -export([millis/0, millis_diff/2, hours/1, minutes/1, seconds/1, sleep/1]). --export([oscmd/1]). +-export([oscmd/1, has_ipv6_support/0]). -export([non_pc_tc_maybe_skip/4, os_based_skip/1, skip/3, fail/3]). -export([flush/0]). -export([start_node/1, stop_node/1]). %% -- Misc os command and stuff +has_ipv6_support() -> + {ok, Hostname} = inet:gethostname(), + case inet:getaddrs(Hostname, inet6) of + {ok, [Addr|_]} -> + {ok, Addr}; + _ -> + undefined + end. + oscmd(Cmd) -> string:strip(os:cmd(Cmd), right, $\n). diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk index 2bb4d83c49..4abc1733d3 100644 --- a/lib/inets/vsn.mk +++ b/lib/inets/vsn.mk @@ -18,7 +18,7 @@ # %CopyrightEnd% APPLICATION = inets -INETS_VSN = 5.6.1 +INETS_VSN = 5.7 PRE_VSN = APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)" -- cgit v1.2.3 From 6a87b618ae7702f569f73b45fa9008dede557dbf Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 1 Jun 2011 17:24:22 +0200 Subject: Temporary solution for profile_name stuff. What about Pids??? --- lib/inets/src/http_client/httpc.erl | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl index 6ffa5e8ba5..d957e97122 100644 --- a/lib/inets/src/http_client/httpc.erl +++ b/lib/inets/src/http_client/httpc.erl @@ -65,16 +65,18 @@ default_profile() -> profile_name(?DEFAULT_PROFILE) -> httpc_manager; profile_name(Profile) -> - profile_name("httpc_manager_", Profile). + Prefix = lists:flatten(io_lib:format("~w_", [?MODULE])), + profile_name(Prefix, Profile). profile_name(Prefix, Profile) when is_atom(Profile) -> list_to_atom(Prefix ++ atom_to_list(Profile)); -profile_name(Prefix, Profile) when is_pid(Profile) -> - ProfileStr0 = - string:strip(string:strip(erlang:pid_to_list(Profile), left, $<), right, $>), - F = fun($.) -> $_; (X) -> X end, - ProfileStr = [F(C) || C <- ProfileStr0], - list_to_atom(Prefix ++ "pid_" ++ ProfileStr). +profile_name(_Prefix, Profile) when is_pid(Profile) -> + Profile. + %% ProfileStr0 = + %% string:strip(string:strip(erlang:pid_to_list(Profile), left, $<), right, $>), + %% F = fun($.) -> $_; (X) -> X end, + %% ProfileStr = [F(C) || C <- ProfileStr0], + %% list_to_atom(Prefix ++ "pid_" ++ ProfileStr). %%-------------------------------------------------------------------------- @@ -115,9 +117,11 @@ request(Url, Profile) -> %% {keyfile, path()} | {password, string()} | {cacertfile, path()} | %% {ciphers, string()} %% Options - [Option] -%% Option - {sync, Boolean} | {body_format, BodyFormat} | -%% {full_result, Boolean} | {stream, To} | -%% {headers_as_is, Boolean} +%% Option - {sync, Boolean} | +%% {body_format, BodyFormat} | +%% {full_result, Boolean} | +%% {stream, To} | +%% {headers_as_is, Boolean} %% StatusLine = {HTTPVersion, StatusCode, ReasonPhrase} %% HTTPVersion = string() %% StatusCode = integer() -- cgit v1.2.3 From 85a0e30e27167efbab0456ad4d694c84c3e9c0d4 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 8 Jun 2011 11:20:41 +0200 Subject: Clients started stand-alone not properly handled. OTP-9365 --- lib/inets/src/http_client/httpc.erl | 7 ++----- lib/inets/test/httpc_SUITE.erl | 3 ++- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl index d957e97122..54f254db52 100644 --- a/lib/inets/src/http_client/httpc.erl +++ b/lib/inets/src/http_client/httpc.erl @@ -64,6 +64,8 @@ default_profile() -> profile_name(?DEFAULT_PROFILE) -> httpc_manager; +profile_name(Profile) when is_pid(Profile) -> + Profile; profile_name(Profile) -> Prefix = lists:flatten(io_lib:format("~w_", [?MODULE])), profile_name(Prefix, Profile). @@ -72,11 +74,6 @@ profile_name(Prefix, Profile) when is_atom(Profile) -> list_to_atom(Prefix ++ atom_to_list(Profile)); profile_name(_Prefix, Profile) when is_pid(Profile) -> Profile. - %% ProfileStr0 = - %% string:strip(string:strip(erlang:pid_to_list(Profile), left, $<), right, $>), - %% F = fun($.) -> $_; (X) -> X end, - %% ProfileStr = [F(C) || C <- ProfileStr0], - %% list_to_atom(Prefix ++ "pid_" ++ ProfileStr). %%-------------------------------------------------------------------------- diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 731e330ef7..202dcca763 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -341,6 +341,7 @@ init_per_testcase(Case, Timeout, Config) -> "~n SSL start result: ~p", [CryptoStartRes, PubKeyStartRes, SSLStartRes]), Profile = ipv6, + %% A stand-alone profile is represented by a pid() {ok, ProfilePid} = inets:start(httpc, [{profile, Profile}, @@ -367,7 +368,7 @@ init_per_testcase(Case, Timeout, Config) -> %% snmp:set_trace([gen_tcp]), NewConfig. - + %%-------------------------------------------------------------------- %% Function: end_per_testcase(Case, Config) -> _ %% Case - atom() -- cgit v1.2.3 From 30dd46d5ac286a5aa39ff38546b72170e7dbfbb2 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 8 Jun 2011 11:21:32 +0200 Subject: Clients started stand-alone not properly handled. OTP-9365 --- lib/inets/doc/src/httpc.xml | 180 ++++++++++++++++++++++---------------------- lib/inets/doc/src/notes.xml | 8 ++ 2 files changed, 97 insertions(+), 91 deletions(-) diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml index f6b6827e93..d1671ac9bd 100644 --- a/lib/inets/doc/src/httpc.xml +++ b/lib/inets/doc/src/httpc.xml @@ -144,7 +144,7 @@ filename() = string() Result = {status_line(), headers(), Body} | {status_code(), Body} | request_id() Body = string() | binary() - Profile = profile() + Profile = profile() | pid() (when started stand_alone) Reason = term() @@ -194,16 +194,16 @@ filename() = string() Result = {status_line(), headers(), Body} | {status_code(), Body} | request_id() Body = string() | binary() - Profile = profile() + Profile = profile() | pid() (when started stand_alone) Reason = {connect_failed, term()} | {send_failed, term()} | term()

Sends a HTTP-request. The function can be both synchronous - and asynchronous. In the later case the function will return - {ok, RequestId} and later on the information will be delivered - to the receiver depending on that value.

+ and asynchronous. In the later case the function will return + {ok, RequestId} and later on the information will be delivered + to the receiver depending on that value.

Http option (http_option()) details:

@@ -211,7 +211,7 @@ filename() = string()

Timeout time for the request.

The clock starts ticking as soon as the request has been - sent.

+ sent.

Time is in milliseconds.

Defaults to infinity.

@@ -219,7 +219,7 @@ filename() = string()

Connection timeout time, used during the initial request, - when the client is connecting to the server.

+ when the client is connecting to the server.

Time is in milliseconds.

Defaults to the value of the timeout option.

@@ -227,60 +227,61 @@ filename() = string()

This is the default ssl config option, currently defaults to - essl, see below.

+ essl, see below.

Defaults to [].

If using the OpenSSL based (old) implementation of SSL, - these SSL-specific options are used.

+ these SSL-specific options are used.

Defaults to [].

If using the Erlang based (new) implementation of SSL, - these SSL-specific options are used.

+ these SSL-specific options are used.

Defaults to [].

-

Should the client automatically retrieve the information - from the new URI and return that as the result instead - of a 30X-result code.

-

Note that for some 30X-result codes automatic redirect - is not allowed. In these cases the 30X-result will always - be returned.

-

Defaults to true.

+

Should the client automatically retrieve the information + from the new URI and return that as the result instead + of a 30X-result code.

+

Note that for some 30X-result codes automatic redirect + is not allowed. In these cases the 30X-result will always + be returned.

+

Defaults to true.

A proxy-authorization header using the provided user name and - password will be added to the request.

+ password will be added to the request.

Can be used to make the client act as an HTTP/1.0 or - HTTP/0.9 client. By default this is an HTTP/1.1 - client. When using HTTP/1.0 persistent connections will - not be used.

-

Defaults to the string "HTTP/1.1".

+ HTTP/0.9 client. By default this is an HTTP/1.1 + client. When using HTTP/1.0 persistent connections will + not be used.

+

Defaults to the string "HTTP/1.1".

-

If set to true workarounds for known server deviations from - the HTTP-standard are enabled.

+

If set to true workarounds for known server deviations + from the HTTP-standard are enabled.

Defaults to false.

-

Will apply Percent-encoding, also known as URL encoding on the URL.

+

Will apply Percent-encoding, also known as URL encoding on the + URL.

Defaults to false.

@@ -296,77 +297,77 @@ filename() = string()

Streams the body of a 200 or 206 response to the calling - process or to a file. When streaming to the calling process - using the option self the following stream messages - will be sent to that process: {http, {RequestId, - stream_start, Headers}, {http, {RequestId, stream, - BinBodyPart}, {http, {RequestId, stream_end, Headers}. When - streaming to to the calling processes using the option - {self, once} the first message will have an additional - element e.i. {http, {RequestId, stream_start, Headers, Pid}, - this is the process id that should be used as an argument to - http:stream_next/1 to trigger the next message to be sent to - the calling process.

+ process or to a file. When streaming to the calling process + using the option self the following stream messages + will be sent to that process: {http, {RequestId, + stream_start, Headers}, {http, {RequestId, stream, + BinBodyPart}, {http, {RequestId, stream_end, Headers}. When + streaming to to the calling processes using the option + {self, once} the first message will have an additional + element e.i. {http, {RequestId, stream_start, Headers, Pid}, + this is the process id that should be used as an argument to + http:stream_next/1 to trigger the next message to be sent to + the calling process.

Note that it is possible that chunked encoding will add - headers so that there are more headers in the stream_end - message than in the stream_start. - When streaming to a file and the request is asynchronous the - message {http, {RequestId, saved_to_file}} will be sent.

+ headers so that there are more headers in the stream_end + message than in the stream_start. + When streaming to a file and the request is asynchronous the + message {http, {RequestId, saved_to_file}} will be sent.

Defaults to none.

Defines if the body shall be delivered as a string or as a - binary. This option is only valid for the synchronous - request.

+ binary. This option is only valid for the synchronous + request.

Defaults to string.

Should a "full result" be returned to the caller (that is, - the body, the headers and the entire status-line) or not - (the body and the status code).

+ the body, the headers and the entire status-line) or not + (the body and the status code).

Defaults to true.

Shall the headers provided by the user be made - lower case or be regarded as case sensitive.

+ lower case or be regarded as case sensitive.

Note that the http standard requires them to be - case insenstive. This feature should only be used if there is - no other way to communicate with the server or for testing - purpose. Also note that when this option is used no headers - will be automatically added, all necessary headers have to be - provided by the user.

-

Defaults to false.

+ case insenstive. This feature should only be used if there is + no other way to communicate with the server or for testing + purpose. Also note that when this option is used no headers + will be automatically added, all necessary headers have to be + provided by the user.

+

Defaults to false.

Socket options to be used for this and subsequent - request(s).

-

Overrides any value set by the - set_options - function.

+ request(s).

+

Overrides any value set by the + set_options + function.

Note that the validity of the options are not - checked in any way.

+ checked in any way.

Note that this may change the socket behaviour - (see inet:setopts/2) - for an already existing one, and therefore an already connected - request handler.

+ (see inet:setopts/2) + for an already existing one, and therefore an already connected + request handler.

By default the socket options set by the - set_options/1,2 - function are used when establishing a connection.

+ set_options/1,2 + function are used when establishing a connection.

Defines how the client will deliver the result of an - asynchroneous request (sync has the value - false).

+ asynchroneous request (sync has the value + false).

@@ -380,7 +381,7 @@ filename() = string()

Information will be delivered to the receiver via calls - to the provided fun:

+ to the provided fun:

 Receiver(ReplyInfo)
 
@@ -389,7 +390,7 @@ Receiver(ReplyInfo)

Information will be delivered to the receiver via calls - to the callback function:

+ to the callback function:

 apply(Module, Function, [ReplyInfo | Args])
 
@@ -410,7 +411,7 @@ apply(Module, Function, [ReplyInfo | Args])

Defaults to the pid() of the process calling the request - function (self()).

+ function (self()).

@@ -425,7 +426,7 @@ apply(Module, Function, [ReplyInfo | Args]) RequestId = request_id() - A unique identifier as returned by request/4 - Profile = profile() + Profile = profile() | pid() (when started stand_alone)

Cancels an asynchronous HTTP-request.

@@ -514,11 +515,10 @@ apply(Module, Function, [ReplyInfo | Args]) This option is used to switch on (or off) different levels of erlang trace on the client. It is a debug feature. - Profile = profile() + Profile = profile() | pid() (when started stand_alone) -

Sets options to be used for subsequent - requests.

+

Sets options to be used for subsequent requests.

If possible the client will keep its connections alive and use persistent connections @@ -548,7 +548,7 @@ apply(Module, Function, [ReplyInfo | Args])

Triggers the next message to be streamed, e.i. - same behavior as active once for sockets.

+ same behavior as active once for sockets.

@@ -562,14 +562,14 @@ apply(Module, Function, [ReplyInfo | Args]) SetCookieHeaders = headers() - where field = "set-cookie" Url = url() - Profile = profile() + Profile = profile() | pid() (when started stand_alone)

Saves the cookies defined in SetCookieHeaders - in the client profile's cookie database. You need to - call this function if you have set the option cookies to verify. - If no profile is specified the default profile will be used. -

+ in the client profile's cookie database. You need to + call this function if you have set the option cookies + to verify. + If no profile is specified the default profile will be used.

@@ -582,13 +582,12 @@ apply(Module, Function, [ReplyInfo | Args]) making a request to Url using the profile Profile. Url = url() - Profile = profile() + Profile = profile() | pid() (when started stand_alone)

Returns the cookie header that would be sent - when making a request to Url using the profile Profile. - If no profile is specified the default profile will be used. -

+ when making a request to Url using the profile Profile. + If no profile is specified the default profile will be used.

@@ -600,12 +599,12 @@ apply(Module, Function, [ReplyInfo | Args]) reset_cookies(Profile) -> void() Reset the cookie database. - Profile = profile() + Profile = profile() | pid() (when started stand_alone) -

Resets (clears) the cookie database for the specified Profile. - If no profile is specified the default profile will be used. -

+

Resets (clears) the cookie database for the specified + Profile. If no profile is specified the default profile + will be used.

@@ -615,17 +614,16 @@ apply(Module, Function, [ReplyInfo | Args]) which_cookies(Profile) -> cookies() Dumps out the entire cookie database. - Profile = profile() - cookies() = [cooie_stores()] - cookie_stores() = {cookies, icookies()} | {session_cookies, icookies()} - icookies() = [icookie()] + Profile = profile() | pid() (when started stand_alone) + cookies() = [cookie_stores()] + cookie_stores() = {cookies, cookies()} | {session_cookies, cookies()} + cookies() = [cookie()] cookie() = term()

This function produces a list of the entire cookie database. - It is intended for debugging/testing purposes. - If no profile is specified the default profile will be used. -

+ It is intended for debugging/testing purposes. + If no profile is specified the default profile will be used.

diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml index ed1b974771..df0b10ef58 100644 --- a/lib/inets/doc/src/notes.xml +++ b/lib/inets/doc/src/notes.xml @@ -65,6 +65,14 @@

Own Id: OTP-5566

+ +

[httpc] Clients started stand-alone not properly handled. + Also it was not documented how to use them, that is that + once started, they are represented by a pid() and not by + their profile().

+

Own Id: OTP-9365

+
+
-- cgit v1.2.3 From 611cccf10cfe98fe2aca018b91e7241714528850 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 9 Jun 2011 16:11:28 +0200 Subject: Added test cases for httpd. --- lib/inets/doc/src/notes.xml | 18 +-- lib/inets/test/httpc_SUITE.erl | 24 ---- lib/inets/test/httpd_SUITE.erl | 281 +++++++++++++++++++++++++++----------- lib/inets/test/httpd_test_lib.erl | 91 +++++++----- lib/inets/test/inets_test_lib.erl | 74 +++++++--- 5 files changed, 318 insertions(+), 170 deletions(-) diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml index df0b10ef58..2df862fb33 100644 --- a/lib/inets/doc/src/notes.xml +++ b/lib/inets/doc/src/notes.xml @@ -35,22 +35,17 @@
Inets 5.7
Improvements and New Features + -
@@ -60,11 +55,6 @@ --> - -

[httpc|httpd] Added support for IPv6 with ssl.

-

Own Id: OTP-5566

-
-

[httpc] Clients started stand-alone not properly handled. Also it was not documented how to use them, that is that diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 202dcca763..27e42c6ca2 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -141,9 +141,7 @@ groups() -> {otp_8106, [], [otp_8106_pid, otp_8106_fun, otp_8106_mfa]}, - %% {ipv6, [], [ipv6_ipcomm, ipv6_essl, ipv6_ossl]} {ipv6, [], [ipv6_ipcomm, ipv6_essl]} - %% {ipv6, [], [ipv6_ipcomm]} ]. @@ -1953,28 +1951,6 @@ ipv6_essl(Config) when is_list(Config) -> ipv6(SocketType, Scheme, HTTPOptions, Extra, Config). -%%------------------------------------------------------------------------- - -%% ipv6_ossl() -> -%% %% [{require, ipv6_hosts}]. -%% []. -%% ipv6_ossl(doc) -> -%% ["Test ossl ipv6."]; -%% ipv6_ossl(suite) -> -%% []; -%% ipv6_ossl(Config) when is_list(Config) -> -%% DataDir = ?config(data_dir, Config), -%% CertFile = filename:join(DataDir, "ssl_client_cert.pem"), -%% SSLOptions = [{certfile, CertFile}, {keyfile, CertFile}], -%% SSLConfig = {ossl, SSLOptions}, -%% tsp("ossl_ipv6 -> make request using: " -%% "~n SSLOptions: ~p", [SSLOptions]), -%% HTTPOptions = [{ssl, SSLConfig}], -%% SocketType = ossl, -%% Scheme = "https", -%% ipv6(SocketType, Scheme, HTTPOptions, Config). - - %%------------------------------------------------------------------------- ipv6(SocketType, Scheme, HTTPOptions, Extra, Config) -> diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl index fde5178879..72b80a9f80 100644 --- a/lib/inets/test/httpd_SUITE.erl +++ b/lib/inets/test/httpd_SUITE.erl @@ -207,8 +207,9 @@ -export([ticket_5775/1,ticket_5865/1,ticket_5913/1,ticket_6003/1, ticket_7304/1]). -%%% Misc --export([ipv6_hostname/1, ipv6_address/1]). +%%% IPv6 tests +-export([ipv6_hostname_ipcomm/1, ipv6_address_ipcomm/1, + ipv6_hostname_essl/1, ipv6_address_essl/1]). %% Help functions -export([cleanup_mnesia/0, setup_mnesia/0, setup_mnesia/1]). @@ -241,9 +242,15 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [{group, ip}, {group, ssl}, {group, http_1_1_ip}, - {group, http_1_0_ip}, {group, http_0_9_ip}, - {group, tickets}]. + [ + {group, ip}, + {group, ssl}, + {group, http_1_1_ip}, + {group, http_1_0_ip}, + {group, http_0_9_ip}, + {group, ipv6}, + {group, tickets} + ]. groups() -> [{ip, [], @@ -329,7 +336,8 @@ groups() -> {http_1_0_ip, [], [ip_head_1_0, ip_get_1_0, ip_post_1_0]}, {http_0_9_ip, [], [ip_get_0_9]}, - {ipv6, [], [ipv6_hostname, ipv6_address]}, + {ipv6, [], [ipv6_hostname_ipcomm, ipv6_address_ipcomm, + ipv6_hostname_essl, ipv6_address_essl]}, {tickets, [], [ticket_5775, ticket_5865, ticket_5913, ticket_6003, ticket_7304]}]. @@ -408,10 +416,10 @@ 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", - SslHtacess = integer_to_list(?SSL_PORT) ++ "htacess.conf", + IpNormal = integer_to_list(?IP_PORT) ++ ".conf", + IpHtaccess = integer_to_list(?IP_PORT) ++ "htaccess.conf", + SslNormal = integer_to_list(?SSL_PORT) ++ ".conf", + SslHtaccess = integer_to_list(?SSL_PORT) ++ "htaccess.conf", DataDir = ?config(data_dir, Config), SuiteTopDir = ?config(suite_top_dir, Config), @@ -471,9 +479,9 @@ init_per_testcase2(Case, Config) -> io:format(user, "~w:init_per_testcase2(~w) -> ip testcase setups~n", [?MODULE, Case]), create_config([{port, ?IP_PORT}, {sock_type, ip_comm} | NewConfig], - normal_acess, IpNormal), + normal_access, IpNormal), create_config([{port, ?IP_PORT}, {sock_type, ip_comm} | NewConfig], - mod_htaccess, IpHtacess), + mod_htaccess, IpHtaccess), %% To be used by SSL test cases io:format(user, "~w:init_per_testcase2(~w) -> ssl testcase setups~n", @@ -491,9 +499,9 @@ init_per_testcase2(Case, Config) -> end, create_config([{port, ?SSL_PORT}, {sock_type, SocketType} | NewConfig], - normal_acess, SslNormal), + normal_access, SslNormal), create_config([{port, ?SSL_PORT}, {sock_type, SocketType} | NewConfig], - mod_htaccess, SslHtacess), + mod_htaccess, SslHtaccess), %% To be used by IPv6 test cases. Case-clause is so that %% you can do ts:run(inets, httpd_SUITE, ) @@ -501,6 +509,48 @@ init_per_testcase2(Case, Config) -> %% on 'test_host_ipv6_only' that will only be present %% when you run the whole test suite due to shortcomings %% of the test server. + + io:format(user, "~w:init_per_testcase2(~w) -> " + "maybe generate IPv6 config file(s)", [?MODULE, Case]), + NewConfig2 = + case atom_to_list(Case) of + "ipv6_" ++ _ -> + case (catch inets_test_lib:has_ipv6_support()) of + {ok, IPv6Address0} -> + {ok, Hostname} = inet:gethostname(), + IPv6Address = http_transport:ipv6_name(IPv6Address0), + create_ipv6_config([{port, ?IP_PORT}, + {sock_type, ip_comm}, + {ipv6_host, IPv6Address} | + NewConfig], + "ipv6_hostname_ipcomm.conf", + Hostname), + create_ipv6_config([{port, ?IP_PORT}, + {sock_type, ip_comm}, + {ipv6_host, IPv6Address} | + NewConfig], + "ipv6_address_ipcomm.conf", + IPv6Address), + create_ipv6_config([{port, ?SSL_PORT}, + {sock_type, essl}, + {ipv6_host, IPv6Address} | + NewConfig], + "ipv6_hostname_essl.conf", + Hostname), + create_ipv6_config([{port, ?SSL_PORT}, + {sock_type, essl}, + {ipv6_host, IPv6Address} | + NewConfig], + "ipv6_address_essl.conf", + IPv6Address), + [{ipv6_host, IPv6Address} | NewConfig]; + _ -> + NewConfig + end; + _ -> + NewConfig + end, + %% case (catch ?config(test_host_ipv6_only, Config)) of %% {_,IPv6Host,IPv6Adress,_,_} -> %% create_ipv6_config([{port, ?IP_PORT}, @@ -516,7 +566,7 @@ init_per_testcase2(Case, Config) -> io:format(user, "~w:init_per_testcase2(~w) -> done~n", [?MODULE, Case]), - NewConfig. + NewConfig2. init_per_testcase3(Case, Config) -> @@ -547,10 +597,10 @@ init_per_testcase3(Case, Config) -> [?MODULE, Case]), inets:disable_trace(); _ -> - %% TraceLevel = max, io:format(user, "~w:init_per_testcase3(~w) -> enabling trace", [?MODULE, Case]), - TraceLevel = 70, + %% TraceLevel = 70, + TraceLevel = max, TraceDest = io, inets:enable_trace(TraceLevel, TraceDest, httpd) end, @@ -569,7 +619,7 @@ init_per_testcase3(Case, Config) -> inets_test_lib:start_http_server( filename:join(TcTopDir, integer_to_list(?IP_PORT) ++ - "htacess.conf")), + "htaccess.conf")), "mod_htaccess"; "ip_" ++ Rest -> inets_test_lib:start_http_server( @@ -602,7 +652,7 @@ init_per_testcase3(Case, Config) -> case inets_test_lib:start_http_server_ssl( filename:join(TcTopDir, integer_to_list(?SSL_PORT) ++ - "htacess.conf"), SslTag) of + "htaccess.conf"), SslTag) of ok -> "mod_htaccess"; Other -> @@ -627,16 +677,13 @@ init_per_testcase3(Case, Config) -> {skip, "SSL does not seem to be supported"} end; "ipv6_" ++ _ = TestCaseStr -> - {ok, Hostname} = inet:gethostname(), - - case lists:member(list_to_atom(Hostname), - ?config(ipv6_hosts, Config)) of - true -> + case inets_test_lib:has_ipv6_support() of + {ok, _} -> inets_test_lib:start_http_server( filename:join(TcTopDir, TestCaseStr ++ ".conf")); - false -> + _ -> {skip, "Host does not support IPv6"} end end, @@ -650,8 +697,8 @@ init_per_testcase3(Case, Config) -> "mod_htaccess" -> ServerRoot = ?config(server_root, Config), Path = filename:join([ServerRoot, "htdocs"]), - catch remove_htacess(Path), - create_htacess_data(Path, ?config(address, Config)), + catch remove_htaccess(Path), + create_htaccess_data(Path, ?config(address, Config)), [{watchdog, Dog} | NewConfig]; "range" -> ServerRoot = ?config(server_root, Config), @@ -2409,30 +2456,67 @@ ip_mod_cgi_chunked_encoding_test(Config) when is_list(Config) -> ok. %------------------------------------------------------------------------- -ipv6_hostname(doc) -> +ipv6_hostname_ipcomm(X) -> + SocketType = ip_comm, + Port = ?IP_PORT, + ipv6_hostname(SocketType, Port, X). + +ipv6_hostname_essl(X) -> + SocketType = essl, + Port = ?SSL_PORT, + ipv6_hostname(SocketType, Port, X). + +ipv6_hostname(_SocketType, _Port, doc) -> ["Test standard ipv6 address"]; -ipv6_hostname(suite)-> +ipv6_hostname(_SocketType, _Port, suite)-> []; -ipv6_hostname(Config) when is_list(Config) -> +ipv6_hostname(SocketType, Port, Config) when is_list(Config) -> + tsp("ipv6_hostname -> entry with" + "~n SocketType: ~p" + "~n Port: ~p" + "~n Config: ~p", [SocketType, Port, Config]), Host = ?config(host, Config), - httpd_test_lib:verify_request(ip_comm, Host, ?IP_PORT, node(), - "GET / HTTP/1.1\r\n\r\n", - [{statuscode, 200}, - {version, "HTTP/1.1"}]), + URI = "GET HTTP://" ++ + Host ++ ":" ++ integer_to_list(Port) ++ "/ HTTP/1.1\r\n\r\n", + tsp("ipv6_hostname -> Host: ~p", [Host]), + httpd_test_lib:verify_request(SocketType, Host, Port, [inet6], + node(), + URI, + [{statuscode, 200}, {version, "HTTP/1.1"}]), ok. %%------------------------------------------------------------------------- -ipv6_address(doc) -> + +ipv6_address_ipcomm(X) -> + SocketType = ip_comm, + Port = ?IP_PORT, + ipv6_address(SocketType, Port, X). + +ipv6_address_essl(X) -> + SocketType = essl, + Port = ?SSL_PORT, + ipv6_address(SocketType, Port, X). + +ipv6_address(_SocketType, _Port, doc) -> ["Test standard ipv6 address"]; -ipv6_address(suite)-> +ipv6_address(_SocketType, _Port, suite)-> []; -ipv6_address(Config) when is_list(Config) -> - httpd_test_lib:verify_request(ip_comm, ?IPV6_LOCAL_HOST, ?IP_PORT, - node(), "GET / HTTP/1.1\r\n\r\n", - [{statuscode, 200}, - {version, "HTTP/1.1"}]), +ipv6_address(SocketType, Port, Config) when is_list(Config) -> + tsp("ipv6_address -> entry with" + "~n SocketType: ~p" + "~n Port: ~p" + "~n Config: ~p", [SocketType, Port, Config]), + Host = ?config(host, Config), + tsp("ipv6_address -> Host: ~p", [Host]), + URI = "GET HTTP://" ++ + Host ++ ":" ++ integer_to_list(Port) ++ "/ HTTP/1.1\r\n\r\n", + httpd_test_lib:verify_request(SocketType, Host, Port, [inet6], + node(), + URI, + [{statuscode, 200}, {version, "HTTP/1.1"}]), ok. + %%-------------------------------------------------------------------- ticket_5775(doc) -> ["Tests that content-length is correct"]; @@ -2805,22 +2889,22 @@ cleanup_mnesia() -> mnesia:delete_schema([node()]), ok. -create_htacess_data(Path, IpAddress)-> - create_htacess_dirs(Path), +create_htaccess_data(Path, IpAddress)-> + create_htaccess_dirs(Path), create_html_file(filename:join([Path,"ht/open/dummy.html"])), create_html_file(filename:join([Path,"ht/blocknet/dummy.html"])), create_html_file(filename:join([Path,"ht/secret/dummy.html"])), create_html_file(filename:join([Path,"ht/secret/top_secret/dummy.html"])), - create_htacess_file(filename:join([Path,"ht/open/.htaccess"]), + create_htaccess_file(filename:join([Path,"ht/open/.htaccess"]), Path, "user one Aladdin"), - create_htacess_file(filename:join([Path,"ht/secret/.htaccess"]), + create_htaccess_file(filename:join([Path,"ht/secret/.htaccess"]), Path, "group group1 group2"), - create_htacess_file(filename:join([Path, + create_htaccess_file(filename:join([Path, "ht/secret/top_secret/.htaccess"]), Path, "user four"), - create_htacess_file(filename:join([Path,"ht/blocknet/.htaccess"]), + create_htaccess_file(filename:join([Path,"ht/blocknet/.htaccess"]), Path, nouser, IpAddress), create_user_group_file(filename:join([Path,"ht","users.file"]), @@ -2835,7 +2919,7 @@ create_html_file(PathAndFileName)-> "test testar")). -create_htacess_file(PathAndFileName, BaseDir, RequireData)-> +create_htaccess_file(PathAndFileName, BaseDir, RequireData)-> file:write_file(PathAndFileName, list_to_binary( "AuthUserFile "++ BaseDir ++ @@ -2844,7 +2928,7 @@ create_htacess_file(PathAndFileName, BaseDir, RequireData)-> " Basic\n\nrequire " ++ RequireData ++ "\n")). -create_htacess_file(PathAndFileName, BaseDir, nouser, IpAddress)-> +create_htaccess_file(PathAndFileName, BaseDir, nouser, IpAddress)-> file:write_file(PathAndFileName,list_to_binary( "AuthUserFile "++ BaseDir ++ "/ht/users.file\nAuthGroupFile " ++ @@ -2858,14 +2942,14 @@ create_htacess_file(PathAndFileName, BaseDir, nouser, IpAddress)-> create_user_group_file(PathAndFileName, Data)-> file:write_file(PathAndFileName, list_to_binary(Data)). -create_htacess_dirs(Path)-> +create_htaccess_dirs(Path)-> ok = file:make_dir(filename:join([Path,"ht"])), ok = file:make_dir(filename:join([Path,"ht/open"])), ok = file:make_dir(filename:join([Path,"ht/blocknet"])), ok = file:make_dir(filename:join([Path,"ht/secret"])), ok = file:make_dir(filename:join([Path,"ht/secret/top_secret"])). -remove_htacess_dirs(Path)-> +remove_htaccess_dirs(Path)-> file:del_dir(filename:join([Path,"ht/secret/top_secret"])), file:del_dir(filename:join([Path,"ht/secret"])), file:del_dir(filename:join([Path,"ht/blocknet"])), @@ -2888,7 +2972,7 @@ format_ip(IpAddress,Pos)when Pos > 0-> format_ip(IpAddress, _Pos)-> "1" ++ IpAddress. -remove_htacess(Path)-> +remove_htaccess(Path)-> file:delete(filename:join([Path,"ht/open/dummy.html"])), file:delete(filename:join([Path,"ht/secret/dummy.html"])), file:delete(filename:join([Path,"ht/secret/top_secret/dummy.html"])), @@ -2899,7 +2983,7 @@ remove_htacess(Path)-> file:delete(filename:join([Path,"ht/secret/top_secret/.htaccess"])), file:delete(filename:join([Path,"ht","users.file"])), file:delete(filename:join([Path,"ht","groups.file"])), - remove_htacess_dirs(Path). + remove_htaccess_dirs(Path). dos_hostname_poll(Type, Host, Port, Node, Hosts) -> @@ -2939,35 +3023,66 @@ create_range_data(Path) -> "12345678901234567890", "12345678901234567890"])). -%% create_ipv6_config(Config, FileName, Ipv6Address) -> -%% ServerRoot = ?config(server_root, Config), -%% TcTopDir = ?config(tc_top_dir, Config), -%% Port = ?config(port, Config), -%% SockType = ?config(sock_type, Config), -%% -%% MaxHdrSz = io_lib:format("~p", [256]), -%% MaxHdrAct = io_lib:format("~p", [close]), -%% -%% Mod_order = "Modules mod_alias mod_auth mod_esi mod_actions mod_cgi" -%% " mod_include mod_dir mod_get mod_head" -%% " mod_log mod_disk_log mod_trace", -%% -%% HttpConfig = [cline(["BindAddress ", "[" ++ Ipv6Address ++"]|inet6"]), -%% cline(["Port ", integer_to_list(Port)]), -%% cline(["ServerName ", "httpc_test"]), -%% cline(["SocketType ", atom_to_list(SockType)]), -%% cline([Mod_order]), -%% cline(["ServerRoot ", ServerRoot]), -%% cline(["DocumentRoot ", -%% filename:join(ServerRoot, "htdocs")]), -%% cline(["MaxHeaderSize ",MaxHdrSz]), -%% cline(["MaxHeaderAction ",MaxHdrAct]), -%% cline(["DirectoryIndex ", "index.html "]), -%% cline(["DefaultType ", "text/plain"])], -%% ConfigFile = filename:join([TcTopDir,FileName]), -%% {ok, Fd} = file:open(ConfigFile, [write]), -%% ok = file:write(Fd, lists:flatten(HttpConfig)), -%% ok = file:close(Fd). +create_ipv6_config(Config, FileName, Ipv6Address) -> + ServerRoot = ?config(server_root, Config), + TcTopDir = ?config(tc_top_dir, Config), + Port = ?config(port, Config), + SockType = ?config(sock_type, Config), + Mods = io_lib:format("~p", [httpd_mod]), + Funcs = io_lib:format("~p", [ssl_password_cb]), + Host = ?config(ipv6_host, Config), + + MaxHdrSz = io_lib:format("~p", [256]), + MaxHdrAct = io_lib:format("~p", [close]), + + Mod_order = "Modules mod_alias mod_auth mod_esi mod_actions mod_cgi" + " mod_include mod_dir mod_get mod_head" + " mod_log mod_disk_log mod_trace", + + SSL = + if + (SockType =:= ssl) orelse + (SockType =:= ossl) orelse + (SockType =:= essl) -> + [cline(["SSLCertificateFile ", + filename:join(ServerRoot, "ssl/ssl_server.pem")]), + cline(["SSLCertificateKeyFile ", + filename:join(ServerRoot, "ssl/ssl_server.pem")]), + cline(["SSLCACertificateFile ", + filename:join(ServerRoot, "ssl/ssl_server.pem")]), + cline(["SSLPasswordCallbackModule ", Mods]), + cline(["SSLPasswordCallbackFunction ", Funcs]), + cline(["SSLVerifyClient 0"]), + cline(["SSLVerifyDepth 1"])]; + true -> + [] + end, + + BindAddress = "[" ++ Ipv6Address ++"]|inet6", + + HttpConfig = [cline(["BindAddress ", BindAddress]), + cline(["Port ", integer_to_list(Port)]), + cline(["ServerName ", Host]), + cline(["SocketType ", atom_to_list(SockType)]), + cline([Mod_order]), + cline(["ServerRoot ", ServerRoot]), + cline(["DocumentRoot ", + filename:join(ServerRoot, "htdocs")]), + cline(["MaxHeaderSize ",MaxHdrSz]), + cline(["MaxHeaderAction ",MaxHdrAct]), + cline(["DirectoryIndex ", "index.html "]), + cline(["DefaultType ", "text/plain"]), + SSL], + ConfigFile = filename:join([TcTopDir,FileName]), + {ok, Fd} = file:open(ConfigFile, [write]), + ok = file:write(Fd, lists:flatten(HttpConfig)), + ok = file:close(Fd). + + +tsp(F) -> + inets_test_lib:tsp(F). +tsp(F, A) -> + inets_test_lib:tsp(F, A). tsf(Reason) -> - test_server:fail(Reason). + inets_test_lib:tsf(Reason). diff --git a/lib/inets/test/httpd_test_lib.erl b/lib/inets/test/httpd_test_lib.erl index 3189a758a5..2903aaafa5 100644 --- a/lib/inets/test/httpd_test_lib.erl +++ b/lib/inets/test/httpd_test_lib.erl @@ -22,7 +22,7 @@ -include("inets_test_lib.hrl"). %% Poll functions --export([verify_request/6, verify_request/7, is_expect/1]). +-export([verify_request/6, verify_request/7, verify_request/8, is_expect/1]). -record(state, {request, % string() socket, % socket() @@ -81,33 +81,57 @@ %%------------------------------------------------------------------ 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), +verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options) + when is_list(TranspOpts) -> + verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options, 30000); +verify_request(SocketType, Host, Port, Node, RequestStr, Options, TimeOut) + when (is_integer(TimeOut) orelse (TimeOut =:= infinity)) -> + verify_request(SocketType, Host, Port, [], Node, RequestStr, Options, TimeOut). +verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options, TimeOut) -> + tsp("verify_request -> entry with" + "~n SocketType: ~p" + "~n Host: ~p" + "~n Port: ~p" + "~n TranspOpts: ~p" + "~n Node: ~p" + "~n Options: ~p" + "~n TimeOut: ~p", + [SocketType, Host, Port, TranspOpts, Node, Options, TimeOut]), + case (catch inets_test_lib:connect_bin(SocketType, Host, Port, TranspOpts)) of + {ok, Socket} -> + tsp("verify_request -> connected - now send message"), + SendRes = inets_test_lib:send(SocketType, Socket, RequestStr), + tsp("verify_request -> send result: " + "~n ~p", [SendRes]), + State = case inets_regexp:match(RequestStr, "printenv") of + nomatch -> + #state{}; + _ -> + #state{print = true} + end, + + 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; - _SendRes = inets_test_lib:send(SocketType, Socket, RequestStr), - - State = case inets_regexp:match(RequestStr, "printenv") of - nomatch -> - #state{}; - _ -> - #state{print = true} - end, - - 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 + ConnectError -> + tsp("verify_request -> connect failed: " + "~n ~p" + "~n", [ConnectError]), + tsf({connect_failure, ConnectError}) end. request(#state{mfa = {Module, Function, Args}, @@ -214,7 +238,10 @@ validate(RequestStr, #state{status_line = {Version, StatusCode, _}, headers = Headers, body = Body}, Options, N, P) -> - %io:format("Status~p: H:~p B:~p~n", [StatusCode, Headers, Body]), + %% tsp("validate -> entry with" + %% "~n StatusCode: ~p" + %% "~n Headers: ~p" + %% "~n Body: ~p", [StatusCode, Headers, Body]), check_version(Version, Options), case lists:keysearch(statuscode, 1, Options) of {value, _} -> @@ -342,8 +369,10 @@ print(_, _, #state{print = false}) -> ok. -%% tsp(F) -> -%% tsp(F, []). +tsp(F) -> + inets_test_lib:tsp(F). tsp(F, A) -> - test_server:format("~p ~p:" ++ F ++ "~n", [self(), ?MODULE | A]). + inets_test_lib:tsp(F, A). +tsf(Reason) -> + inets_test_lib:tsf(Reason). diff --git a/lib/inets/test/inets_test_lib.erl b/lib/inets/test/inets_test_lib.erl index c4b220dd2f..60164c5a72 100644 --- a/lib/inets/test/inets_test_lib.erl +++ b/lib/inets/test/inets_test_lib.erl @@ -26,9 +26,12 @@ -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([connect_bin/3, connect_bin/4, + connect_byte/3, connect_byte/4, + send/3, close/2]). -export([copy_file/3, copy_files/2, copy_dirs/2, del_dirs/1]). -export([info/4, log/4, debug/4, print/4]). +-export([tsp/1, tsp/2, tsf/1]). -export([check_body/1]). -export([millis/0, millis_diff/2, hours/1, minutes/1, seconds/1, sleep/1]). -export([oscmd/1, has_ipv6_support/0]). @@ -294,29 +297,45 @@ os_based_skip(_) -> %% Host -> atom() | string() | {A, B, C, D} %% 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_bin(SockType, Host, Port) -> + connect_bin(SockType, Host, Port, []). + +connect_bin(ssl, Host, Port, Opts0) -> + Opts = [binary, {packet,0} | Opts0], + connect(ssl, Host, Port, Opts); +connect_bin(ossl, Host, Port, Opts0) -> + Opts = [{ssl_imp, old}, binary, {packet,0} | Opts0], + connect(ssl, Host, Port, Opts); +connect_bin(essl, Host, Port, Opts0) -> + Opts = [{ssl_imp, new}, binary, {packet,0}, {reuseaddr, true} | Opts0], + connect(ssl, Host, Port, Opts); +connect_bin(ip_comm, Host, Port, Opts0) -> + Opts = [binary, {packet, 0} | Opts0], connect(ip_comm, Host, Port, Opts). + +connect_byte(SockType, Host, Port) -> + connect_byte(SockType, Host, Port, []). -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_byte(ssl, Host, Port, Opts0) -> + Opts = [{packet,0} | Opts0], + connect(ssl, Host, Port, Opts); +connect_byte(ossl, Host, Port, Opts0) -> + Opts = [{ssl_imp, old}, {packet,0} | Opts0], + connect(ssl, Host, Port, Opts); +connect_byte(essl, Host, Port, Opts0) -> + Opts = [{ssl_imp, new}, {packet,0} | Opts0], + connect(ssl, Host, Port, Opts); +connect_byte(ip_comm, Host, Port, Opts0) -> + Opts = [{packet,0} | Opts0], connect(ip_comm, Host, Port, Opts). connect(ssl, Host, Port, Opts) -> + tsp("connect(ssl) -> entry with" + "~n Host: ~p" + "~n Port: ~p" + "~n Opts: ~p", [Host, Port, Opts]), ssl:start(), %% Does not support ipv6 in old ssl case ssl:connect(Host, Port, Opts) of @@ -328,6 +347,10 @@ connect(ssl, Host, Port, Opts) -> Error end; connect(ip_comm, Host, Port, Opts) -> + tsp("connect(ip_comm) -> entry with" + "~n Host: ~p" + "~n Port: ~p" + "~n Opts: ~p", [Host, Port, Opts]), case gen_tcp:connect(Host,Port, Opts) of {ok, Socket} -> %% tsp("connect success"), @@ -423,7 +446,22 @@ flush() -> tsp(F) -> tsp(F, []). tsp(F, A) -> - test_server:format("~p ~p ~p:" ++ F ++ "~n", [node(), self(), ?MODULE | A]). + Timestamp = formated_timestamp(), + test_server:format("*** ~s ~p ~p ~w:" ++ F ++ "~n", + [Timestamp, node(), self(), ?MODULE | A]). tsf(Reason) -> test_server:fail(Reason). + +formated_timestamp() -> + format_timestamp( os:timestamp() ). + +format_timestamp({_N1, _N2, N3} = Now) -> + {Date, Time} = calendar:now_to_datetime(Now), + {YYYY,MM,DD} = Date, + {Hour,Min,Sec} = Time, + FormatDate = + io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w", + [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]), + lists:flatten(FormatDate). + -- cgit v1.2.3 From 36c85608156dfebd732172559777ae61b6b5fc14 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 9 Jun 2011 18:13:55 +0200 Subject: Stopping httpc client... --- lib/inets/src/http_client/httpc.erl | 2 - lib/inets/test/httpc_SUITE.erl | 122 +++++++++++++++++++++++------------- 2 files changed, 79 insertions(+), 45 deletions(-) diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl index 54f254db52..6b3af3f924 100644 --- a/lib/inets/src/http_client/httpc.erl +++ b/lib/inets/src/http_client/httpc.erl @@ -553,9 +553,7 @@ return_answer(Options, {{"HTTP/0.9",_,_}, _, BinBody}) -> {ok, Body}; return_answer(Options, {StatusLine, Headers, BinBody}) -> - Body = maybe_format_body(BinBody, Options), - case proplists:get_value(full_result, Options, true) of true -> {ok, {StatusLine, Headers, Body}}; diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 27e42c6ca2..e4cd893009 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -64,16 +64,6 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [ - proxy_options, - proxy_head, - proxy_get, - proxy_trace, - proxy_post, - proxy_put, - proxy_delete, - proxy_auth, - proxy_headers, - proxy_emulate_lower_versions, http_options, http_head, http_get, @@ -88,15 +78,6 @@ all() -> http_headers, 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, @@ -106,14 +87,12 @@ all() -> http_emulate_lower_versions, http_relaxed, page_does_not_exist, - proxy_page_does_not_exist, - proxy_https_not_supported, - http_stream, - http_stream_once, - proxy_stream, parse_url, options, headers_as_is, + {group, proxy}, + {group, ssl}, + {group, stream}, {group, ipv6}, {group, tickets}, initial_server_connect @@ -121,6 +100,30 @@ all() -> groups() -> [ + {proxy, [], [proxy_options, + proxy_head, + proxy_get, + proxy_trace, + proxy_post, + proxy_put, + proxy_delete, + proxy_auth, + proxy_headers, + proxy_emulate_lower_versions, + proxy_page_does_not_exist, + proxy_https_not_supported]}, + {ssl, [], [ssl_head, + ossl_head, + essl_head, + ssl_get, + ossl_get, + essl_get, + ssl_trace, + ossl_trace, + essl_trace]}, + {stream, [], [http_stream, + http_stream_once, + proxy_stream]}, {tickets, [], [hexed_query_otp_6191, empty_body_otp_6243, empty_response_header_otp_6830, @@ -236,17 +239,6 @@ init_per_testcase(initial_server_connect, 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", [?MODULE, Case, Timeout]), @@ -328,6 +320,7 @@ init_per_testcase(Case, Timeout, Config) -> [{skip, "proxy not responding"} | TmpConfig] end end; + "ipv6_" ++ _Rest -> %% Start httpc part of inets CryptoStartRes = application:start(crypto), @@ -356,9 +349,7 @@ init_per_testcase(Case, Timeout, Config) -> [{watchdog, Dog}, {local_server, Server} | TmpConfig2] end, - %% httpc:set_options([{proxy, {{?PROXY, ?PROXY_PORT}, - %% ["localhost", ?IPV6_LOCAL_HOST]}}]), - + %% This will fail for the ipv6_ - cases (but that is ok) httpc:set_options([{proxy, {{?PROXY, ?PROXY_PORT}, ["localhost", ?IPV6_LOCAL_HOST]}}, {ipfamily, inet6fb4}]), @@ -366,6 +357,18 @@ init_per_testcase(Case, Timeout, Config) -> %% snmp:set_trace([gen_tcp]), NewConfig. + +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]. + %%-------------------------------------------------------------------- %% Function: end_per_testcase(Case, Config) -> _ @@ -388,11 +391,19 @@ end_per_testcase(Case, Config) -> [?MODULE, Case]), case atom_to_list(Case) of "ipv6_" ++ _Rest -> + tsp("end_per_testcase(~w) -> stop ssl", [Case]), application:stop(ssl), + tsp("end_per_testcase(~w) -> stop public_key", [Case]), application:stop(public_key), + tsp("end_per_testcase(~w) -> stop crypto", [Case]), application:stop(crypto), ProfilePid = ?config(profile, Config), + tsp("end_per_testcase(~w) -> stop httpc profile (~p)", + [Case, ProfilePid]), + unlink(ProfilePid), inets:stop(stand_alone, ProfilePid), + tsp("end_per_testcase(~w) -> httpc profile (~p) stopped", + [Case, ProfilePid]), ok; _ -> ok @@ -405,6 +416,7 @@ finish(Config) -> undefined -> ok; _ -> + tsp("finish -> stop watchdog (~p)", [Dog]), test_server:timetrap_cancel(Dog) end. @@ -1914,7 +1926,6 @@ parse_url(Config) when is_list(Config) -> %%------------------------------------------------------------------------- ipv6_ipcomm() -> - %% [{require, ipv6_hosts}]. []. ipv6_ipcomm(doc) -> ["Test ip_comm ipv6."]; @@ -1931,7 +1942,6 @@ ipv6_ipcomm(Config) when is_list(Config) -> %%------------------------------------------------------------------------- ipv6_essl() -> - %% [{require, ipv6_hosts}]. []. ipv6_essl(doc) -> ["Test essl ipv6."]; @@ -1970,9 +1980,17 @@ ipv6(SocketType, Scheme, HTTPOptions, Extra, Config) -> "~n HTTPOptions: ~p", [URL, HTTPOptions]), case httpc:request(get, {URL, []}, HTTPOptions, [], Profile) of {ok, {{_,200,_}, [_ | _], [_|_]}} -> + tsp("ipv6 -> expected result"), DummyServerPid ! stop, ok; + {ok, Unexpected} -> + tsp("ipv6 -> unexpected result: " + "~n ~p", [Unexpected]), + DummyServerPid ! stop, + tsf({unexpected_result, Unexpected}); {error, Reason} -> + tsp("ipv6 -> error: " + "~n Reason: ~p", [Reason]), DummyServerPid ! stop, tsf(Reason) end, @@ -2950,7 +2968,13 @@ receive_streamed_body(RequestId, Body, Pid) -> test_server:fail(Msg) end. - +%% Perform a synchronous stop +dummy_server_stop(Pid) -> + Pid ! {stop, self()}, + receive + {stopped, Pid} -> + ok + end. dummy_server(IpV) -> dummy_server(self(), ip_comm, IpV, []). @@ -3013,7 +3037,13 @@ dummy_ipcomm_server_loop(MFA, Handlers, ListenSocket) -> receive stop -> tsp("dummy_ipcomm_server_loop -> stop handlers", []), - lists:foreach(fun(Handler) -> Handler ! stop end, Handlers) + lists:foreach(fun(Handler) -> Handler ! stop end, Handlers); + {stop, From} -> + tsp("dummy_ipcomm_server_loop -> " + "stop command from ~p for handlers (~p)", [From, Handlers]), + Stopper = fun(Handler) -> Handler ! stop end, + lists:foreach(Stopper, Handlers), + From ! {stopped, self()} after 0 -> tsp("dummy_ipcomm_server_loop -> await accept", []), {ok, Socket} = gen_tcp:accept(ListenSocket), @@ -3034,7 +3064,13 @@ dummy_ssl_server_loop(MFA, Handlers, ListenSocket) -> receive stop -> tsp("dummy_ssl_server_loop -> stop handlers", []), - lists:foreach(fun(Handler) -> Handler ! stop end, Handlers) + lists:foreach(fun(Handler) -> Handler ! stop end, Handlers); + {stop, From} -> + tsp("dummy_ssl_server_loop -> " + "stop command from ~p for handlers (~p)", [From, Handlers]), + Stopper = fun(Handler) -> Handler ! stop end, + lists:foreach(Stopper, Handlers), + From ! {stopped, self()} after 0 -> tsp("dummy_ssl_server_loop -> await accept", []), {ok, Socket} = ssl:transport_accept(ListenSocket), -- cgit v1.2.3 From 24808ff1c55344a54fa5379c9d0ae3034b539c42 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 14 Jun 2011 17:34:02 +0200 Subject: Fixed IPv6 test case selection. That is if a IPv6 test case should be run or not. --- lib/inets/test/httpc_SUITE.erl | 117 ++++++++++++++++++++++++++------------ lib/inets/test/httpd_SUITE.erl | 59 ++++++++++--------- lib/inets/test/inets_test_lib.erl | 46 +++++++++++++-- 3 files changed, 149 insertions(+), 73 deletions(-) diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index e4cd893009..828fa54523 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -220,20 +220,33 @@ end_per_suite(Config) -> %% Note: This function is free to add any key/value pairs to the Config %% variable, but should NOT alter/remove any existing entries. %%-------------------------------------------------------------------- + init_per_testcase(otp_8154_1 = Case, Config) -> init_per_testcase(Case, 5, Config); -init_per_testcase(initial_server_connect, Config) -> +init_per_testcase(initial_server_connect = Case, Config) -> %% Try to check if crypto actually exist or not, %% this test case does not work unless it does - case (catch crypto:start()) of - ok -> - application:start(public_key), - application:start(ssl), + try + begin + ensure_started(crypto), + ensure_started(public_key), + ensure_started(ssl), inets:start(), - Config; - _ -> - {skip,"Could not start crypto"} + Config + end + catch + throw:{error, {failed_starting, App, ActualError}} -> + tsp("init_per_testcase(~w) -> failed starting ~w: " + "~n ~p", [Case, App, ActualError]), + SkipString = + "Could not start " ++ atom_to_list(App), + {skip, SkipString}; + _:X -> + SkipString = + lists:flatten( + io_lib:format("Failed starting apps: ~p", [X])), + {skip, SkipString} end; init_per_testcase(Case, Config) -> @@ -274,16 +287,23 @@ init_per_testcase(Case, Timeout, Config) -> "https_not_supported" -> tsp("init_per_testcase -> [proxy case] start inets"), inets:start(), - tsp("init_per_testcase -> [proxy case] start ssl"), - application:start(crypto), - application:start(public_key), - case (catch application:start(ssl)) of + tsp("init_per_testcase -> " + "[proxy case] start crypto, public_key and ssl"), + try ensure_started([crypto, public_key, ssl]) of ok -> - [{watchdog, Dog} | TmpConfig]; - _ -> - [{skip, "SSL does not seem to be supported"} - | TmpConfig] + [{watchdog, Dog} | TmpConfig] + catch + throw:{error, {failed_starting, App, _}} -> + SkipString = + "Could not start " ++ atom_to_list(App), + {skip, SkipString}; + _:X -> + SkipString = + lists:flatten( + io_lib:format("Failed starting apps: ~p", [X])), + {skip, SkipString} end; + _ -> %% We use erlang.org for the proxy tests %% and after the switch to erlang-web, many @@ -322,24 +342,31 @@ init_per_testcase(Case, Timeout, Config) -> end; "ipv6_" ++ _Rest -> - %% Start httpc part of inets - CryptoStartRes = application:start(crypto), - PubKeyStartRes = application:start(public_key), - SSLStartRes = application:start(ssl), - tsp("App start result: " - "~n Crypto start result: ~p" - "~n PublicKey start result: ~p" - "~n SSL start result: ~p", - [CryptoStartRes, PubKeyStartRes, SSLStartRes]), - Profile = ipv6, - %% A stand-alone profile is represented by a pid() - {ok, ProfilePid} = - inets:start(httpc, - [{profile, Profile}, - {data_dir, PrivDir}], stand_alone), - httpc:set_options([{ipfamily, inet6}], ProfilePid), - tsp("httpc profile pid: ~p", [ProfilePid]), - [{watchdog, Dog}, {profile, ProfilePid}| TmpConfig]; + %% Ensure needed apps (crypto, public_key and ssl) started + try ensure_started([crypto, public_key, ssl]) of + ok -> + Profile = ipv6, + %% A stand-alone profile is represented by a pid() + {ok, ProfilePid} = + inets:start(httpc, + [{profile, Profile}, + {data_dir, PrivDir}], stand_alone), + httpc:set_options([{ipfamily, inet6}], ProfilePid), + tsp("httpc profile pid: ~p", [ProfilePid]), + [{watchdog, Dog}, {profile, ProfilePid}| TmpConfig] + catch + throw:{error, {failed_starting, App, ActualError}} -> + tsp("init_per_testcase(~w) -> failed starting ~w: " + "~n ~p", [Case, App, ActualError]), + SkipString = + "Could not start " ++ atom_to_list(App), + {skip, SkipString}; + _:X -> + SkipString = + lists:flatten( + io_lib:format("Failed starting apps: ~p", [X])), + {skip, SkipString} + end; _ -> TmpConfig2 = lists:keydelete(local_server, 1, TmpConfig), Server = @@ -1926,7 +1953,7 @@ parse_url(Config) when is_list(Config) -> %%------------------------------------------------------------------------- ipv6_ipcomm() -> - []. + [{require, ipv6_hosts}]. ipv6_ipcomm(doc) -> ["Test ip_comm ipv6."]; ipv6_ipcomm(suite) -> @@ -1942,7 +1969,7 @@ ipv6_ipcomm(Config) when is_list(Config) -> %%------------------------------------------------------------------------- ipv6_essl() -> - []. + [{require, ipv6_hosts}]. ipv6_essl(doc) -> ["Test essl ipv6."]; ipv6_essl(suite) -> @@ -1966,7 +1993,7 @@ ipv6_essl(Config) when is_list(Config) -> ipv6(SocketType, Scheme, HTTPOptions, Extra, Config) -> %% Check if we are a IPv6 host tsp("ipv6 -> verify ipv6 support", []), - case inets_test_lib:has_ipv6_support() of + case inets_test_lib:has_ipv6_support(Config) of {ok, Addr} -> tsp("ipv6 -> ipv6 supported: ~p", [Addr]), {DummyServerPid, Port} = dummy_server(SocketType, ipv6, Extra), @@ -3526,3 +3553,19 @@ dummy_ssl_server_hang_loop(_) -> ok end. + +ensure_started([]) -> + ok; +ensure_started([App|Apps]) -> + ensure_started(App), + ensure_started(Apps); +ensure_started(App) when is_atom(App) -> + case (catch application:start(App)) of + ok -> + ok; + {error, {already_started, _}} -> + ok; + Error -> + throw({error, {failed_starting, App, Error}}) + end. + diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl index 72b80a9f80..c4d4bf969b 100644 --- a/lib/inets/test/httpd_SUITE.erl +++ b/lib/inets/test/httpd_SUITE.erl @@ -208,8 +208,10 @@ ticket_7304/1]). %%% IPv6 tests --export([ipv6_hostname_ipcomm/1, ipv6_address_ipcomm/1, - ipv6_hostname_essl/1, ipv6_address_essl/1]). +-export([ipv6_hostname_ipcomm/0, ipv6_hostname_ipcomm/1, + ipv6_address_ipcomm/0, ipv6_address_ipcomm/1, + ipv6_hostname_essl/0, ipv6_hostname_essl/1, + ipv6_address_essl/0, ipv6_address_essl/1]). %% Help functions -export([cleanup_mnesia/0, setup_mnesia/0, setup_mnesia/1]). @@ -515,7 +517,7 @@ init_per_testcase2(Case, Config) -> NewConfig2 = case atom_to_list(Case) of "ipv6_" ++ _ -> - case (catch inets_test_lib:has_ipv6_support()) of + case (catch inets_test_lib:has_ipv6_support(NewConfig)) of {ok, IPv6Address0} -> {ok, Hostname} = inet:gethostname(), IPv6Address = http_transport:ipv6_name(IPv6Address0), @@ -551,18 +553,6 @@ init_per_testcase2(Case, Config) -> NewConfig end, - %% case (catch ?config(test_host_ipv6_only, Config)) of - %% {_,IPv6Host,IPv6Adress,_,_} -> - %% create_ipv6_config([{port, ?IP_PORT}, - %% {sock_type, ip_comm} | NewConfig], - %% "ipv6_hostname.conf", IPv6Host), - %% create_ipv6_config([{port, ?IP_PORT}, - %% {sock_type, ip_comm} | NewConfig], - %% "ipv6_address.conf", IPv6Adress); - %% _ -> - %% ok - %% end, - io:format(user, "~w:init_per_testcase2(~w) -> done~n", [?MODULE, Case]), @@ -2456,11 +2446,16 @@ ip_mod_cgi_chunked_encoding_test(Config) when is_list(Config) -> ok. %------------------------------------------------------------------------- + +ipv6_hostname_ipcomm() -> + [{require, ipv6_hosts}]. ipv6_hostname_ipcomm(X) -> SocketType = ip_comm, Port = ?IP_PORT, ipv6_hostname(SocketType, Port, X). +ipv6_hostname_essl() -> + [{require, ipv6_hosts}]. ipv6_hostname_essl(X) -> SocketType = essl, Port = ?SSL_PORT, @@ -2487,11 +2482,15 @@ ipv6_hostname(SocketType, Port, Config) when is_list(Config) -> %%------------------------------------------------------------------------- +ipv6_address_ipcomm() -> + [{require, ipv6_hosts}]. ipv6_address_ipcomm(X) -> SocketType = ip_comm, Port = ?IP_PORT, ipv6_address(SocketType, Port, X). +ipv6_address_essl() -> + [{require, ipv6_hosts}]. ipv6_address_essl(X) -> SocketType = essl, Port = ?SSL_PORT, @@ -3060,27 +3059,27 @@ create_ipv6_config(Config, FileName, Ipv6Address) -> BindAddress = "[" ++ Ipv6Address ++"]|inet6", - HttpConfig = [cline(["BindAddress ", BindAddress]), - cline(["Port ", integer_to_list(Port)]), - cline(["ServerName ", Host]), - cline(["SocketType ", atom_to_list(SockType)]), - cline([Mod_order]), - cline(["ServerRoot ", ServerRoot]), - cline(["DocumentRoot ", - filename:join(ServerRoot, "htdocs")]), - cline(["MaxHeaderSize ",MaxHdrSz]), - cline(["MaxHeaderAction ",MaxHdrAct]), - cline(["DirectoryIndex ", "index.html "]), - cline(["DefaultType ", "text/plain"]), - SSL], + HttpConfig = + [cline(["BindAddress ", BindAddress]), + cline(["Port ", integer_to_list(Port)]), + cline(["ServerName ", Host]), + cline(["SocketType ", atom_to_list(SockType)]), + cline([Mod_order]), + cline(["ServerRoot ", ServerRoot]), + cline(["DocumentRoot ", filename:join(ServerRoot, "htdocs")]), + cline(["MaxHeaderSize ",MaxHdrSz]), + cline(["MaxHeaderAction ",MaxHdrAct]), + cline(["DirectoryIndex ", "index.html "]), + cline(["DefaultType ", "text/plain"]), + SSL], ConfigFile = filename:join([TcTopDir,FileName]), {ok, Fd} = file:open(ConfigFile, [write]), ok = file:write(Fd, lists:flatten(HttpConfig)), ok = file:close(Fd). -tsp(F) -> - inets_test_lib:tsp(F). +%% tsp(F) -> +%% inets_test_lib:tsp(F). tsp(F, A) -> inets_test_lib:tsp(F, A). diff --git a/lib/inets/test/inets_test_lib.erl b/lib/inets/test/inets_test_lib.erl index 60164c5a72..0c3422b529 100644 --- a/lib/inets/test/inets_test_lib.erl +++ b/lib/inets/test/inets_test_lib.erl @@ -34,20 +34,54 @@ -export([tsp/1, tsp/2, tsf/1]). -export([check_body/1]). -export([millis/0, millis_diff/2, hours/1, minutes/1, seconds/1, sleep/1]). --export([oscmd/1, has_ipv6_support/0]). +-export([oscmd/1, has_ipv6_support/1]). -export([non_pc_tc_maybe_skip/4, os_based_skip/1, skip/3, fail/3]). -export([flush/0]). -export([start_node/1, stop_node/1]). %% -- Misc os command and stuff -has_ipv6_support() -> - {ok, Hostname} = inet:gethostname(), - case inet:getaddrs(Hostname, inet6) of - {ok, [Addr|_]} -> - {ok, Addr}; +has_ipv6_support(Config) -> + case lists:keysearch(ipv6_hosts, Config) of + false -> + %% Do a basic check to se if + %% our own host has a working IPv6 address... + tsp("has_ipv6_support -> no ipv6_hosts config"), + {ok, Hostname} = inet:gethostname(), + case inet:getaddrs(Hostname, inet6) of + {ok, [Addr|_]} when is_tuple(Addr) andalso + (element(1, Addr) =/= 0) -> + %% We actually need to test that the addr can be used, + %% this is done by attempting to create a (tcp) + %% listen socket + tsp("has_ipv6_support -> check Addr: ~p", [Addr]), + case (catch gen_tcp:listen(0, [inet6, {ip, Addr}])) of + {ok, LSock} -> + tsp("has_ipv6_support -> we are ipv6 host"), + gen_tcp:close(LSock), + {ok, Addr}; + _ -> + undefined + end; + _ -> + undefined + end; + {value, {_, Hosts}} when is_list(Hosts) -> + %% Check if our host is in the list of *known* IPv6 hosts + tsp("has_ipv6_support -> Hosts: ~p", [Hosts]), + {ok, Hostname} = inet:gethostname(), + case lists:member(list_to_atom(Hostname), Hosts) of + true -> + tsp("has_ipv6_support -> we are known ipv6 host"), + {ok, [Addr|_]} = inet:getaddrs(Hostname, inet6), + {ok, Addr}; + false -> + undefined + end; + _ -> undefined + end. oscmd(Cmd) -> -- cgit v1.2.3 From a6e707004f9fcb370f05bb897a6ec975f1128572 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 15 Jun 2011 11:27:05 +0200 Subject: Uppdated appup-file. --- lib/inets/src/inets_app/inets.appup.src | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src index c432ac82eb..7306578b7b 100644 --- a/lib/inets/src/inets_app/inets.appup.src +++ b/lib/inets/src/inets_app/inets.appup.src @@ -20,7 +20,10 @@ [ {"5.6", [ - {load_module, http_transport, soft_purge, soft_purge, []} + {load_module, httpc, soft_purge, soft_purge, [httpc_manager]} + {load_module, http_transport, soft_purge, soft_purge, [http_transport]}, + {update, httpc_handler, soft, soft_purge, soft_purge, []} + {update, httpc_manager, soft, soft_purge, soft_purge, [httpc_handler]} ] }, {"5.5.2", @@ -47,7 +50,10 @@ [ {"5.6", [ - {load_module, http_transport, soft_purge, soft_purge, []} + {load_module, httpc, soft_purge, soft_purge, [httpc_manager]} + {load_module, http_transport, soft_purge, soft_purge, [http_transport]}, + {update, httpc_handler, soft, soft_purge, soft_purge, []} + {update, httpc_manager, soft, soft_purge, soft_purge, [httpc_handler]} ] }, {"5.5.2", -- cgit v1.2.3 From 186428028b2f53a284b32d1a63c1ce140633cb48 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 17 Jun 2011 12:26:48 +0200 Subject: (httpc) test case cleanups. --- lib/inets/test/httpc_SUITE.erl | 15 ++++++++------- lib/inets/test/inets_test_lib.erl | 19 +++++++++++-------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 828fa54523..6edd5371af 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -386,14 +386,15 @@ init_per_testcase(Case, Timeout, Config) -> init_per_testcase_ssl(Tag, PrivDir, SslConfFile, Config) -> - tsp("init_per_testcase_ssl -> stop ssl"), + tsp("init_per_testcase_ssl(~w) -> stop ssl", [Tag]), 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)"), + tsp("init_per_testcase_ssl(~w) -> try start http server (including inets)", + [Tag]), Server = inets_test_lib:start_http_server( filename:join(PrivDir, SslConfFile), Tag), - tsp("init_per_testcase -> Server: ~p", [Server]), + tsp("init_per_testcase(~w) -> Server: ~p", [Tag, Server]), [{local_ssl_server, Server} | Config2]. @@ -1169,9 +1170,9 @@ ssl_get(SslTag, Config) when is_list(Config) -> httpc:request(get, {URL, []}, [{ssl, SSLConfig}], []), inets_test_lib:check_body(Body); {ok, _} -> - {skip, "Failed to start local http-server"}; + {skip, "local http-server not started"}; _ -> - {skip, "Failed to start SSL"} + {skip, "SSL not started"} end. @@ -1229,9 +1230,9 @@ ssl_trace(SslTag, Config) when is_list(Config) -> tsf({failed, Error}) end; {ok, _} -> - {skip, "Failed to start local http-server"}; + {skip, "local http-server not started"}; _ -> - {skip, "Failed to start SSL"} + {skip, "SSL not started"} end. diff --git a/lib/inets/test/inets_test_lib.erl b/lib/inets/test/inets_test_lib.erl index eaeb244203..fe680fb35a 100644 --- a/lib/inets/test/inets_test_lib.erl +++ b/lib/inets/test/inets_test_lib.erl @@ -133,31 +133,34 @@ start_http_server(Conf) -> start_http_server(Conf, ?HTTP_DEFAULT_SSL_KIND). start_http_server(Conf, essl = _SslTag) -> + tsp("start_http_server(essl) -> entry - try start crypto and public_key"), application:start(crypto), + application:start(public_key), do_start_http_server(Conf); -start_http_server(Conf, _SslTag) -> +start_http_server(Conf, SslTag) -> + tsp("start_http_server(~w) -> entry", [SslTag]), do_start_http_server(Conf). do_start_http_server(Conf) -> - tsp("start http server with " + tsp("do_start_http_server -> entry with" "~n Conf: ~p" "~n", [Conf]), application:load(inets), case application:set_env(inets, services, [{httpd, Conf}]) of ok -> + tsp("start_http_server -> httpd conf stored in inets app env"), case application:start(inets) of ok -> + tsp("start_http_server -> inets started"), ok; Error1 -> - test_server:format(" Failed starting application: " - "~n Error: ~p" - "~n", [Error1]), + tsp(" Failed starting application: " + "~n Error1: ~p", [Error1]), Error1 end; Error2 -> - test_server:format(" Failed set application env: " - "~n Error: ~p" - "~n", [Error2]), + tsp(" Failed set application env: " + "~n Error: ~p", [Error2]), Error2 end. -- cgit v1.2.3 From e72a9e3850acb0587e903c1c5ba236289c982006 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 17 Jun 2011 13:24:08 +0200 Subject: Fixed ipv6 support detection. --- lib/inets/test/inets_test_lib.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/inets/test/inets_test_lib.erl b/lib/inets/test/inets_test_lib.erl index fe680fb35a..2e19c41f16 100644 --- a/lib/inets/test/inets_test_lib.erl +++ b/lib/inets/test/inets_test_lib.erl @@ -42,7 +42,7 @@ %% -- Misc os command and stuff has_ipv6_support(Config) -> - case lists:keysearch(ipv6_hosts, Config) of + case lists:keysearch(ipv6_hosts, 1, Config) of false -> %% Do a basic check to se if %% our own host has a working IPv6 address... -- cgit v1.2.3 From a791e3f678d988079aa22b525dfee089d265b091 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 17 Jun 2011 13:25:50 +0200 Subject: Corrected appup-file (missing ','). --- lib/inets/src/inets_app/inets.appup.src | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src index 0c24c67fc3..8b0fcb185d 100644 --- a/lib/inets/src/inets_app/inets.appup.src +++ b/lib/inets/src/inets_app/inets.appup.src @@ -20,7 +20,7 @@ [ {"5.6", [ - {load_module, httpc, soft_purge, soft_purge, [httpc_manager]} + {load_module, httpc, soft_purge, soft_purge, [httpc_manager]}, {load_module, http_transport, soft_purge, soft_purge, [http_transport]}, {update, httpc_handler, soft, soft_purge, soft_purge, []}, {update, httpc_manager, soft, soft_purge, soft_purge, [httpc_handler]}, @@ -51,7 +51,7 @@ [ {"5.6", [ - {load_module, httpc, soft_purge, soft_purge, [httpc_manager]} + {load_module, httpc, soft_purge, soft_purge, [httpc_manager]}, {load_module, http_transport, soft_purge, soft_purge, [http_transport]}, {update, httpc_handler, soft, soft_purge, soft_purge, []}, {update, httpc_manager, soft, soft_purge, soft_purge, [httpc_handler]}, -- cgit v1.2.3 From b426e01f9a477fdd77ec19999419fda466908b51 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 22 Jun 2011 14:11:00 +0200 Subject: Fixed non-related test case (ticket_6035). --- lib/inets/test/ftp_suite_lib.erl | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/lib/inets/test/ftp_suite_lib.erl b/lib/inets/test/ftp_suite_lib.erl index d0d07a8358..3ebd02229e 100644 --- a/lib/inets/test/ftp_suite_lib.erl +++ b/lib/inets/test/ftp_suite_lib.erl @@ -1129,10 +1129,16 @@ ticket_6035(Config) -> LogFile = filename:join([PrivDir,"ticket_6035.log"]), try begin + p("ticket_6035 -> select ftpd host"), Host = dirty_select_ftpd_host(Config), + p("ticket_6035 -> ftpd host selected (~p) => now spawn ftp owner", [Host]), Pid = spawn(?MODULE, open_wait_6035, [Host, self()]), + p("ticket_6035 -> waiter spawned: ~p => now open error logfile (~p)", + [Pid, LogFile]), error_logger:logfile({open, LogFile}), - ok = kill_ftp_proc_6035(Pid,LogFile), + p("ticket_6035 -> error logfile open => now kill waiter process"), + true = kill_ftp_proc_6035(Pid, LogFile), + p("ticket_6035 -> waiter process killed => now close error logfile"), error_logger:logfile(close), p("ticket_6035 -> done", []), ok @@ -1146,7 +1152,7 @@ kill_ftp_proc_6035(Pid, LogFile) -> p("kill_ftp_proc_6035 -> entry"), receive open -> - p("kill_ftp_proc_6035 -> received open: send shutdown"), + p("kill_ftp_proc_6035 -> received open => now issue shutdown"), exit(Pid, shutdown), kill_ftp_proc_6035(Pid, LogFile); {open_failed, Reason} -> @@ -1159,11 +1165,11 @@ kill_ftp_proc_6035(Pid, LogFile) -> is_error_report_6035(LogFile) end. -open_wait_6035(FtpServer, From) -> - p("open_wait_6035 -> try connect to ~s", [FtpServer]), +open_wait_6035({Tag, FtpServer}, From) -> + p("open_wait_6035 -> try connect to [~p] ~s for ~p", [Tag, FtpServer, From]), case ftp:open(FtpServer, [{timeout, timer:seconds(15)}]) of {ok, Pid} -> - p("open_wait_6035 -> connected, now login"), + p("open_wait_6035 -> connected (~p), now login", [Pid]), LoginResult = ftp:user(Pid,"anonymous","kldjf"), p("open_wait_6035 -> login result: ~p", [LoginResult]), From ! open, @@ -1191,22 +1197,27 @@ is_error_report_6035(LogFile) -> Res = case file:read_file(LogFile) of {ok, Bin} -> - p("is_error_report_6035 -> logfile read"), - read_log_6035(binary_to_list(Bin)); + Txt = binary_to_list(Bin), + p("is_error_report_6035 -> logfile read: ~n~p", [Txt]), + read_log_6035(Txt); _ -> - ok + false end, p("is_error_report_6035 -> logfile read result: " "~n ~p", [Res]), - file:delete(LogFile), + %% file:delete(LogFile), Res. read_log_6035("=ERROR REPORT===="++_Rest) -> - error_report; -read_log_6035([_H|T]) -> + p("read_log_6035 -> ERROR REPORT detected"), + true; +read_log_6035([H|T]) -> + p("read_log_6035 -> OTHER: " + "~p", [H]), read_log_6035(T); read_log_6035([]) -> - ok. + p("read_log_6035 -> done"), + false. %%-------------------------------------------------------------------- -- cgit v1.2.3 From 7c52434e6b207e1485ce1bd00018c3f6c05e53fa Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Tue, 31 May 2011 11:52:06 +0200 Subject: The clean up of the session table now works as intended. In ssl-4.1.5 temporary clean-up processes would crash resulting in that the session table would not be cleaned up (e.i. using more and more memory) and error reports would be printed, but connections would not be affected. --- lib/ssl/src/ssl.appup.src | 2 + lib/ssl/src/ssl_manager.erl | 23 +++++++++-- lib/ssl/src/ssl_session_cache.erl | 4 +- lib/ssl/test/ssl_basic_SUITE.erl | 31 +++++++-------- lib/ssl/test/ssl_session_cache_SUITE.erl | 68 +++++++++++++++++++++++++++++++- lib/ssl/test/ssl_test_lib.erl | 3 ++ lib/ssl/vsn.mk | 2 +- 7 files changed, 109 insertions(+), 24 deletions(-) diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src index cf8867245b..29674f30da 100644 --- a/lib/ssl/src/ssl.appup.src +++ b/lib/ssl/src/ssl.appup.src @@ -1,6 +1,7 @@ %% -*- erlang -*- {"%VSN%", [ + {"4.1.5", [{restart_application, ssl}]}, {"4.1.4", [{restart_application, ssl}]}, {"4.1.3", [{restart_application, ssl}]}, {"4.1.2", [{restart_application, ssl}]}, @@ -9,6 +10,7 @@ {"4.0.1", [{restart_application, ssl}]} ], [ + {"4.1.5", [{restart_application, ssl}]}, {"4.1.4", [{restart_application, ssl}]}, {"4.1.3", [{restart_application, ssl}]}, {"4.1.2", [{restart_application, ssl}]}, diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl index 1bbb03bdde..541ca1e918 100644 --- a/lib/ssl/src/ssl_manager.erl +++ b/lib/ssl/src/ssl_manager.erl @@ -265,19 +265,22 @@ handle_cast({register_session, Port, Session}, CacheCb:update(Cache, {Port, NewSession#session.session_id}, NewSession), {noreply, State}; -handle_cast({invalidate_session, Host, Port, +%%% When a session is invalidated we need to wait a while before deleting +%%% it as there might be pending connections that rightfully needs to look +%%% up the session data but new connections should not get to use this session. +handle_cast({invalidate_session, Host, Port, #session{session_id = ID} = Session}, #state{session_cache = Cache, session_cache_cb = CacheCb} = State) -> CacheCb:update(Cache, {{Host, Port}, ID}, Session#session{is_resumable = false}), - timer:apply_after(?CLEAN_SESSION_DB, CacheCb, delete, [{{Host, Port}, ID}]), + timer:send_after(delay_time(), self(), {delayed_clean_session, {{Host, Port}, ID}}), {noreply, State}; handle_cast({invalidate_session, Port, #session{session_id = ID} = Session}, #state{session_cache = Cache, session_cache_cb = CacheCb} = State) -> CacheCb:update(Cache, {Port, ID}, Session#session{is_resumable = false}), - timer:apply_after(?CLEAN_SESSION_DB, CacheCb, delete, [{Port, ID}]), + timer:send_after(delay_time(), self(), {delayed_clean_session, {Port, ID}}), {noreply, State}; handle_cast({recache_pem, File, LastWrite, Pid, From}, @@ -312,6 +315,12 @@ handle_info(validate_sessions, #state{session_cache_cb = CacheCb, start_session_validator(Cache, CacheCb, LifeTime), {noreply, State#state{session_validation_timer = Timer}}; +handle_info({delayed_clean_session, Key}, #state{session_cache = Cache, + session_cache_cb = CacheCb + } = State) -> + CacheCb:delete(Cache, Key), + {noreply, State}; + handle_info({'EXIT', _, _}, State) -> %% Session validator died!! Do we need to take any action? %% maybe error log @@ -411,3 +420,11 @@ cache_pem_file(File, LastWrite) -> [] -> call({cache_pem, File, LastWrite}) end. + +delay_time() -> + case application:get_env(ssl, session_delay_cleanup_time) of + {ok, Time} when is_integer(Time) -> + Time; + _ -> + ?CLEAN_SESSION_DB + end. diff --git a/lib/ssl/src/ssl_session_cache.erl b/lib/ssl/src/ssl_session_cache.erl index 823bf7acfa..ae7c67bb98 100644 --- a/lib/ssl/src/ssl_session_cache.erl +++ b/lib/ssl/src/ssl_session_cache.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. 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 @@ -36,7 +36,7 @@ %% Description: Return table reference. Called by ssl_manager process. %%-------------------------------------------------------------------- init(_) -> - ets:new(cache_name(), [set, protected]). + ets:new(cache_name(), [named_table, set, protected]). %%-------------------------------------------------------------------- -spec terminate(cache_ref()) -> any(). %% diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 4f0907027f..ec287ed803 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -1659,7 +1659,7 @@ reuse_session(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client0 = @@ -1681,7 +1681,7 @@ reuse_session(Config) when is_list(Config) -> Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {from, self()}, {options, ClientOpts}]), receive {Client1, SessionInfo} -> @@ -1697,7 +1697,7 @@ reuse_session(Config) when is_list(Config) -> Client2 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {from, self()}, {options, [{reuse_sessions, false} | ClientOpts]}]), receive @@ -1713,7 +1713,7 @@ reuse_session(Config) when is_list(Config) -> Server1 = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {options, [{reuse_sessions, false} | ServerOpts]}]), Port1 = ssl_test_lib:inet_port(Server1), @@ -1737,7 +1737,7 @@ reuse_session(Config) when is_list(Config) -> Client4 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port1}, {host, Hostname}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {from, self()}, {options, ClientOpts}]), receive @@ -1756,9 +1756,6 @@ reuse_session(Config) when is_list(Config) -> ssl_test_lib:close(Client3), ssl_test_lib:close(Client4). -session_info_result(Socket) -> - ssl:session_info(Socket). - %%-------------------------------------------------------------------- reuse_session_expired(doc) -> ["Test sessions is not reused when it has expired"]; @@ -1774,7 +1771,7 @@ reuse_session_expired(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client0 = @@ -1796,7 +1793,7 @@ reuse_session_expired(Config) when is_list(Config) -> Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {from, self()}, {options, ClientOpts}]), receive {Client1, SessionInfo} -> @@ -1815,7 +1812,7 @@ reuse_session_expired(Config) when is_list(Config) -> Client2 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {from, self()}, {options, ClientOpts}]), receive {Client2, SessionInfo} -> @@ -1844,7 +1841,7 @@ server_does_not_want_to_reuse_session(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {options, [{reuse_session, fun(_,_,_,_) -> false end} | @@ -1870,7 +1867,7 @@ server_does_not_want_to_reuse_session(Config) when is_list(Config) -> Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {from, self()}, {options, ClientOpts}]), receive {Client1, SessionInfo} -> @@ -3179,7 +3176,7 @@ no_reuses_session_server_restart_new_cert(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client0 = @@ -3207,7 +3204,7 @@ no_reuses_session_server_restart_new_cert(Config) when is_list(Config) -> Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {from, self()}, {options, ClientOpts}]), receive {Client1, SessionInfo} -> @@ -3238,7 +3235,7 @@ no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {options, NewServerOpts}]), Port = ssl_test_lib:inet_port(Server), Client0 = @@ -3268,7 +3265,7 @@ no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) -> Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, - {mfa, {?MODULE, session_info_result, []}}, + {mfa, {ssl_test_lib, session_info_result, []}}, {from, self()}, {options, ClientOpts}]), receive {Client1, SessionInfo} -> diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl index a43b9ab586..62d404092f 100644 --- a/lib/ssl/test/ssl_session_cache_SUITE.erl +++ b/lib/ssl/test/ssl_session_cache_SUITE.erl @@ -29,6 +29,7 @@ -define(SLEEP, 500). -define(TIMEOUT, 60000). -define(LONG_TIMEOUT, 600000). + -behaviour(ssl_session_cache_api). %% For the session cache tests @@ -95,6 +96,16 @@ init_per_testcase(session_cache_process_mnesia, Config) -> mnesia:start(), init_customized_session_cache(mnesia, Config); +init_per_testcase(session_cleanup, Config0) -> + Config = lists:keydelete(watchdog, 1, Config0), + Dog = test_server:timetrap(?TIMEOUT), + ssl:stop(), + application:load(ssl), + application:set_env(ssl, session_lifetime, 5), + application:set_env(ssl, session_delay_cleanup_time, ?SLEEP), + ssl:start(), + [{watchdog, Dog} | Config]; + init_per_testcase(_TestCase, Config0) -> Config = lists:keydelete(watchdog, 1, Config0), Dog = test_server:timetrap(?TIMEOUT), @@ -128,6 +139,10 @@ end_per_testcase(session_cache_process_mnesia, Config) -> ssl:stop(), ssl:start(), end_per_testcase(default_action, Config); +end_per_testcase(session_cleanup, Config) -> + application:unset_env(ssl, session_delay_cleanup_time), + application:unset_env(ssl, session_lifetime), + end_per_testcase(default_action, Config); end_per_testcase(_TestCase, Config) -> Dog = ?config(watchdog, Config), case Dog of @@ -148,7 +163,8 @@ end_per_testcase(_TestCase, Config) -> suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [session_cache_process_list, + [session_cleanup, + session_cache_process_list, session_cache_process_mnesia]. groups() -> @@ -159,7 +175,57 @@ init_per_group(_GroupName, Config) -> end_per_group(_GroupName, Config) -> Config. +%%-------------------------------------------------------------------- +session_cleanup(doc) -> + ["Test that sessions are cleand up eventually, so that the session table " + "does grow and grow ..."]; +session_cleanup(suite) -> + []; +session_cleanup(Config)when is_list(Config) -> + process_flag(trap_exit, true), + 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()}, + {mfa, {ssl_test_lib, session_info_result, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {ssl_test_lib, no_result, []}}, + {from, self()}, {options, ClientOpts}]), + SessionInfo = + receive + {Server, Info} -> + Info + end, + + %% Make sure session is registered + test_server:sleep(?SLEEP), + + Id = proplists:get_value(session_id, SessionInfo), + CSession = ssl_session_cache:lookup(ssl_otp_session_cache, {{Hostname, Port}, Id}), + SSession = ssl_session_cache:lookup(ssl_otp_session_cache, {Port, Id}), + + true = CSession =/= undefined, + true = SSession =/= undefined, + + %% Make sure session has expired and been cleaned up + test_server:sleep(5000), %% Expire time + test_server:sleep(?SLEEP *4), %% Clean up delay + + undefined = ssl_session_cache:lookup(ssl_otp_session_cache, {{Hostname, Port}, Id}), + undefined = ssl_session_cache:lookup(ssl_otp_session_cache, {Port, Id}), + + process_flag(trap_exit, false), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). +%%-------------------------------------------------------------------- session_cache_process_list(doc) -> ["Test reuse of sessions (short handshake)"]; diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index 40bbdf1dbd..b7916b96eb 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -670,3 +670,6 @@ cipher_result(Socket, Result) -> Other -> {unexpected, Other} end. + +session_info_result(Socket) -> + ssl:session_info(Socket). diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk index 0e80e42637..64a7603c44 100644 --- a/lib/ssl/vsn.mk +++ b/lib/ssl/vsn.mk @@ -1 +1 @@ -SSL_VSN = 4.1.5 +SSL_VSN = 4.1.5.1 -- cgit v1.2.3