From b327123e4da61ee2794aa473d357c37e7168d189 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 13 Jan 2010 16:18:47 +0000 Subject: OTP-8016, OTP-8056, OTP-8103, OTP-8106, OTP-8312, OTP-8315, OTP-8327, OTP-8349, OTP-8351, OTP-8359 & OTP-8371. --- lib/inets/src/http_client/Makefile | 27 +- lib/inets/src/http_client/http.erl | 772 ++-------------------- lib/inets/src/http_client/httpc_response.erl | 19 +- lib/inets/src/http_lib/Makefile | 22 +- lib/inets/src/http_lib/http_chunk.erl | 21 +- lib/inets/src/http_lib/http_transport.erl | 11 +- lib/inets/src/http_lib/http_util.erl | 35 +- lib/inets/src/http_server/Makefile | 15 +- lib/inets/src/http_server/httpd.erl | 14 +- lib/inets/src/http_server/httpd_conf.erl | 19 +- lib/inets/src/http_server/httpd_instance_sup.erl | 16 +- lib/inets/src/http_server/httpd_request.erl | 17 +- lib/inets/src/http_server/httpd_sup.erl | 12 +- lib/inets/src/http_server/mod_alias.erl | 111 ++-- lib/inets/src/http_server/mod_cgi.erl | 12 +- lib/inets/src/http_server/mod_esi.erl | 51 +- lib/inets/src/inets_app/Makefile | 24 +- lib/inets/src/inets_app/inets.app.src | 15 +- lib/inets/src/inets_app/inets.appup.src | 24 +- lib/inets/src/inets_app/inets.erl | 16 +- lib/inets/src/tftp/Makefile | 20 +- lib/inets/test/Makefile | 78 ++- lib/inets/test/ftp_SUITE_data/TAR.exclude | 2 + lib/inets/test/ftp_SUITE_data/ftpd_hosts.skel | 17 + lib/inets/test/ftp_SUITE_data/inets_test_hosts | 15 - lib/inets/test/ftp_suite_lib.erl | 116 +++- lib/inets/test/ftp_ticket_test.erl | 13 +- lib/inets/test/httpc_SUITE.erl | 794 ++++++++++++++++------- lib/inets/test/httpc_cookie_SUITE.erl | 201 ++++-- lib/inets/test/httpd_SUITE.erl | 128 ++-- lib/inets/test/inets_SUITE.erl | 153 ++++- lib/inets/test/inets_sup_SUITE.erl | 92 ++- 32 files changed, 1478 insertions(+), 1404 deletions(-) create mode 100644 lib/inets/test/ftp_SUITE_data/TAR.exclude create mode 100644 lib/inets/test/ftp_SUITE_data/ftpd_hosts.skel delete mode 100644 lib/inets/test/ftp_SUITE_data/inets_test_hosts diff --git a/lib/inets/src/http_client/Makefile b/lib/inets/src/http_client/Makefile index 23170f439f..628c91421f 100644 --- a/lib/inets/src/http_client/Makefile +++ b/lib/inets/src/http_client/Makefile @@ -1,19 +1,19 @@ # # %CopyrightBegin% -# -# Copyright Ericsson AB 2005-2009. All Rights Reserved. -# +# +# Copyright Ericsson AB 2005-2010. All Rights Reserved. +# # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in # compliance with the License. You should have received a copy of the # Erlang Public License along with this software. If not, it can be # retrieved online at http://www.erlang.org/. -# +# # Software distributed under the License is distributed on an "AS IS" # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See # the License for the specific language governing rights and limitations # under the License. -# +# # %CopyrightEnd% # # @@ -22,6 +22,7 @@ include $(ERL_TOP)/make/target.mk EBIN = ../../ebin include $(ERL_TOP)/make/$(TARGET)/otp.mk + # ---------------------------------------------------- # Application version # ---------------------------------------------------- @@ -29,17 +30,20 @@ include ../../vsn.mk VSN = $(INETS_VSN) + # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- -RELSYSDIR = $(RELEASE_PATH)/lib/inets-$(VSN) +RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) + # ---------------------------------------------------- # Target Specs # ---------------------------------------------------- MODULES = \ http \ - http_cookie \ + httpc \ + httpc_cookie \ httpc_handler \ httpc_manager \ httpc_sup \ @@ -55,20 +59,24 @@ ERL_FILES = $(MODULES:%=%.erl) TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + # ---------------------------------------------------- # INETS FLAGS # ---------------------------------------------------- -INETS_FLAGS = -D'SERVER_SOFTWARE="inets/$(VSN)"' \ +INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' + # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- INETS_ERL_FLAGS += -I ../http_lib -I ../inets_app -pa ../../ebin -ERL_COMPILE_FLAGS += $(INETS_ERL_FLAGS)\ +ERL_COMPILE_FLAGS += $(INETS_ERL_FLAGS) \ $(INETS_FLAGS) \ +'{parse_transform,sys_pre_attributes}' \ +'{attribute,insert,app_vsn,$(APP_VSN)}' + + # ---------------------------------------------------- # Targets # ---------------------------------------------------- @@ -94,6 +102,7 @@ release_spec: opt release_docs_spec: info: + @echo "APPLICATION = $(APPLICATION)" @echo "INETS_DEBUG = $(INETS_DEBUG)" @echo "INETS_FLAGS = $(INETS_FLAGS)" @echo "ERL_COMPILE_FLAGS = $(ERL_COMPILE_FLAGS)" diff --git a/lib/inets/src/http_client/http.erl b/lib/inets/src/http_client/http.erl index ce5d7723f0..7e1e90b50e 100644 --- a/lib/inets/src/http_client/http.erl +++ b/lib/inets/src/http_client/http.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2002-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2002-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -24,7 +24,6 @@ %%% - RFC 2818 HTTP Over TLS -module(http). --behaviour(inets_service). %% API -export([request/1, request/2, request/4, request/5, @@ -35,15 +34,6 @@ cookie_header/2, stream_next/1, default_profile/0]). -%% Behavior callbacks --export([start_standalone/1, start_service/1, - stop_service/1, services/0, service_info/1]). - --include("http_internal.hrl"). --include("httpc_internal.hrl"). - --define(DEFAULT_PROFILE, default). - %%%========================================================================= %%% API @@ -51,751 +41,75 @@ %%-------------------------------------------------------------------------- %% request(Url [, Profile]) -> -%% {ok, {StatusLine, Headers, Body}} | {error,Reason} -%% -%% Url - string() -%% Description: Calls request/4 with default values. +%% request(Method, Request, HTTPOptions, Options [, Profile]) %%-------------------------------------------------------------------------- -request(Url) -> - request(Url, default_profile()). - -request(Url, Profile) -> - request(get, {Url, []}, [], [], Profile). - - -%%-------------------------------------------------------------------------- -%% request(Method, Request, HTTPOptions, Options [, Profile]) -> -%% {ok, {StatusLine, Headers, Body}} | {ok, {Status, Body}} | -%% {ok, RequestId} | {error,Reason} | {ok, {saved_as, FilePath} -%% -%% Method - atom() = head | get | put | post | trace | options| delete -%% Request - {Url, Headers} | {Url, Headers, ContentType, Body} -%% Url - string() -%% HTTPOptions - [HttpOption] -%% HTTPOption - {timeout, Time} | {connect_timeout, Time} | -%% {ssl, SSLOptions} | {proxy_auth, {User, Password}} -%% Ssloptions = [SSLOption] -%% SSLOption = {verify, code()} | {depth, depth()} | {certfile, path()} | -%% {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} -%% StatusLine = {HTTPVersion, StatusCode, ReasonPhrase} -%% HTTPVersion = string() -%% StatusCode = integer() -%% ReasonPhrase = string() -%% Headers = [Header] -%% Header = {Field, Value} -%% Field = string() -%% Value = string() -%% Body = string() | binary() - HTLM-code -%% -%% Description: Sends a HTTP-request. The function can be both -%% syncronus and asynchronous in the later case the function will -%% return {ok, RequestId} and later on a message will be sent to the -%% calling process on the format {http, {RequestId, {StatusLine, -%% Headers, Body}}} or {http, {RequestId, {error, Reason}}} -%%-------------------------------------------------------------------------- +request(Url) -> httpc:request(Url). +request(Url, Profile) -> httpc:request(Url, Profile). request(Method, Request, HttpOptions, Options) -> - request(Method, Request, HttpOptions, Options, default_profile()). + httpc:request(Method, Request, HttpOptions, Options). +request(Method, Request, HttpOptions, Options, Profile) -> + httpc:request(Method, Request, HttpOptions, Options, Profile). -request(Method, {Url, Headers}, HTTPOptions, Options, Profile) - when (Method =:= options) orelse - (Method =:= get) orelse - (Method =:= head) orelse - (Method =:= delete) orelse - (Method =:= trace) -> - case http_uri:parse(Url) of - {error, Reason} -> - {error, Reason}; - ParsedUrl -> - handle_request(Method, Url, ParsedUrl, Headers, [], [], - HTTPOptions, Options, Profile) - end; - -request(Method, {Url,Headers,ContentType,Body}, HTTPOptions, Options, Profile) - when (Method =:= post) orelse (Method =:= put) -> - case http_uri:parse(Url) of - {error, Reason} -> - {error, Reason}; - ParsedUrl -> - handle_request(Method, Url, - ParsedUrl, Headers, ContentType, Body, - HTTPOptions, Options, Profile) - end. %%-------------------------------------------------------------------------- -%% request(RequestId) -> ok -%% RequestId - As returned by request/4 -%% -%% Description: Cancels a HTTP-request. +%% cancel_request(RequestId [, Profile]) %%------------------------------------------------------------------------- -cancel_request(RequestId) -> - cancel_request(RequestId, default_profile()). +cancel_request(RequestId) -> + httpc:cancel_request(RequestId). cancel_request(RequestId, Profile) -> - ok = httpc_manager:cancel_request(RequestId, profile_name(Profile)), - receive - %% If the request was allready fullfilled throw away the - %% answer as the request has been canceled. - {http, {RequestId, _}} -> - ok - after 0 -> - ok - end. - - -set_option(Key, Value) -> - set_option(Key, Value, default_profile()). - -set_option(Key, Value, Profile) -> - set_options([{Key, Value}], Profile). + httpc:cancel_request(RequestId, Profile). %%-------------------------------------------------------------------------- -%% set_options(Options [, Profile]) -> ok | {error, Reason} -%% Options - [Option] -%% Profile - atom() -%% Option - {proxy, {Proxy, NoProxy}} | {max_sessions, MaxSessions} | -%% {max_pipeline_length, MaxPipeline} | -%% {pipeline_timeout, PipelineTimeout} | {cookies, CookieMode} | -%% {ipfamily, IpFamily} -%% Proxy - {Host, Port} -%% NoProxy - [Domain | HostName | IPAddress] -%% MaxSessions, MaxPipeline, PipelineTimeout = integer() -%% CookieMode - enabled | disabled | verify -%% IpFamily - inet | inet6 | inet6fb4 -%% Description: Informs the httpc_manager of the new settings. +%% set_options(Options [, Profile]) +%% set_option(Key, Value [, Profile]) %%------------------------------------------------------------------------- + set_options(Options) -> - set_options(Options, default_profile()). + httpc:set_options(Options). set_options(Options, Profile) -> - case validate_options(Options) of - {ok, Opts} -> - try httpc_manager:set_options(Opts, profile_name(Profile)) of - Result -> - Result - catch - exit:{noproc, _} -> - {error, inets_not_started} - end; - {error, Reason} -> - {error, Reason} - end. + httpc:set_options(Options, Profile). + +set_option(Key, Value) -> + httpc:set_option(Key, Value). +set_option(Key, Value, Profile) -> + httpc:set_option(Key, Value, Profile). %%-------------------------------------------------------------------------- -%% verify_cookies(SetCookieHeaders, Url [, Profile]) -> ok | {error, reason} -%% -%% -%% Description: Store the cookies from -%% in the cookie database -%% for the profile . This function shall be used when the option -%% cookie is set to verify. +%% verify_cookies(SetCookieHeaders, Url [, Profile]) %%------------------------------------------------------------------------- -verify_cookies(SetCookieHeaders, Url) -> - verify_cookies(SetCookieHeaders, Url, default_profile()). +verify_cookies(SetCookieHeaders, Url) -> + httpc:store_cookies(SetCookieHeaders, Url). verify_cookies(SetCookieHeaders, Url, Profile) -> - {_, _, Host, Port, Path, _} = http_uri:parse(Url), - ProfileName = profile_name(Profile), - Cookies = http_cookie:cookies(SetCookieHeaders, Path, Host), - try httpc_manager:store_cookies(Cookies, {Host, Port}, ProfileName) of - _ -> - ok - catch - exit:{noproc, _} -> - {error, {not_started, Profile}} - end. + httpc:store_cookies(SetCookieHeaders, Url, Profile). + %%-------------------------------------------------------------------------- -%% cookie_header(Url [, Profile]) -> Header | {error, Reason} -%% -%% Description: Returns the cookie header that would be sent when making -%% a request to . +%% cookie_header(Url [, Profile]) %%------------------------------------------------------------------------- -cookie_header(Url) -> - cookie_header(Url, default_profile()). +cookie_header(Url) -> + httpc:cookie_header(Url). cookie_header(Url, Profile) -> - try httpc_manager:cookies(Url, profile_name(Profile)) of - Header -> - Header - catch - exit:{noproc, _} -> - {error, {not_started, Profile}} - end. - - -stream_next(Pid) -> - httpc_handler:stream_next(Pid). - -%%%======================================================================== -%%% Behavior callbacks -%%%======================================================================== -start_standalone(PropList) -> - case proplists:get_value(profile, PropList) of - undefined -> - {error, no_profile}; - Profile -> - Dir = - proplists:get_value(data_dir, PropList, only_session_cookies), - httpc_manager:start_link({Profile, Dir}, stand_alone) - end. - -start_service(Config) -> - httpc_profile_sup:start_child(Config). - -stop_service(Profile) when is_atom(Profile) -> - httpc_profile_sup:stop_child(Profile); -stop_service(Pid) when is_pid(Pid) -> - case service_info(Pid) of - {ok, [{profile, Profile}]} -> - stop_service(Profile); - Error -> - Error - end. - -services() -> - [{httpc, Pid} || {_, Pid, _, _} <- - supervisor:which_children(httpc_profile_sup)]. -service_info(Pid) -> - try [{ChildName, ChildPid} || - {ChildName, ChildPid, _, _} <- - supervisor:which_children(httpc_profile_sup)] of - Children -> - child_name2info(child_name(Pid, Children)) - catch - exit:{noproc, _} -> - {error, service_not_available} - end. - - -%%%======================================================================== -%%% Internal functions -%%%======================================================================== -handle_request(Method, Url, - {Scheme, UserInfo, Host, Port, Path, Query}, - Headers, ContentType, Body, - HTTPOptions0, Options, Profile) -> - - HTTPOptions = http_options(HTTPOptions0), - Sync = proplists:get_value(sync, Options, true), - NewHeaders = lists:map(fun({Key, Val}) -> - {http_util:to_lower(Key), Val} end, - Headers), - Stream = proplists:get_value(stream, Options, none), - case {Sync, Stream} of - {true, self} -> - {error, streaming_error}; - _ -> - RecordHeaders = header_record(NewHeaders, - #http_request_h{}, - Host, - HTTPOptions#http_options.version), - Request = #request{from = self(), - scheme = Scheme, - address = {Host,Port}, - path = Path, - pquery = Query, - method = Method, - headers = RecordHeaders, - content = {ContentType,Body}, - settings = HTTPOptions, - abs_uri = Url, - userinfo = UserInfo, - stream = Stream, - headers_as_is = headers_as_is(Headers, Options)}, - try httpc_manager:request(Request, profile_name(Profile)) of - {ok, RequestId} -> - handle_answer(RequestId, Sync, Options); - {error, Reason} -> - {error, Reason} - catch - error:{noproc, _} -> - {error, {not_started, Profile}} - end - end. - - -handle_answer(RequestId, false, _) -> - {ok, RequestId}; -handle_answer(RequestId, true, Options) -> - receive - {http, {RequestId, saved_to_file}} -> - {ok, saved_to_file}; - {http, {RequestId, Result = {_,_,_}}} -> - return_answer(Options, Result); - {http, {RequestId, {error, Reason}}} -> - {error, Reason} - end. - -return_answer(Options, {{"HTTP/0.9",_,_}, _, BinBody}) -> - Body = format_body(BinBody, Options), - {ok, Body}; - -return_answer(Options, {StatusLine, Headers, BinBody}) -> - - Body = format_body(BinBody, Options), - - case proplists:get_value(full_result, Options, true) of - true -> - {ok, {StatusLine, Headers, Body}}; - false -> - {_, Status, _} = StatusLine, - {ok, {Status, Body}} - end. - -format_body(BinBody, Options) -> - case proplists:get_value(body_format, Options, string) of - string -> - binary_to_list(BinBody); - _ -> - BinBody - end. + httpc:cookie_header(Url, Profile). -%% This options is a workaround for http servers that do not follow the -%% http standard and have case sensative header parsing. Should only be -%% used if there is no other way to communicate with the server or for -%% testing purpose. -headers_as_is(Headers, Options) -> - case proplists:get_value(headers_as_is, Options, false) of - false -> - []; - true -> - Headers - end. +%%-------------------------------------------------------------------------- +%% stream_next(Pid) +%%------------------------------------------------------------------------- -http_options(HttpOptions) -> - HttpOptionsDefault = http_options_default(), - http_options(HttpOptionsDefault, HttpOptions, #http_options{}). - -http_options([], [], Acc) -> - Acc; -http_options([], HttpOptions, Acc) -> - Fun = fun(BadOption) -> - Report = io_lib:format("Invalid option ~p ignored ~n", - [BadOption]), - error_logger:info_report(Report) - end, - lists:foreach(Fun, HttpOptions), - Acc; -http_options([{Tag, Default, Idx, Post} | Defaults], HttpOptions, Acc) -> - case lists:keysearch(Tag, 1, HttpOptions) of - {value, {Tag, Val0}} -> - case Post(Val0) of - {ok, Val} -> - Acc2 = setelement(Idx, Acc, Val), - HttpOptions2 = lists:keydelete(Tag, 1, HttpOptions), - http_options(Defaults, HttpOptions2, Acc2); - error -> - Report = io_lib:format("Invalid option ~p:~p ignored ~n", - [Tag, Val0]), - error_logger:info_report(Report), - HttpOptions2 = lists:keydelete(Tag, 1, HttpOptions), - http_options(Defaults, HttpOptions2, Acc) - end; - false -> - DefaultVal = - case Default of - {value, Val} -> - Val; - {field, DefaultIdx} -> - element(DefaultIdx, Acc) - end, - Acc2 = setelement(Idx, Acc, DefaultVal), - http_options(Defaults, HttpOptions, Acc2) - end. - -http_options_default() -> - VersionPost = - fun(Value) when is_atom(Value) -> - {ok, http_util:to_upper(atom_to_list(Value))}; - (Value) when is_list(Value) -> - {ok, http_util:to_upper(Value)}; - (_) -> - error - end, - TimeoutPost = fun(Value) when is_integer(Value) andalso (Value >= 0) -> - {ok, Value}; - (infinity = Value) -> - {ok, Value}; - (_) -> - error - end, - AutoRedirectPost = fun(Value) when (Value =:= true) orelse - (Value =:= false) -> - {ok, Value}; - (_) -> - error - end, - SslPost = fun(Value) when is_list(Value) -> - {ok, Value}; - (_) -> - error - end, - ProxyAuthPost = fun({User, Passwd} = Value) when is_list(User) andalso - is_list(Passwd) -> - {ok, Value}; - (_) -> - error - end, - RelaxedPost = fun(Value) when (Value =:= true) orelse - (Value =:= false) -> - {ok, Value}; - (_) -> - error - end, - ConnTimeoutPost = - fun(Value) when is_integer(Value) andalso (Value >= 0) -> - {ok, Value}; - (infinity = Value) -> - {ok, Value}; - (_) -> - error - end, - [ - {version, {value, "HTTP/1.1"}, #http_options.version, VersionPost}, - {timeout, {value, ?HTTP_REQUEST_TIMEOUT}, #http_options.timeout, TimeoutPost}, - {autoredirect, {value, true}, #http_options.autoredirect, AutoRedirectPost}, - {ssl, {value, []}, #http_options.ssl, SslPost}, - {proxy_auth, {value, undefined}, #http_options.proxy_auth, ProxyAuthPost}, - {relaxed, {value, false}, #http_options.relaxed, RelaxedPost}, - %% this field has to be *after* the timeout field (as that field is used for the default value) - {connect_timeout, {field, #http_options.timeout}, #http_options.connect_timeout, ConnTimeoutPost} - ]. - -validate_options(Options) -> - (catch validate_options(Options, [])). - -validate_options([], ValidateOptions) -> - {ok, lists:reverse(ValidateOptions)}; - -validate_options([{proxy, Proxy} = Opt| Tail], Acc) -> - validate_proxy(Proxy), - validate_options(Tail, [Opt | Acc]); - -validate_options([{max_sessions, Value} = Opt| Tail], Acc) -> - validate_max_sessions(Value), - validate_options(Tail, [Opt | Acc]); - -validate_options([{keep_alive_timeout, Value} = Opt| Tail], Acc) -> - validate_keep_alive_timeout(Value), - validate_options(Tail, [Opt | Acc]); - -validate_options([{max_keep_alive_length, Value} = Opt| Tail], Acc) -> - validate_max_keep_alive_length(Value), - validate_options(Tail, [Opt | Acc]); - -validate_options([{pipeline_timeout, Value} = Opt| Tail], Acc) -> - validate_pipeline_timeout(Value), - validate_options(Tail, [Opt | Acc]); - -validate_options([{max_pipeline_length, Value} = Opt| Tail], Acc) -> - validate_max_pipeline_length(Value), - validate_options(Tail, [Opt | Acc]); - -validate_options([{cookies, Value} = Opt| Tail], Acc) -> - validate_cookies(Value), - validate_options(Tail, [Opt | Acc]); - -validate_options([{ipfamily, Value} = Opt| Tail], Acc) -> - validate_ipfamily(Value), - validate_options(Tail, [Opt | Acc]); - -%% For backward compatibillity -validate_options([{ipv6, Value}| Tail], Acc) -> - NewValue = validate_ipv6(Value), - Opt = {ipfamily, NewValue}, - validate_options(Tail, [Opt | Acc]); - -validate_options([{ip, Value} = Opt| Tail], Acc) -> - validate_ip(Value), - validate_options(Tail, [Opt | Acc]); - -validate_options([{port, Value} = Opt| Tail], Acc) -> - validate_port(Value), - validate_options(Tail, [Opt | Acc]); - -validate_options([{verbose, Value} = Opt| Tail], Acc) -> - validate_verbose(Value), - validate_options(Tail, [Opt | Acc]); - -validate_options([{_, _} = Opt| _], _Acc) -> - {error, {not_an_option, Opt}}. - - -validate_proxy({{ProxyHost, ProxyPort}, NoProxy} = Proxy) - when is_list(ProxyHost) andalso - is_integer(ProxyPort) andalso - is_list(NoProxy) -> - Proxy; -validate_proxy(BadProxy) -> - bad_option(proxy, BadProxy). - -validate_max_sessions(Value) when is_integer(Value) andalso (Value >= 0) -> - Value; -validate_max_sessions(BadValue) -> - bad_option(max_sessions, BadValue). - -validate_keep_alive_timeout(Value) when is_integer(Value) andalso (Value >= 0) -> - Value; -validate_keep_alive_timeout(infinity = Value) -> - Value; -validate_keep_alive_timeout(BadValue) -> - bad_option(keep_alive_timeout, BadValue). - -validate_max_keep_alive_length(Value) when is_integer(Value) andalso (Value >= 0) -> - Value; -validate_max_keep_alive_length(BadValue) -> - bad_option(max_keep_alive_length, BadValue). - -validate_pipeline_timeout(Value) when is_integer(Value) -> - Value; -validate_pipeline_timeout(infinity = Value) -> - Value; -validate_pipeline_timeout(BadValue) -> - bad_option(pipeline_timeout, BadValue). - -validate_max_pipeline_length(Value) when is_integer(Value) -> - Value; -validate_max_pipeline_length(BadValue) -> - bad_option(max_pipeline_length, BadValue). - -validate_cookies(Value) - when ((Value =:= enabled) orelse - (Value =:= disabled) orelse - (Value =:= verify)) -> - Value; -validate_cookies(BadValue) -> - bad_option(cookies, BadValue). - -validate_ipv6(Value) when (Value =:= enabled) orelse (Value =:= disabled) -> - case Value of - enabled -> - inet6fb4; - disabled -> - inet - end; -validate_ipv6(BadValue) -> - bad_option(ipv6, BadValue). - -validate_ipfamily(Value) - when (Value =:= inet) orelse (Value =:= inet6) orelse (Value =:= inet6fb4) -> - Value; -validate_ipfamily(BadValue) -> - bad_option(ipfamily, BadValue). - -validate_ip(Value) - when is_tuple(Value) andalso ((size(Value) =:= 4) orelse (size(Value) =:= 8)) -> - Value; -validate_ip(BadValue) -> - bad_option(ip, BadValue). - -validate_port(Value) when is_integer(Value) -> - Value; -validate_port(BadValue) -> - bad_option(port, BadValue). - -validate_verbose(Value) - when ((Value =:= false) orelse - (Value =:= verbose) orelse - (Value =:= debug) orelse - (Value =:= trace)) -> - ok; -validate_verbose(BadValue) -> - bad_option(verbose, BadValue). - -bad_option(Option, BadValue) -> - throw({error, {bad_option, Option, BadValue}}). - - - -header_record([], RequestHeaders, Host, Version) -> - validate_headers(RequestHeaders, Host, Version); -header_record([{"cache-control", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{'cache-control' = Val}, - Host, Version); -header_record([{"connection", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{connection = Val}, Host, - Version); -header_record([{"date", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{date = Val}, Host, - Version); -header_record([{"pragma", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{pragma = Val}, Host, - Version); -header_record([{"trailer", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{trailer = Val}, Host, - Version); -header_record([{"transfer-encoding", Val} | Rest], RequestHeaders, Host, - Version) -> - header_record(Rest, - RequestHeaders#http_request_h{'transfer-encoding' = Val}, - Host, Version); -header_record([{"upgrade", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{upgrade = Val}, Host, - Version); -header_record([{"via", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{via = Val}, Host, - Version); -header_record([{"warning", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{warning = Val}, Host, - Version); -header_record([{"accept", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{accept = Val}, Host, - Version); -header_record([{"accept-charset", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{'accept-charset' = Val}, - Host, Version); -header_record([{"accept-encoding", Val} | Rest], RequestHeaders, Host, - Version) -> - header_record(Rest, RequestHeaders#http_request_h{'accept-encoding' = Val}, - Host, Version); -header_record([{"accept-language", Val} | Rest], RequestHeaders, Host, - Version) -> - header_record(Rest, RequestHeaders#http_request_h{'accept-language' = Val}, - Host, Version); -header_record([{"authorization", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{authorization = Val}, - Host, Version); -header_record([{"expect", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{expect = Val}, Host, - Version); -header_record([{"from", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{from = Val}, Host, - Version); -header_record([{"host", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{host = Val}, Host, - Version); -header_record([{"if-match", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{'if-match' = Val}, - Host, Version); -header_record([{"if-modified-since", Val} | Rest], RequestHeaders, Host, - Version) -> - header_record(Rest, - RequestHeaders#http_request_h{'if-modified-since' = Val}, - Host, Version); -header_record([{"if-none-match", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{'if-none-match' = Val}, - Host, Version); -header_record([{"if-range", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{'if-range' = Val}, - Host, Version); - -header_record([{"if-unmodified-since", Val} | Rest], RequestHeaders, Host, - Version) -> - header_record(Rest, RequestHeaders#http_request_h{'if-unmodified-since' - = Val}, Host, Version); -header_record([{"max-forwards", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{'max-forwards' = Val}, - Host, Version); -header_record([{"proxy-authorization", Val} | Rest], RequestHeaders, Host, - Version) -> - header_record(Rest, RequestHeaders#http_request_h{'proxy-authorization' - = Val}, Host, Version); -header_record([{"range", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{range = Val}, Host, - Version); -header_record([{"referer", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{referer = Val}, Host, - Version); -header_record([{"te", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{te = Val}, Host, - Version); -header_record([{"user-agent", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{'user-agent' = Val}, - Host, Version); -header_record([{"allow", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{allow = Val}, Host, - Version); -header_record([{"content-encoding", Val} | Rest], RequestHeaders, Host, - Version) -> - header_record(Rest, - RequestHeaders#http_request_h{'content-encoding' = Val}, - Host, Version); -header_record([{"content-language", Val} | Rest], RequestHeaders, - Host, Version) -> - header_record(Rest, - RequestHeaders#http_request_h{'content-language' = Val}, - Host, Version); -header_record([{"content-length", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{'content-length' = Val}, - Host, Version); -header_record([{"content-location", Val} | Rest], RequestHeaders, - Host, Version) -> - header_record(Rest, - RequestHeaders#http_request_h{'content-location' = Val}, - Host, Version); -header_record([{"content-md5", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{'content-md5' = Val}, - Host, Version); -header_record([{"content-range", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{'content-range' = Val}, - Host, Version); -header_record([{"content-type", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{'content-type' = Val}, - Host, Version); -header_record([{"expires", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{expires = Val}, Host, - Version); -header_record([{"last-modified", Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{'last-modified' = Val}, - Host, Version); -header_record([{Key, Val} | Rest], RequestHeaders, Host, Version) -> - header_record(Rest, RequestHeaders#http_request_h{ - other = [{Key, Val} | - RequestHeaders#http_request_h.other]}, - Host, Version). +stream_next(Pid) -> + httpc:stream_next(Pid). -validate_headers(RequestHeaders = #http_request_h{te = undefined}, Host, - "HTTP/1.1" = Version) -> - validate_headers(RequestHeaders#http_request_h{te = ""}, Host, - "HTTP/1.1" = Version); -validate_headers(RequestHeaders = #http_request_h{host = undefined}, - Host, "HTTP/1.1" = Version) -> - validate_headers(RequestHeaders#http_request_h{host = Host}, Host, Version); -validate_headers(RequestHeaders, _, _) -> - RequestHeaders. +%%-------------------------------------------------------------------------- +%% default_profile() +%%------------------------------------------------------------------------- default_profile() -> - ?DEFAULT_PROFILE. - -profile_name(?DEFAULT_PROFILE) -> - httpc_manager; -profile_name(Pid) when is_pid(Pid) -> - Pid; -profile_name(Profile) -> - list_to_atom("httpc_manager_" ++ atom_to_list(Profile)). - -child_name2info(undefined) -> - {error, no_such_service}; -child_name2info(httpc_manager) -> - {ok, [{profile, default}]}; -child_name2info({http, Profile}) -> - {ok, [{profile, Profile}]}. - -child_name(_, []) -> - undefined; -child_name(Pid, [{Name, Pid} | _]) -> - Name; -child_name(Pid, [_ | Children]) -> - child_name(Pid, Children). - -%% d(F) -> -%% d(F, []). - -%% d(F, A) -> -%% d(get(dbg), F, A). - -%% d(true, F, A) -> -%% io:format(user, "~w:~w:" ++ F ++ "~n", [self(), ?MODULE | A]); -%% d(_, _, _) -> -%% ok. - + httpc:default_profile(). diff --git a/lib/inets/src/http_client/httpc_response.erl b/lib/inets/src/http_client/httpc_response.erl index e2ba66f730..df7d40a33e 100644 --- a/lib/inets/src/http_client/httpc_response.erl +++ b/lib/inets/src/http_client/httpc_response.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -132,8 +132,13 @@ result(Response = {{_,Code,_}, _, _}, Request) when (Code div 100) =:= 5 -> result(Response, Request) -> transparent(Response, Request). -send(To, Msg) -> - To ! {http, Msg}. +send(Receiver, Msg) when is_pid(Receiver) -> + Receiver ! {http, Msg}; +send(Receiver, Msg) when is_function(Receiver) -> + (catch Receiver(Msg)); +send({Module, Function, Args}, Msg) -> + (catch apply(Module, Function, [Msg | Args])). + %%%======================================================================== %%% Internal functions diff --git a/lib/inets/src/http_lib/Makefile b/lib/inets/src/http_lib/Makefile index 27e7ee65c5..7f4c92861c 100644 --- a/lib/inets/src/http_lib/Makefile +++ b/lib/inets/src/http_lib/Makefile @@ -1,19 +1,19 @@ # # %CopyrightBegin% -# -# Copyright Ericsson AB 2005-2009. All Rights Reserved. -# +# +# Copyright Ericsson AB 2005-2010. All Rights Reserved. +# # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in # compliance with the License. You should have received a copy of the # Erlang Public License along with this software. If not, it can be # retrieved online at http://www.erlang.org/. -# +# # Software distributed under the License is distributed on an "AS IS" # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See # the License for the specific language governing rights and limitations # under the License. -# +# # %CopyrightEnd% # # @@ -22,6 +22,7 @@ include $(ERL_TOP)/make/target.mk EBIN = ../../ebin include $(ERL_TOP)/make/$(TARGET)/otp.mk + # ---------------------------------------------------- # Application version # ---------------------------------------------------- @@ -29,10 +30,12 @@ include ../../vsn.mk VSN = $(INETS_VSN) + # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- -RELSYSDIR = $(RELEASE_PATH)/lib/inets-$(VSN) +RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) + # ---------------------------------------------------- # Target Specs @@ -50,10 +53,12 @@ ERL_FILES = $(MODULES:%=%.erl) TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + # ---------------------------------------------------- # INETS FLAGS # ---------------------------------------------------- -INETS_FLAGS = -D'SERVER_SOFTWARE="inets/$(VSN)"' \ +INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' + # ---------------------------------------------------- # FLAGS @@ -82,6 +87,7 @@ clean: docs: + # ---------------------------------------------------- # Release Target # ---------------------------------------------------- @@ -96,6 +102,8 @@ release_spec: opt release_docs_spec: info: + @echo "APPLICATION = $(APPLICATION)" @echo "INETS_DEBUG = $(INETS_DEBUG)" @echo "INETS_FLAGS = $(INETS_FLAGS)" @echo "ERL_COMPILE_FLAGS = $(ERL_COMPILE_FLAGS)" + diff --git a/lib/inets/src/http_lib/http_chunk.erl b/lib/inets/src/http_lib/http_chunk.erl index cd20dce9d5..621bc68eae 100644 --- a/lib/inets/src/http_lib/http_chunk.erl +++ b/lib/inets/src/http_lib/http_chunk.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% Description: Implements chunked transfer encoding see RFC2616 section @@ -186,13 +186,6 @@ decode_data(ChunkSize, TotalChunk, Info = {MaxBodySize, BodySoFar, AccLength, MaxHeaderSize, Stream}) when ChunkSize =< size(TotalChunk) -> case TotalChunk of - %% Potential last chunk - <<_:ChunkSize/binary, ?CR, ?LF, "0">> -> - {?MODULE, decode_data, [ChunkSize, TotalChunk, Info]}; - <<_:ChunkSize/binary, ?CR, ?LF, "0", ?CR>> -> - {?MODULE, decode_data, [ChunkSize, TotalChunk, Info]}; - <<_:ChunkSize/binary, ?CR, ?LF>> -> - {?MODULE, decode_data, [ChunkSize, TotalChunk, Info]}; %% Last chunk <> -> %% Note ignore_extensions will call decode_trailer/1 @@ -223,6 +216,10 @@ decode_data(ChunkSize, TotalChunk, NewBody, integer_to_list(AccLength)); %% There are more chunks, so here we go agin... + <> -> + {NewBody, NewStream} = + stream(<>, Stream), + {?MODULE, decode_size, [<<>>, [], {MaxBodySize, NewBody, AccLength, MaxHeaderSize, NewStream}]}; <> when (AccLength < MaxBodySize) or (MaxBodySize == nolimit) -> {NewBody, NewStream} = diff --git a/lib/inets/src/http_lib/http_transport.erl b/lib/inets/src/http_lib/http_transport.erl index 8100d7183a..27a950174f 100644 --- a/lib/inets/src/http_lib/http_transport.erl +++ b/lib/inets/src/http_lib/http_transport.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% % @@ -247,6 +247,7 @@ send(ip_comm, Socket, Message) -> send({ssl, _}, Socket, Message) -> ssl:send(Socket, Message). + %%------------------------------------------------------------------------- %% close(SocketType, Socket) -> ok | {error, Reason} %% SocketType = ip_comm | {ssl, _} diff --git a/lib/inets/src/http_lib/http_util.erl b/lib/inets/src/http_lib/http_util.erl index b03b780cf8..ddb58c7116 100644 --- a/lib/inets/src/http_lib/http_util.erl +++ b/lib/inets/src/http_lib/http_util.erl @@ -1,27 +1,33 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% -module(http_util). --export([to_upper/1, to_lower/1, convert_netscapecookie_date/1, +-export([ + to_upper/1, to_lower/1, + convert_netscapecookie_date/1, hexlist_to_integer/1, integer_to_hexlist/1, - convert_month/1, is_hostname/1]). + convert_month/1, + is_hostname/1, + timestamp/0, timeout/2 + ]). + %%%========================================================================= %%% Internal application API @@ -100,6 +106,21 @@ convert_month("Dec") -> 12. is_hostname(Dest) -> inet_parse:domain(Dest). + +timestamp() -> + {A,B,C} = os:timestamp(), + A*1000000000+B*1000+(C div 1000). + +timeout(Timeout, Started) -> + %% NewTimeout = Timeout - (timestamp() - Started), + case Timeout - (timestamp() - Started) of + NewTimeout when Timeout > 0 -> + NewTimeout; + _ -> + 0 + end. + + %%%======================================================================== %%% Internal functions %%%======================================================================== diff --git a/lib/inets/src/http_server/Makefile b/lib/inets/src/http_server/Makefile index 4bbd23df3f..ce1405011e 100644 --- a/lib/inets/src/http_server/Makefile +++ b/lib/inets/src/http_server/Makefile @@ -1,19 +1,19 @@ # # %CopyrightBegin% -# -# Copyright Ericsson AB 2005-2009. All Rights Reserved. -# +# +# Copyright Ericsson AB 2005-2010. All Rights Reserved. +# # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in # compliance with the License. You should have received a copy of the # Erlang Public License along with this software. If not, it can be # retrieved online at http://www.erlang.org/. -# +# # Software distributed under the License is distributed on an "AS IS" # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See # the License for the specific language governing rights and limitations # under the License. -# +# # %CopyrightEnd% # # @@ -33,7 +33,7 @@ VSN = $(INETS_VSN) # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- -RELSYSDIR = $(RELEASE_PATH)/lib/inets-$(VSN) +RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) # ---------------------------------------------------- @@ -92,7 +92,7 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) # ---------------------------------------------------- # INETS FLAGS # ---------------------------------------------------- -INETS_FLAGS = -D'SERVER_SOFTWARE="inets/$(VSN)"' +INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' # ---------------------------------------------------- @@ -133,6 +133,7 @@ release_spec: opt release_docs_spec: info: + @echo "APPLICATION = $(APPLICATION)" @echo "INETS_DEBUG = $(INETS_DEBUG)" @echo "INETS_FLAGS = $(INETS_FLAGS)" @echo "ERL_COMPILE_FLAGS = $(ERL_COMPILE_FLAGS)" diff --git a/lib/inets/src/http_server/httpd.erl b/lib/inets/src/http_server/httpd.erl index 554f162fc5..8fe54ccef6 100644 --- a/lib/inets/src/http_server/httpd.erl +++ b/lib/inets/src/http_server/httpd.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -358,7 +358,7 @@ foreach([KeyValue|Rest]) -> get_addr_and_port(ConfigFile) -> case httpd_conf:load(ConfigFile) of {ok, ConfigList} -> - case httpd_conf:validate_properties(ConfigList) of + case (catch httpd_conf:validate_properties(ConfigList)) of {ok, Config} -> Address = proplists:get_value(bind_address, Config, any), Port = proplists:get_value(port, Config, 80), @@ -506,7 +506,7 @@ get_status(Addr,Port,Timeout) when is_integer(Port) -> end. do_reload_config(ConfigList, Mode) -> - case httpd_conf:validate_properties(ConfigList) of + case (catch httpd_conf:validate_properties(ConfigList)) of {ok, Config} -> Address = proplists:get_value(bind_address, Config, any), Port = proplists:get_value(port, Config, 80), diff --git a/lib/inets/src/http_server/httpd_conf.erl b/lib/inets/src/http_server/httpd_conf.erl index 9c93e2c5fe..3e498d1db7 100644 --- a/lib/inets/src/http_server/httpd_conf.erl +++ b/lib/inets/src/http_server/httpd_conf.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -864,17 +864,22 @@ load_traverse(Line, [Context|Contexts], [Module|Modules], NewContexts, {'EXIT', {undef, _}} -> ?hdrt("does not implement load", []), load_traverse(Line, Contexts, Modules, - [Context|NewContexts], ConfigList,yes); + [Context|NewContexts], ConfigList, yes); {'EXIT', Reason} -> error_logger:error_report({'EXIT', Reason}), load_traverse(Line, Contexts, Modules, [Context|NewContexts], ConfigList, State); + ok -> + ?hdrt("line processed", []), + load_traverse(Line, Contexts, Modules, + [Context|NewContexts], ConfigList, yes); + {ok, NewContext} -> ?hdrt("line processed", [{new_context, NewContext}]), load_traverse(Line, Contexts, Modules, - [NewContext|NewContexts], ConfigList,yes); + [NewContext|NewContexts], ConfigList, yes); {ok, NewContext, ConfigEntry} when is_tuple(ConfigEntry) -> ?hdrt("line processed", diff --git a/lib/inets/src/http_server/httpd_instance_sup.erl b/lib/inets/src/http_server/httpd_instance_sup.erl index 3b5464132c..0aaeb838c2 100644 --- a/lib/inets/src/http_server/httpd_instance_sup.erl +++ b/lib/inets/src/http_server/httpd_instance_sup.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2001-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -37,7 +37,7 @@ %%% Internal Application API %%%========================================================================= start_link([{_, _}| _] = Config, AcceptTimeout, Debug) -> - case httpd_conf:validate_properties(Config) of + case (catch httpd_conf:validate_properties(Config)) of {ok, Config2} -> Address = proplists:get_value(bind_address, Config2), Port = proplists:get_value(port, Config2), @@ -66,7 +66,7 @@ start_link(ConfigFile, AcceptTimeout, Debug) -> start_link([{_, _}| _] = Config, AcceptTimeout, ListenInfo, Debug) -> - case httpd_conf:validate_properties(Config) of + case (catch httpd_conf:validate_properties(Config)) of {ok, Config2} -> Address = proplists:get_value(bind_address, Config2), Port = proplists:get_value(port, Config2), @@ -154,7 +154,7 @@ make_name(Address,Port) -> file_2_config(ConfigFile) -> case httpd_conf:load(ConfigFile) of {ok, ConfigList} -> - case httpd_conf:validate_properties(ConfigList) of + case (catch httpd_conf:validate_properties(ConfigList)) of {ok, Config} -> Address = proplists:get_value(bind_address, ConfigList), Port = proplists:get_value(port, ConfigList), diff --git a/lib/inets/src/http_server/httpd_request.erl b/lib/inets/src/http_server/httpd_request.erl index ad2cc4bda3..8eee08e766 100644 --- a/lib/inets/src/http_server/httpd_request.erl +++ b/lib/inets/src/http_server/httpd_request.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -68,10 +68,11 @@ body_data(Headers, Body) -> {binary_to_list(BodyThisReq), Next} end. + %%------------------------------------------------------------------------- %% validate(Method, Uri, Version) -> ok | {error, {bad_request, Reason} | %% {error, {not_supported, {Method, Uri, Version}} -%% Method = "HEAD" | "GET" | "POST" | "TRACE" +%% Method = "HEAD" | "GET" | "POST" | "TRACE" | "PUT" | "DELETE" %% Uri = uri() %% Version = "HTTP/N.M" %% Description: Checks that HTTP-request-line is valid. @@ -84,6 +85,10 @@ validate("GET", Uri, "HTTP/0.9") -> validate_uri(Uri); validate("GET", Uri, "HTTP/1." ++ _N) -> validate_uri(Uri); +validate("PUT", Uri, "HTTP/1." ++ _N) -> + validate_uri(Uri); +validate("DELETE", Uri, "HTTP/1." ++ _N) -> + validate_uri(Uri); validate("POST", Uri, "HTTP/1." ++ _N) -> validate_uri(Uri); validate("TRACE", Uri, "HTTP/1." ++ N) when hd(N) >= $1 -> diff --git a/lib/inets/src/http_server/httpd_sup.erl b/lib/inets/src/http_server/httpd_sup.erl index fc41994727..3399f78b53 100644 --- a/lib/inets/src/http_server/httpd_sup.erl +++ b/lib/inets/src/http_server/httpd_sup.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -169,7 +169,7 @@ httpd_child_spec([Value| _] = Config, AcceptTimeout, Debug) httpd_child_spec(ConfigFile, AcceptTimeout, Debug) -> case httpd_conf:load(ConfigFile) of {ok, ConfigList} -> - case httpd_conf:validate_properties(ConfigList) of + case (catch httpd_conf:validate_properties(ConfigList)) of {ok, Config} -> Address = proplists:get_value(bind_address, Config, any), Port = proplists:get_value(port, Config, 80), diff --git a/lib/inets/src/http_server/mod_alias.erl b/lib/inets/src/http_server/mod_alias.erl index 7073f5405d..ec0a12242f 100644 --- a/lib/inets/src/http_server/mod_alias.erl +++ b/lib/inets/src/http_server/mod_alias.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -28,44 +28,51 @@ path/3]). -include("httpd.hrl"). +-include("httpd_internal.hrl"). -define(VMODULE,"ALIAS"). %% do -do(Info) -> - case proplists:get_value(status, Info#mod.data) of +do(#mod{data = Data} = Info) -> + ?hdrt("do", []), + case proplists:get_value(status, Data) of %% A status code has been generated! {_StatusCode, _PhraseArgs, _Reason} -> - {proceed,Info#mod.data}; + {proceed, Data}; %% No status code has been generated! undefined -> - case proplists:get_value(response, Info#mod.data) of + case proplists:get_value(response, Data) of %% No response has been generated! undefined -> do_alias(Info); %% A response has been generated or sent! _Response -> - {proceed, Info#mod.data} + {proceed, Data} end end. -do_alias(Info) -> - {ShortPath, Path, AfterPath} = - real_name(Info#mod.config_db, - Info#mod.request_uri, - httpd_util:multi_lookup(Info#mod.config_db,alias)), +do_alias(#mod{config_db = ConfigDB, + request_uri = ReqURI, + data = Data}) -> + {ShortPath, Path, AfterPath} = + real_name(ConfigDB, ReqURI, which_alias(ConfigDB)), + ?hdrt("real name", + [{request_uri, ReqURI}, + {short_path, ShortPath}, + {path, Path}, + {after_path, AfterPath}]), %% Relocate if a trailing slash is missing else proceed! LastChar = lists:last(ShortPath), case file:read_file_info(ShortPath) of - {ok, FileInfo} when FileInfo#file_info.type == directory, - LastChar /= $/ -> - ServerName = httpd_util:lookup(Info#mod.config_db, server_name), - Port = port_string(httpd_util:lookup(Info#mod.config_db,port, 80)), - URL = "http://" ++ ServerName ++ Port ++ - Info#mod.request_uri ++ "/", + {ok, FileInfo} when ((FileInfo#file_info.type =:= directory) andalso + (LastChar =/= $/)) -> + ?hdrt("directory and last-char is a /", []), + ServerName = which_server_name(ConfigDB), + Port = port_string( which_port(ConfigDB) ), + URL = "http://" ++ ServerName ++ Port ++ ReqURI ++ "/", ReasonPhrase = httpd_util:reason_phrase(301), - Message = httpd_util:message(301, URL, Info#mod.config_db), + Message = httpd_util:message(301, URL, ConfigDB), {proceed, [{response, {301, ["Location: ", URL, "\r\n" @@ -76,25 +83,26 @@ do_alias(Info) -> "\n

",ReasonPhrase, "

\n", Message, "\n\n\n"]}}| - [{real_name, {Path, AfterPath}} | Info#mod.data]]}; + [{real_name, {Path, AfterPath}} | Data]]}; _NoFile -> - {proceed,[{real_name, {Path, AfterPath}} | Info#mod.data]} + {proceed, [{real_name, {Path, AfterPath}} | Data]} end. port_string(80) -> ""; port_string(Port) -> - ":"++integer_to_list(Port). + ":" ++ integer_to_list(Port). %% real_name real_name(ConfigDB, RequestURI, []) -> - DocumentRoot = httpd_util:lookup(ConfigDB, document_root, ""), + DocumentRoot = which_document_root(ConfigDB), RealName = DocumentRoot ++ RequestURI, {ShortPath, _AfterPath} = httpd_util:split_path(RealName), - {Path, AfterPath} = httpd_util:split_path(default_index(ConfigDB, - RealName)), + {Path, AfterPath} = + httpd_util:split_path(default_index(ConfigDB, RealName)), {ShortPath, Path, AfterPath}; + real_name(ConfigDB, RequestURI, [{FakeName,RealName}|Rest]) -> case inets_regexp:match(RequestURI, "^" ++ FakeName) of {match, _, _} -> @@ -105,7 +113,7 @@ real_name(ConfigDB, RequestURI, [{FakeName,RealName}|Rest]) -> httpd_util:split_path(default_index(ConfigDB, ActualName)), {ShortPath, Path, AfterPath}; nomatch -> - real_name(ConfigDB,RequestURI,Rest) + real_name(ConfigDB, RequestURI, Rest) end. %% real_script_name @@ -113,20 +121,21 @@ real_name(ConfigDB, RequestURI, [{FakeName,RealName}|Rest]) -> real_script_name(_ConfigDB, _RequestURI, []) -> not_a_script; real_script_name(ConfigDB, RequestURI, [{FakeName,RealName} | Rest]) -> - case inets_regexp:match(RequestURI,"^"++FakeName) of + case inets_regexp:match(RequestURI, "^" ++ FakeName) of {match,_,_} -> - {ok,ActualName,_}=inets_regexp:sub(RequestURI,"^"++FakeName,RealName), - httpd_util:split_script_path(default_index(ConfigDB,ActualName)); + {ok, ActualName, _} = + inets_regexp:sub(RequestURI, "^" ++ FakeName, RealName), + httpd_util:split_script_path(default_index(ConfigDB, ActualName)); nomatch -> - real_script_name(ConfigDB,RequestURI,Rest) + real_script_name(ConfigDB, RequestURI, Rest) end. %% default_index default_index(ConfigDB, Path) -> case file:read_file_info(Path) of - {ok, FileInfo} when FileInfo#file_info.type == directory -> - DirectoryIndex = httpd_util:lookup(ConfigDB, directory_index, []), + {ok, FileInfo} when FileInfo#file_info.type =:= directory -> + DirectoryIndex = which_directory_index(ConfigDB), append_index(Path, DirectoryIndex); _ -> Path @@ -147,9 +156,9 @@ append_index(RealName, [Index | Rest]) -> path(Data, ConfigDB, RequestURI) -> case proplists:get_value(real_name, Data) of undefined -> - DocumentRoot = httpd_util:lookup(ConfigDB, document_root, ""), + DocumentRoot = which_document_root(ConfigDB), {Path, _AfterPath} = - httpd_util:split_path(DocumentRoot++RequestURI), + httpd_util:split_path(DocumentRoot ++ RequestURI), Path; {Path, _AfterPath} -> Path @@ -164,7 +173,7 @@ path(Data, ConfigDB, RequestURI) -> load("DirectoryIndex " ++ DirectoryIndex, []) -> {ok, DirectoryIndexes} = inets_regexp:split(DirectoryIndex," "), {ok,[], {directory_index, DirectoryIndexes}}; -load("Alias " ++ Alias,[]) -> +load("Alias " ++ Alias, []) -> case inets_regexp:split(Alias," ") of {ok, [FakeName, RealName]} -> {ok,[],{alias,{FakeName,RealName}}}; @@ -191,13 +200,13 @@ store({directory_index, Value} = Conf, _) when is_list(Value) -> end; store({directory_index, Value}, _) -> {error, {wrong_type, {directory_index, Value}}}; -store({alias, {Fake, Real}} = Conf, _) when is_list(Fake), - is_list(Real) -> +store({alias, {Fake, Real}} = Conf, _) + when is_list(Fake) andalso is_list(Real) -> {ok, Conf}; store({alias, Value}, _) -> {error, {wrong_type, {alias, Value}}}; -store({script_alias, {Fake, Real}} = Conf, _) when is_list(Fake), - is_list(Real) -> +store({script_alias, {Fake, Real}} = Conf, _) + when is_list(Fake) andalso is_list(Real) -> {ok, Conf}; store({script_alias, Value}, _) -> {error, {wrong_type, {script_alias, Value}}}. @@ -208,3 +217,21 @@ is_directory_index_list([Head | Tail]) when is_list(Head) -> is_directory_index_list(Tail); is_directory_index_list(_) -> false. + + +%% --------------------------------------------------------------------- + +which_alias(ConfigDB) -> + httpd_util:multi_lookup(ConfigDB, alias). + +which_server_name(ConfigDB) -> + httpd_util:lookup(ConfigDB, server_name). + +which_port(ConfigDB) -> + httpd_util:lookup(ConfigDB, port, 80). + +which_document_root(ConfigDB) -> + httpd_util:lookup(ConfigDB, document_root, ""). + +which_directory_index(ConfigDB) -> + httpd_util:lookup(ConfigDB, directory_index, []). diff --git a/lib/inets/src/http_server/mod_cgi.erl b/lib/inets/src/http_server/mod_cgi.erl index ab12a3b57b..33605b9698 100644 --- a/lib/inets/src/http_server/mod_cgi.erl +++ b/lib/inets/src/http_server/mod_cgi.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -335,6 +335,8 @@ script_elements(#mod{method = "GET"}, {PathInfo, QueryString}) -> [{query_string, QueryString}, {path_info, PathInfo}]; script_elements(#mod{method = "POST", entity_body = Body}, _) -> [{entity_body, Body}]; +script_elements(#mod{method = "PUT", entity_body = Body}, _) -> + [{entity_body, Body}]; script_elements(_, _) -> []. diff --git a/lib/inets/src/http_server/mod_esi.erl b/lib/inets/src/http_server/mod_esi.erl index dd6f62ae2d..484d4b3fb4 100644 --- a/lib/inets/src/http_server/mod_esi.erl +++ b/lib/inets/src/http_server/mod_esi.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -249,7 +249,24 @@ erl(#mod{method = Method} = ModData, ESIBody, Modules) {proceed, [{status,{400, none, BadRequest}} | ModData#mod.data]} end; -erl(#mod{method = "POST", entity_body = Body} = ModData, ESIBody, Modules) -> +erl(#mod{request_uri = ReqUri, + method = "PUT", + http_version = Version, + data = Data}, _ESIBody, _Modules) -> + {proceed, [{status,{501,{"PUT", ReqUri, Version}, + ?NICE("Erl mechanism doesn't support method PUT")}}| + Data]}; + +erl(#mod{request_uri = ReqUri, + method = "DELETE", + http_version = Version, + data = Data}, _ESIBody, _Modules) -> + {proceed,[{status,{501,{"DELETE", ReqUri, Version}, + ?NICE("Erl mechanism doesn't support method DELETE")}}| + Data]}; + +erl(#mod{method = "POST", + entity_body = Body} = ModData, ESIBody, Modules) -> case httpd_util:split(ESIBody,":|%3A|/",2) of {ok,[ModuleName, Function]} -> generate_webpage(ModData, ESIBody, Modules, @@ -444,8 +461,26 @@ input_type([_First|Rest]) -> %%------------------------ Eval mechanism -------------------------------- -eval(#mod{request_uri = ReqUri, method = "POST", - http_version = Version, data = Data}, _ESIBody, _Modules) -> +eval(#mod{request_uri = ReqUri, + method = "PUT", + http_version = Version, + data = Data}, _ESIBody, _Modules) -> + {proceed,[{status,{501,{"PUT", ReqUri, Version}, + ?NICE("Eval mechanism doesn't support method PUT")}}| + Data]}; + +eval(#mod{request_uri = ReqUri, + method = "DELETE", + http_version = Version, + data = Data}, _ESIBody, _Modules) -> + {proceed,[{status,{501,{"DELETE", ReqUri, Version}, + ?NICE("Eval mechanism doesn't support method DELETE")}}| + Data]}; + +eval(#mod{request_uri = ReqUri, + method = "POST", + http_version = Version, + data = Data}, _ESIBody, _Modules) -> {proceed,[{status,{501,{"POST", ReqUri, Version}, ?NICE("Eval mechanism doesn't support method POST")}}| Data]}; diff --git a/lib/inets/src/inets_app/Makefile b/lib/inets/src/inets_app/Makefile index 2dab99386a..33c9e34a3a 100644 --- a/lib/inets/src/inets_app/Makefile +++ b/lib/inets/src/inets_app/Makefile @@ -1,19 +1,19 @@ # # %CopyrightBegin% -# -# Copyright Ericsson AB 2005-2009. All Rights Reserved. -# +# +# Copyright Ericsson AB 2005-2010. All Rights Reserved. +# # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in # compliance with the License. You should have received a copy of the # Erlang Public License along with this software. If not, it can be # retrieved online at http://www.erlang.org/. -# +# # Software distributed under the License is distributed on an "AS IS" # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See # the License for the specific language governing rights and limitations # under the License. -# +# # %CopyrightEnd% # # @@ -22,6 +22,7 @@ include $(ERL_TOP)/make/target.mk EBIN = ../../ebin include $(ERL_TOP)/make/$(TARGET)/otp.mk + # ---------------------------------------------------- # Application version # ---------------------------------------------------- @@ -32,12 +33,13 @@ VSN = $(INETS_VSN) # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- -RELSYSDIR = $(RELEASE_PATH)/lib/inets-$(VSN) +RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) # ---------------------------------------------------- # Target Specs # ---------------------------------------------------- + MODULES = \ inets_service \ inets \ @@ -49,7 +51,8 @@ HRL_FILES = inets_internal.hrl ERL_FILES = $(MODULES:%=%.erl) -TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) \ +TARGET_FILES= \ + $(MODULES:%=$(EBIN)/%.$(EMULATOR)) \ $(APP_TARGET) \ $(APPUP_TARGET) @@ -66,7 +69,7 @@ APPUP_TARGET = $(EBIN)/$(APPUP_FILE) # ---------------------------------------------------- # INETS FLAGS # ---------------------------------------------------- -INETS_FLAGS = -D'SERVER_SOFTWARE="inets/$(VSN)"' \ +INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' # ---------------------------------------------------- @@ -108,14 +111,15 @@ $(APPUP_TARGET): $(APPUP_SRC) ../../vsn.mk include $(ERL_TOP)/make/otp_release_targets.mk release_spec: opt - $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/src $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src - $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/ebin $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin release_docs_spec: info: + @echo "APPLICATION = $(APPLICATION)" @echo "INETS_DEBUG = $(INETS_DEBUG)" @echo "INETS_FLAGS = $(INETS_FLAGS)" @echo "ERL_COMPILE_FLAGS = $(ERL_COMPILE_FLAGS)" diff --git a/lib/inets/src/inets_app/inets.app.src b/lib/inets/src/inets_app/inets.app.src index 6524c3b19b..04f6365b98 100644 --- a/lib/inets/src/inets_app/inets.app.src +++ b/lib/inets/src/inets_app/inets.app.src @@ -1,19 +1,19 @@ %% This is an -*- erlang -*- file. %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -34,7 +34,8 @@ ftp_sup, %% HTTP client: - http, + http, %% Old client API module + httpc, %% New client API module httpc_handler, httpc_handler_sup, httpc_manager, @@ -42,7 +43,7 @@ httpc_request, httpc_response, httpc_sup, - http_cookie, + httpc_cookie, http_uri, %% Proably will by used by server also in the future diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src index 0112a64239..2efa7ccb60 100644 --- a/lib/inets/src/inets_app/inets.appup.src +++ b/lib/inets/src/inets_app/inets.appup.src @@ -1,34 +1,31 @@ %% This is an -*- erlang -*- file. %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1999-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% {"%VSN%", [ {"5.2", [ - {load_module, inets, soft_purge, soft_purge, []} + {restart_application, inets} ] }, {"5.1.3", [ - {load_module, httpd_response, soft_purge, soft_purge, []}, - {update, ftp, {advanced, upgrade_from_pre_5_12}, - soft_purge, soft_purge, []}, - {update, httpc_handler, soft, soft_purge, soft_purge, []} + {restart_application, inets} ] }, {"5.1.2", @@ -40,15 +37,12 @@ [ {"5.2", [ - {load_module, inets, soft_purge, soft_purge, []} + {restart_application, inets} ] }, {"5.1.3", [ - {load_module, httpd_response, soft_purge, soft_purge, []}, - {update, ftp, {advanced, downgrade_to_pre_5_12}, - soft_purge, soft_purge, []}, - {update, httpc_handler, soft, soft_purge, soft_purge, []} + {restart_application, inets} ] }, {"5.1.2", diff --git a/lib/inets/src/inets_app/inets.erl b/lib/inets/src/inets_app/inets.erl index 77cb14cc20..7e3f862ee7 100644 --- a/lib/inets/src/inets_app/inets.erl +++ b/lib/inets/src/inets_app/inets.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2006-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -522,9 +522,7 @@ change_pattern({Mod, Service, Pattern}) catch exit:{Where, Reason} -> {error, {Where, Reason}} - end; - _ -> - exit({bad_pattern, Pattern}) + end end, ok. @@ -728,7 +726,7 @@ call_service(Service, Call, Args) -> service_module(tftpd) -> tftp; service_module(httpc) -> - http; + httpc; service_module(ftpc) -> ftp; service_module(Service) -> diff --git a/lib/inets/src/tftp/Makefile b/lib/inets/src/tftp/Makefile index 63f70f7943..b4339da1e2 100644 --- a/lib/inets/src/tftp/Makefile +++ b/lib/inets/src/tftp/Makefile @@ -1,19 +1,19 @@ # # %CopyrightBegin% -# -# Copyright Ericsson AB 2005-2009. All Rights Reserved. -# +# +# Copyright Ericsson AB 2005-2010. All Rights Reserved. +# # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in # compliance with the License. You should have received a copy of the # Erlang Public License along with this software. If not, it can be # retrieved online at http://www.erlang.org/. -# +# # Software distributed under the License is distributed on an "AS IS" # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See # the License for the specific language governing rights and limitations # under the License. -# +# # %CopyrightEnd% # # @@ -33,7 +33,8 @@ VSN = $(INETS_VSN) # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- -RELSYSDIR = $(RELEASE_PATH)/lib/inets-$(VSN) +RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) + # ---------------------------------------------------- # Target Specs @@ -53,10 +54,12 @@ ERL_FILES = $(MODULES:%=%.erl) TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + # ---------------------------------------------------- # INETS FLAGS # ---------------------------------------------------- -INETS_FLAGS = -D'SERVER_SOFTWARE="inets/$(VSN)"' \ +INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"' + # ---------------------------------------------------- # FLAGS @@ -64,6 +67,8 @@ INETS_FLAGS = -D'SERVER_SOFTWARE="inets/$(VSN)"' \ ERL_COMPILE_FLAGS += $(INETS_FLAGS) \ +'{parse_transform,sys_pre_attributes}' \ +'{attribute,insert,app_vsn,$(APP_VSN)}' + + # ---------------------------------------------------- # Targets # ---------------------------------------------------- @@ -90,6 +95,7 @@ release_spec: opt release_docs_spec: info: + @echo "APPLICATION = $(APPLICATION)" @echo "INETS_DEBUG = $(INETS_DEBUG)" @echo "INETS_FLAGS = $(INETS_FLAGS)" @echo "ERL_COMPILE_FLAGS = $(ERL_COMPILE_FLAGS)" diff --git a/lib/inets/test/Makefile b/lib/inets/test/Makefile index d13ffea544..1dd7a51717 100644 --- a/lib/inets/test/Makefile +++ b/lib/inets/test/Makefile @@ -1,19 +1,19 @@ # # %CopyrightBegin% -# -# Copyright Ericsson AB 1997-2009. All Rights Reserved. -# +# +# Copyright Ericsson AB 1997-2010. All Rights Reserved. +# # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in # compliance with the License. You should have received a copy of the # Erlang Public License along with this software. If not, it can be # retrieved online at http://www.erlang.org/. -# +# # Software distributed under the License is distributed on an "AS IS" # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See # the License for the specific language governing rights and limitations # under the License. -# +# # %CopyrightEnd% # # @@ -31,6 +31,12 @@ include ../vsn.mk VSN = $(INETS_VSN) +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) + + # ---------------------------------------------------- # Target Specs # ---------------------------------------------------- @@ -188,22 +194,26 @@ HRL_FILES = inets_test_lib.hrl \ ERL_FILES = $(MODULES:%=%.erl) -TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR)) - -INETS_FILES = Makefile.inets rules.mk suite_targets.mk \ - inets.config inets.spec inets.spec.vxworks - - SOURCE = $(ERL_FILES) $(HRL_FILES) +TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + INETS_SPECS = inets.spec inets.spec.vxworks +INETS_FILES = inets.config $(INETS_SPECS) -INETS_DATADIR = inets_SUITE_data inets_sup_SUITE_data -HTTPD_DATADIR = httpd_test_data httpd_SUITE_data -HTTPC_DATADIR = httpc_SUITE_data -FTP_DATADIR = ftp_SUITE_data +# SUB_SUITES = \ +# inets_sup_suite \ +# inets_httpd_suite \ +# inets_httpc_suite \ +# inets_ftp_suite \ +# inets_tftp_suite -DATADIRS = $(INETS_DATADIR) $(HTTPD_DATADIR) $(HTTPC_DATADIR) $(FTP_DATADIR) +INETS_DATADIRS = inets_SUITE_data inets_sup_SUITE_data +HTTPD_DATADIRS = httpd_test_data httpd_SUITE_data +HTTPC_DATADIRS = httpc_SUITE_data +FTP_DATADIRS = ftp_SUITE_data + +DATADIRS = $(INETS_DATADIRS) $(HTTPD_DATADIRS) $(HTTPC_DATADIRS) $(FTP_DATADIRS) EMAKEFILE = Emakefile MAKE_EMAKE = $(wildcard $(ERL_TOP)/make/make_emakefile) @@ -216,10 +226,10 @@ BUILDTARGET = emakebuild RELTEST_FILES = $(EMAKEFILE) $(INETS_SPECS) $(SOURCE) endif + # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- -RELSYSDIR = $(RELEASE_PATH)/lib/inets-$(VSN) RELTESTSYSDIR = $(RELEASE_PATH)/inets_test RELTESTSYSALLDATADIR = $(RELTESTSYSDIR)/all_SUITE_data @@ -276,9 +286,19 @@ release_spec: opt $(INSTALL_DIR) $(RELSYSDIR)/test $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/test $(INSTALL_DATA) $(INETS_FILES) $(RELSYSDIR)/test - $(INSTALL_DIR) $(RELSYSDIR)/test/$(HTTPD_DATADIR) - tar chf - -C $(HTTPD_DATADIR) . | (cd $(RELSYSDIR)/test/$(HTTPD_DATADIR); tar xf -) - (cd $(RELSYSDIR)/test; mv Makefile.inets Makefile) + @for d in $(DATADIRS); do \ + echo "installing data dir $$d"; \ + echo $$d/TAR.exclude2 > $$d/TAR.exclude2; \ + cat $$d/TAR.exclude >> $$d/TAR.exclude2; \ + find $$d -name '*.contrib*' >> $$d/TAR.exclude2; \ + find $$d -name '*.keep*' >> $$d/TAR.exclude2; \ + find $$d -name '*.mkelem*' >> $$d/TAR.exclude2; \ + find $$d -name '*~' >> $$d/TAR.exclude2; \ + find $$d -name 'erl_crash.dump' >> $$d/TAR.exclude2; \ + find $$d -name 'core' >> $$d/TAR.exclude2; \ + find $$d -name '.cmake.state' >> $$d/TAR.exclude2; \ + tar cfX - $$d/TAR.exclude2 $$d | (cd $(RELSYSDIR)/test; tar xf -); \ + done release_tests_spec: opt $(INSTALL_DIR) $(RELTESTSYSDIR) @@ -287,7 +307,6 @@ release_tests_spec: opt tar chf - $(DATADIRS) | (cd $(RELTESTSYSDIR); tar xf -) $(INSTALL_DIR) $(RELTESTSYSALLDATADIR) $(INSTALL_DATA) $(MAKEFILE_SRC) $(RELTESTSYSALLDATADIR)/Makefile.src - $(INSTALL_DATA) copy_files.erl $(RELTESTSYSALLDATADIR)/copy_files.erl $(INSTALL_DIR) $(RELTESTSYSBINDIR) chmod -f -R +x $(RELTESTSYSBINDIR) tar cf - -C $(INETS_SSL_LIB_DIR) . | (cd $(RELTESTSYSALLDATADIR); tar xf -) @@ -301,7 +320,24 @@ info: @echo "MAKE_EMAKE = $(MAKE_EMAKE)" @echo "EMAKEFILE = $(EMAKEFILE)" @echo "BUILDTARGET = $(BUILDTARGET)" + @echo "" + @echo "MODULES = $(MODULES)" + @echo "ERL_FILES = $(ERL_FILES)" + @echo "SOURCE = $(SOURCE)" @echo "TARGET_FILES = $(TARGET_FILES)" + @echo "" + @echo "INETS_SPECS = $(INETS_SPECS)" + @echo "INETS_FILES = $(INETS_FILES)" + @echo "" + @echo "RELEASE_PATH = $(RELEASE_PATH)" + @echo "RELSYSDIR = $(RELSYSDIR)" + @echo "RELTESTSYSDIR = $(RELTESTSYSDIR)" + @echo "RELTESTSYSALLDATADIR = $(RELTESTSYSALLDATADIR)" + @echo "RELTESTSYSBINDIR = $(RELTESTSYSBINDIR)" + @echo "" + @echo "DATADIRS = $(DATADIRS)" + @echo "REL_DATADIRS = $(REL_DATADIRS)" + @echo "" @echo "INETS_DATA_DIR = $(INETS_DATA_DIR)" @echo "INETS_PRIV_DIR = $(INETS_PRIV_DIR)" @echo "INETS_SSL_LIB_DIR = $(INETS_SSL_LIB_DIR)" diff --git a/lib/inets/test/ftp_SUITE_data/TAR.exclude b/lib/inets/test/ftp_SUITE_data/TAR.exclude new file mode 100644 index 0000000000..2078965740 --- /dev/null +++ b/lib/inets/test/ftp_SUITE_data/TAR.exclude @@ -0,0 +1,2 @@ +ftp_SUITE_data/TAR.exclude +ftp_SUITE_data/ftpd_hosts diff --git a/lib/inets/test/ftp_SUITE_data/ftpd_hosts.skel b/lib/inets/test/ftp_SUITE_data/ftpd_hosts.skel new file mode 100644 index 0000000000..a820f8d014 --- /dev/null +++ b/lib/inets/test/ftp_SUITE_data/ftpd_hosts.skel @@ -0,0 +1,17 @@ +%% Add a host name in the appropriate list +%% Each "platform" contains a list of hostnames (a string) that can +%% be used for testing the ftp client. +[{solaris8_sparc, []}, + {solaris9_sparc, []}, + {solaris10_sparc, []}, + {solaris10_x86, []}, + {linux_x86, []}, + {linux_ppc, []}, + {macosx_ppc, []}, + {macosx_x86, []}, + {openbsd_x86, []}, + {freebsd_x86, []}, + {netbsd_x86, []}, + {windows_xp, []}, + {windows_2003_server, []}, + {ticket_test, []}]. diff --git a/lib/inets/test/ftp_SUITE_data/inets_test_hosts b/lib/inets/test/ftp_SUITE_data/inets_test_hosts deleted file mode 100644 index 20623b9edc..0000000000 --- a/lib/inets/test/ftp_SUITE_data/inets_test_hosts +++ /dev/null @@ -1,15 +0,0 @@ -%% Add a host name in the appropriate list -[{solaris8_sparc, ["fingon"]}, - {solaris9_sparc, []}, - {solaris10_sparc, []}, - {solaris10_x86, []}, - {linux_x86, []}, - {linux_ppc, []}, - {macosx_ppc, []}, - {macosx_x86, []}, - {openbsd_x86, []}, - {freebsd_x86, []}, - {netbsd_x86, []}, - {windows_xp, []}, - {windows_2003_server, ["fobi"]}, - {ticket_test,["fingon","finrod"]}]. diff --git a/lib/inets/test/ftp_suite_lib.erl b/lib/inets/test/ftp_suite_lib.erl index 29339da6e5..75e1a5a7f9 100644 --- a/lib/inets/test/ftp_suite_lib.erl +++ b/lib/inets/test/ftp_suite_lib.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -23,6 +23,7 @@ -include("test_server.hrl"). -include("test_server_line.hrl"). +-include("inets_test_lib.hrl"). %% Test server specific exports % -export([init_per_testcase/2, end_per_testcase/2]). @@ -37,7 +38,6 @@ --define(FTP_HOSTS(X),ftp_hosts(X)). -define(FTP_USER, "anonymous"). -define(FTP_PASS, passwd()). -define(FTP_PORT, 21). @@ -73,7 +73,7 @@ ftpd_init(FtpdTag, Config) -> Hosts = case ?config(ftpd_hosts, Config) of undefined -> - ?FTP_HOSTS(data_dir(Config)); + ftpd_hosts(data_dir(Config)); H -> H end, @@ -123,6 +123,59 @@ get_ftpd_host([Host|Hosts]) -> get_ftpd_host(Hosts) end. + +%%-------------------------------------------------------------------- + +dirty_select_ftpd_host(Config) -> + Hosts = + case ?config(ftpd_hosts, Config) of + undefined -> + ftpd_hosts(data_dir(Config)); + H -> + H + end, + dirty_select_ftpd_host2(Hosts). + +dirty_select_ftpd_host2([]) -> + throw({error, not_found}); +dirty_select_ftpd_host2([{PlatformTag, Hosts} | PlatformHosts]) -> + case dirty_select_ftpd_host3(Hosts) of + none -> + dirty_select_ftpd_host2(PlatformHosts); + {ok, Host} -> + {PlatformTag, Host} + end. + +dirty_select_ftpd_host3([]) -> + none; +dirty_select_ftpd_host3([Host|Hosts]) when is_list(Host) -> + case dirty_select_ftpd_host4(Host) of + true -> + {ok, Host}; + false -> + dirty_select_ftpd_host3(Hosts) + end; +dirty_select_ftpd_host3([_|Hosts]) -> + dirty_select_ftpd_host3(Hosts). + +%% This is a very simple and dirty test that there is a +%% (FTP) deamon on the other end. +dirty_select_ftpd_host4(Host) -> + Port = 21, + IpFam = inet, + Opts = [IpFam, binary, {packet, 0}, {active, false}], + Timeout = ?SECS(5), + case gen_tcp:connect(Host, Port, Opts, Timeout) of + {ok, Sock} -> + gen_tcp:close(Sock), + true; + _Error -> + false + end. + + +%%-------------------------------------------------------------------- + test_filenames() -> {ok, Host} = inet:gethostname(), File = Host ++ "_ftp_test.txt", @@ -1048,12 +1101,20 @@ ticket_6035(Config) -> "~n Config: ~p", [Config]), PrivDir = ?config(priv_dir, Config), LogFile = filename:join([PrivDir,"ticket_6035.log"]), - Pid = spawn(?MODULE,open_wait_6035,[self()]), - error_logger:logfile({open,LogFile}), - ok = kill_ftp_proc_6035(Pid,LogFile), - error_logger:logfile(close), - p("ticket_6035 -> done", []), - ok. + try + begin + Host = dirty_select_ftpd_host(Config), + Pid = spawn(?MODULE, open_wait_6035, [Host, self()]), + error_logger:logfile({open, LogFile}), + ok = kill_ftp_proc_6035(Pid,LogFile), + error_logger:logfile(close), + p("ticket_6035 -> done", []), + ok + end + catch + throw:{error, not_found} -> + {skip, "No available FTP servers"} + end. kill_ftp_proc_6035(Pid, LogFile) -> p("kill_ftp_proc_6035 -> entry"), @@ -1072,8 +1133,7 @@ kill_ftp_proc_6035(Pid, LogFile) -> is_error_report_6035(LogFile) end. -open_wait_6035(From) -> - FtpServer = "elrond", +open_wait_6035(FtpServer, From) -> p("open_wait_6035 -> try connect to ~s", [FtpServer]), case ftp:open(FtpServer, [{timeout, timer:seconds(15)}]) of {ok, Pid} -> @@ -1491,14 +1551,15 @@ passwd() -> end, "ftp_SUITE@" ++ Host. -ftp_hosts(Config) -> - DataDir = ?config(data_dir,Config), - FileName = filename:join([DataDir,"../ftp_SUITE_data/",inets_test_hosts]), - io:format("FileName: ~p~n",[FileName]), +ftpd_hosts(Config) -> + DataDir = ?config(data_dir, Config), + FileName = filename:join([DataDir, "../ftp_SUITE_data/", ftpd_hosts]), + io:format("FileName: ~p~n", [FileName]), case file:consult(FileName) of - {ok,[Hosts]} when is_list(Hosts) -> + {ok, [Hosts]} when is_list(Hosts) -> Hosts; - _ -> [] + _ -> + [] end. wrapper(Prefix,doc,Func) -> @@ -1507,13 +1568,14 @@ wrapper(_,X,Func) -> Func(X). data_dir(Config) -> - case ?config(data_dir,Config) of + case ?config(data_dir, Config) of List when (length(List) > 0) -> - PathList = filename:split(List), - {NewPathList,_} = lists:split((length(PathList)-1),PathList), - DataDir=filename:join(NewPathList++[ftp_SUITE_data]), - _NewConfig = lists:keyreplace(data_dir,1,Config, - {data_dir,DataDir}); + PathList = filename:split(List), + {NewPathList,_} = lists:split((length(PathList)-1), PathList), + DataDir = filename:join(NewPathList ++ [ftp_SUITE_data]), + NewConfig = + lists:keyreplace(data_dir,1,Config, {data_dir,DataDir}), + NewConfig; _ -> Config end. diff --git a/lib/inets/test/ftp_ticket_test.erl b/lib/inets/test/ftp_ticket_test.erl index 96e443fab5..6748df03bb 100644 --- a/lib/inets/test/ftp_ticket_test.erl +++ b/lib/inets/test/ftp_ticket_test.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2006-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -39,8 +39,7 @@ all(suite) -> {conf,init,tickets(),fin}. init(Config) -> - [{ftp_remote_host, "elrond"}|Config]. -% ?LIB_MOD:ftpd_init(ticket_test,Config). + ?LIB_MOD:ftpd_init(ticket_test, Config). tickets() -> [ticket_6035]. diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 3485966307..4914a16264 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -1,25 +1,28 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% +%% +%% ts:run(inets, httpc_SUITE, [batch]). +%% + -module(httpc_SUITE). --author('ingela@erix.ericsson.se'). -include("test_server.hrl"). -include("test_server_line.hrl"). @@ -55,6 +58,7 @@ %% Description: Returns documentation/test cases in this test suite %% or a skip tuple if the platform is not supported. %%-------------------------------------------------------------------- + all(doc) -> ["Test the http client in the intes application."]; all(suite) -> @@ -93,7 +97,7 @@ all(suite) -> http_server_does_not_exist, http_invalid_http, http_emulate_lower_versions, - http_relaxed, + http_relaxed, page_does_not_exist, proxy_page_does_not_exist, proxy_https_not_supported, @@ -138,12 +142,12 @@ init_per_suite(Config) -> end, {ok, FileInfo} = file:read_file_info(Cgi), - ok = file:write_file_info(Cgi, - FileInfo#file_info{mode = 8#00755}), + ok = file:write_file_info(Cgi, FileInfo#file_info{mode = 8#00755}), - [{server_root, ServerRoot}, {doc_root, DocRoot}, - {local_port, ?IP_PORT}, {local_ssl_port, ?SSL_PORT} - | Config]. + [{server_root, ServerRoot}, + {doc_root, DocRoot}, + {local_port, ?IP_PORT}, + {local_ssl_port, ?SSL_PORT} | Config]. %%-------------------------------------------------------------------- %% Function: end_per_suite(Config) -> _ @@ -170,11 +174,17 @@ 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(Case, Config) -> - io:format(user, "~n~n*** INIT ~w:~w ***~n~n", [?MODULE,Case]), + init_per_testcase(Case, 2, Config). + +init_per_testcase(Case, Timeout, Config) -> + io:format(user, "~n~n*** INIT ~w:~w[~w] ***~n~n", + [?MODULE, Timeout, Case]), PrivDir = ?config(priv_dir, Config), application:stop(inets), - Dog = test_server:timetrap(inets_test_lib:minutes(10)), + Dog = test_server:timetrap(inets_test_lib:minutes(Timeout)), TmpConfig = lists:keydelete(watchdog, 1, Config), IpConfFile = integer_to_list(?IP_PORT) ++ ".conf", SslConfFile = integer_to_list(?SSL_PORT) ++ ".conf", @@ -185,11 +195,10 @@ init_per_testcase(Case, Config) -> application:stop(ssl), TmpConfig2 = lists:keydelete(local_ssl_server, 1, TmpConfig), + %% Will start inets Server = - %% Will start inets - inets_test_lib:start_http_server( - filename:join(PrivDir, - SslConfFile)), + inets_test_lib:start_http_server( + filename:join(PrivDir, SslConfFile)), [{watchdog, Dog}, {local_ssl_server, Server} | TmpConfig2]; "proxy" ++ Rest -> case Rest of @@ -224,7 +233,8 @@ init_per_testcase(Case, Config) -> http:set_options([{proxy, {{?PROXY, ?PROXY_PORT}, ["localhost", ?IPV6_LOCAL_HOST]}}]), - inets:enable_trace(max, io), + inets:enable_trace(max, io, httpc), + %% snmp:set_trace([gen_tcp, inet_tcp, prim_inet]), NewConfig. %%-------------------------------------------------------------------- @@ -269,7 +279,10 @@ tickets(suite) -> no_content_204_otp_6982, missing_CR_otp_7304, otp_7883, - otp_8154 + otp_8154, + otp_8106, + otp_8056, + otp_8371 ]. @@ -295,9 +308,9 @@ http_head(Config) when is_list(Config) -> {ok, {{_,200,_}, [_ | _], []}} -> ok; {ok, WrongReply} -> - test_server:fail({wrong_reply, WrongReply}); + tsf({wrong_reply, WrongReply}); Error -> - test_server:fail({failed, Error}) + tsf({failed, Error}) end; _ -> {skip, "Failed to start local http-server"} @@ -308,28 +321,47 @@ http_get(doc) -> http_get(suite) -> []; http_get(Config) when is_list(Config) -> - case ?config(local_server, Config) of + tsp("http_get -> entry with" + "~n Config: ~p", [Config]), + case ?config(local_server, Config) of ok -> - Port = ?config(local_port, Config), - URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", - Timeout = timer:seconds(1), - ConnTimeout = Timeout + timer:seconds(1), - {ok, {{_,200,_}, [_ | _], Body = [_ | _]}} = - http:request(get, {URL, []}, - [{timeout, Timeout}, {connect_timeout, ConnTimeout}], []), - %% eqvivivalent to http:request(get, {URL, []}, [], []), - inets_test_lib:check_body(Body), - {ok, {{_,200,_}, [_ | _], Bin}} = - http:request(get, {URL, []}, [], [{body_format, binary}]), - case Bin of - Bin when is_binary(Bin) -> - ok; - _ -> - test_server:fail(body_format_not_binary) - end; - _ -> - {skip, "Failed to start local http-server"} - end. + tsp("local-server running"), + Method = get, + Port = ?config(local_port, Config), + URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", + Request = {URL, []}, + Timeout = timer:seconds(1), + ConnTimeout = Timeout + timer:seconds(1), + HttpOptions1 = [{timeout, Timeout}, {connect_timeout, ConnTimeout}], + Options1 = [], + Body = + case http:request(Method, Request, HttpOptions1, Options1) of + {ok, {{_,200,_}, [_ | _], ReplyBody = [_ | _]}} -> + ReplyBody; + {ok, UnexpectedReply1} -> + tsf({unexpected_reply, UnexpectedReply1}); + {error, _} = Error1 -> + tsf({bad_reply, Error1}) + end, + + %% eqvivivalent to http:request(get, {URL, []}, [], []), + inets_test_lib:check_body(Body), + + HttpOptions2 = [], + Options2 = [{body_format, binary}], + case http:request(Method, Request, HttpOptions2, Options2) of + {ok, {{_,200,_}, [_ | _], Bin}} when is_binary(Bin) -> + ok; + {ok, {{_,200,_}, [_ | _], BadBin}} -> + tsf({body_format_not_binary, BadBin}); + {ok, UnexpectedReply2} -> + tsf({unexpected_reply, UnexpectedReply2}); + {error, _} = Error2 -> + tsf({bad_reply, Error2}) + end; + _ -> + {skip, "Failed to start local http-server"} + end. %%------------------------------------------------------------------------- http_post(doc) -> @@ -389,7 +421,9 @@ http_emulate_lower_versions(Config) when is_list(Config) -> {skip, "Failed to start local http-server"} end. + %%------------------------------------------------------------------------- + http_relaxed(doc) -> ["Test relaxed mode"]; http_relaxed(suite) -> @@ -397,12 +431,7 @@ http_relaxed(suite) -> http_relaxed(Config) when is_list(Config) -> ok = http:set_options([{ipv6, disabled}]), % also test the old option %% ok = http:set_options([{ipfamily, inet}]), - DummyServerPid = dummy_server(self(), ipv4), - - Port = receive - {port, ServerPort} -> - ServerPort - end, + {DummyServerPid, Port} = dummy_server(self(), ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/missing_reason_phrase.html", @@ -428,13 +457,8 @@ http_dummy_pipe(suite) -> []; http_dummy_pipe(Config) when is_list(Config) -> ok = http:set_options([{ipfamily, inet}]), - DummyServerPid = dummy_server(self(), ipv4), + {DummyServerPid, Port} = dummy_server(self(), ipv4), - Port = receive - {port, ServerPort} -> - ServerPort - end, - URL = ?URL_START ++ integer_to_list(Port) ++ "/foobar.html", test_pipeline(URL), @@ -451,78 +475,126 @@ http_inets_pipe(Config) when is_list(Config) -> case ?config(local_server, Config) of ok -> - Port = ?config(local_port, Config), - URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", + Port = ?config(local_port, Config), + URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", test_pipeline(URL); _ -> {skip, "Failed to start local http-server"} end. test_pipeline(URL) -> - + p("test_pipeline -> entry with" + "~n URL: ~p", [URL]), + http:set_options([{pipeline_timeout, 50000}]), + p("test_pipeline -> issue (async) request 1"), {ok, RequestId1} = http:request(get, {URL, []}, [], [{sync, false}]), test_server:format("RequestId1: ~p~n", [RequestId1]), + p("test_pipeline -> RequestId1: ~p", [RequestId1]), %% Make sure pipeline is initiated + p("test_pipeline -> sleep some", []), test_server:sleep(4000), + p("test_pipeline -> issue (async) request 2"), {ok, RequestId2} = http:request(get, {URL, []}, [], [{sync, false}]), - test_server:format("RequestId2: ~p~n", [RequestId2]), + tsp("RequestId2: ~p", [RequestId2]), + p("test_pipeline -> RequestId2: ~p", [RequestId2]), - {ok, {{_,200,_}, [_ | _], [_ | _]}} - = http:request(get, {URL, []}, [], []), + p("test_pipeline -> issue (sync) request 3"), + {ok, {{_,200,_}, [_ | _], [_ | _]}} = + http:request(get, {URL, []}, [], []), + + p("test_pipeline -> expect reply for (async) request 1 or 2"), receive {http, {RequestId1, {{_, 200, _}, _, _}}} -> + p("test_pipeline -> received reply for (async) request 1 - now wait for 2"), receive {http, {RequestId2, {{_, 200, _}, _, _}}} -> + p("test_pipeline -> received reply for (async) request 2"), ok; {http, Msg1} -> test_server:fail(Msg1) end; {http, {RequestId2, {{_, 200, _}, _, _}}} -> + io:format("test_pipeline -> received reply for (async) request 2 - now wait for 1"), receive {http, {RequestId1, {{_, 200, _}, _, _}}} -> + io:format("test_pipeline -> received reply for (async) request 1"), ok; {http, Msg2} -> test_server:fail(Msg2) end; {http, Msg3} -> - test_server:fail(Msg3) + test_server:fail(Msg3) + after 60000 -> + receive Any1 -> + tsp("received crap after timeout: ~n ~p", [Any1]), + test_server:fail({error, {timeout, Any1}}) + end end, + p("test_pipeline -> sleep some"), + test_server:sleep(4000), + + p("test_pipeline -> issue (async) request 4"), {ok, RequestId3} = - http:request(get, {URL, []}, [], [{sync, false}]), - test_server:format("RequestId3: ~p~n", [RequestId3]), + http:request(get, {URL, []}, [], [{sync, false}]), + tsp("RequestId3: ~p", [RequestId3]), + p("test_pipeline -> RequestId3: ~p", [RequestId3]), + + p("test_pipeline -> issue (async) request 5"), {ok, RequestId4} = http:request(get, {URL, []}, [], [{sync, false}]), - test_server:format("RequestId4: ~p~n", [RequestId4]), + tsp("RequestId4: ~p~n", [RequestId4]), + p("test_pipeline -> RequestId4: ~p", [RequestId4]), + + p("test_pipeline -> cancel (async) request 4"), ok = http:cancel_request(RequestId3), + + p("test_pipeline -> expect *no* reply for cancelled (async) request 4 (for 3 secs)"), receive {http, {RequestId3, _}} -> - test_server:fail(http_cancel_request_failed) + test_server:fail(http_cancel_request_failed) after 3000 -> ok end, + + p("test_pipeline -> expect reply for (async) request 4"), Body = receive - Res = {http, {RequestId4, {{_, 200, _}, _, BinBody4}}} -> - test_server:format(" Receive : ~p~n", [Res]), + {http, {RequestId4, {{_, 200, _}, _, BinBody4}}} = Res -> + p("test_pipeline -> received reply for (async) request 5"), + tsp("Receive : ~p", [Res]), BinBody4; {http, Msg4} -> test_server:fail(Msg4) + after 60000 -> + receive Any2 -> + tsp("received crap after timeout: ~n ~p", [Any2]), + test_server:fail({error, {timeout, Any2}}) + end end, + + p("test_pipeline -> check reply for (async) request 5"), inets_test_lib:check_body(binary_to_list(Body)), + p("test_pipeline -> ensure no unexpected incomming"), receive {http, Any} -> test_server:fail({unexpected_message, Any}) after 500 -> ok - end. + end, + + p("test_pipeline -> done"), + ok. + + + %%------------------------------------------------------------------------- http_trace(doc) -> ["Perform a TRACE request that goes through a proxy."]; @@ -700,12 +772,7 @@ http_headers_dummy(suite) -> []; http_headers_dummy(Config) when is_list(Config) -> ok = http:set_options([{ipfamily, inet}]), - DummyServerPid = dummy_server(self(), ipv4), - - Port = receive - {port, ServerPort} -> - ServerPort - end, + {DummyServerPid, Port} = dummy_server(self(), ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy_headers.html", @@ -770,12 +837,7 @@ http_bad_response(suite) -> []; http_bad_response(Config) when is_list(Config) -> ok = http:set_options([{ipfamily, inet}]), - DummyServerPid = dummy_server(self(), ipv4), - - Port = receive - {port, ServerPort} -> - ServerPort - end, + {DummyServerPid, Port} = dummy_server(self(), ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/missing_crlf.html", @@ -868,64 +930,90 @@ http_redirect(doc) -> http_redirect(suite) -> []; http_redirect(Config) when is_list(Config) -> + tsp("http_redirect -> entry with" + "~n Config: ~p", [Config]), case ?config(local_server, Config) of ok -> + tsp("http_redirect -> set ipfamily option to inet"), ok = http:set_options([{ipfamily, inet}]), - DummyServerPid = dummy_server(self(), ipv4), - - Port = receive - {port, ServerPort} -> - ServerPort - end, + + tsp("http_redirect -> start dummy server inet"), + {DummyServerPid, Port} = dummy_server(self(), ipv4), + tsp("http_redirect -> server port = ~p", [Port]), URL300 = ?URL_START ++ integer_to_list(Port) ++ "/300.html", + tsp("http_redirect -> issue request 1: " + "~n ~p", [URL300]), {ok, {{_,200,_}, [_ | _], [_|_]}} = http:request(get, {URL300, []}, [], []), - {ok, {{_,300,_}, [_ | _], _}} - = http:request(get, {URL300, []}, [{autoredirect, false}], - []), + tsp("http_redirect -> issue request 2: " + "~n ~p", [URL300]), + {ok, {{_,300,_}, [_ | _], _}} = + http:request(get, {URL300, []}, [{autoredirect, false}], []), URL301 = ?URL_START ++ integer_to_list(Port) ++ "/301.html", - + tsp("http_redirect -> issue request 3: " + "~n ~p", [URL301]), {ok, {{_,200,_}, [_ | _], [_|_]}} = http:request(get, {URL301, []}, [], []), + tsp("http_redirect -> issue request 4: " + "~n ~p", [URL301]), {ok, {{_,200,_}, [_ | _], []}} = http:request(head, {URL301, []}, [], []), + tsp("http_redirect -> issue request 5: " + "~n ~p", [URL301]), {ok, {{_,301,_}, [_ | _], [_|_]}} = http:request(post, {URL301, [],"text/plain", "foobar"}, [], []), URL302 = ?URL_START ++ integer_to_list(Port) ++ "/302.html", + tsp("http_redirect -> issue request 6: " + "~n ~p", [URL302]), {ok, {{_,200,_}, [_ | _], [_|_]}} = http:request(get, {URL302, []}, [], []), + tsp("http_redirect -> issue request 7: " + "~n ~p", [URL302]), {ok, {{_,200,_}, [_ | _], []}} = http:request(head, {URL302, []}, [], []), + tsp("http_redirect -> issue request 8: " + "~n ~p", [URL302]), {ok, {{_,302,_}, [_ | _], [_|_]}} = http:request(post, {URL302, [],"text/plain", "foobar"}, [], []), URL307 = ?URL_START ++ integer_to_list(Port) ++ "/307.html", + tsp("http_redirect -> issue request 9: " + "~n ~p", [URL307]), {ok, {{_,200,_}, [_ | _], [_|_]}} = http:request(get, {URL307, []}, [], []), + tsp("http_redirect -> issue request 10: " + "~n ~p", [URL307]), {ok, {{_,200,_}, [_ | _], []}} = http:request(head, {URL307, []}, [], []), + tsp("http_redirect -> issue request 11: " + "~n ~p", [URL307]), {ok, {{_,307,_}, [_ | _], [_|_]}} = http:request(post, {URL307, [],"text/plain", "foobar"}, [], []), + tsp("http_redirect -> stop dummy server"), DummyServerPid ! stop, - ok = http:set_options([{ipfamily, inet6fb4}]); % ********** ipfamily = inet6 ************* + tsp("http_redirect -> reset ipfamily option (to inet6fb4)"), + ok = http:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* + tsp("http_redirect -> done"), + ok; + _ -> {skip, "Failed to start local http-server"} end. @@ -938,12 +1026,7 @@ http_redirect_loop(suite) -> []; http_redirect_loop(Config) when is_list(Config) -> ok = http:set_options([{ipfamily, inet}]), - DummyServerPid = dummy_server(self(), ipv4), - - Port = receive - {port, ServerPort} -> - ServerPort - end, + {DummyServerPid, Port} = dummy_server(self(), ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/redirectloop.html", @@ -960,12 +1043,7 @@ http_internal_server_error(suite) -> []; http_internal_server_error(Config) when is_list(Config) -> ok = http:set_options([{ipfamily, inet}]), - DummyServerPid = dummy_server(self(), ipv4), - - Port = receive - {port, ServerPort} -> - ServerPort - end, + {DummyServerPid, Port} = dummy_server(self(), ipv4), URL500 = ?URL_START ++ integer_to_list(Port) ++ "/500.html", @@ -1001,12 +1079,7 @@ http_userinfo(suite) -> http_userinfo(Config) when is_list(Config) -> ok = http:set_options([{ipfamily, inet}]), - DummyServerPid = dummy_server(self(), ipv4), - - Port = receive - {port, ServerPort} -> - ServerPort - end, + {DummyServerPid, Port} = dummy_server(self(), ipv4), URLAuth = "http://alladin:sesame@localhost:" ++ integer_to_list(Port) ++ "/userinfo.html", @@ -1032,12 +1105,7 @@ http_cookie(suite) -> []; http_cookie(Config) when is_list(Config) -> ok = http:set_options([{cookies, enabled}, {ipfamily, inet}]), - DummyServerPid = dummy_server(self(), ipv4), - - Port = receive - {port, ServerPort} -> - ServerPort - end, + {DummyServerPid, Port} = dummy_server(self(), ipv4), URLStart = ?URL_START ++ integer_to_list(Port), @@ -1335,8 +1403,8 @@ proxy_https_not_supported(doc) -> proxy_https_not_supported(suite) -> []; proxy_https_not_supported(Config) when is_list(Config) -> - {error, https_through_proxy_is_not_currently_supported} - = http:request(get, {"https://login.yahoo.com", []}, [], []), + {error, {failed_connecting, https_through_proxy_is_not_currently_supported}} = + http:request(get, {"https://login.yahoo.com", []}, [], []), ok. @@ -1374,51 +1442,68 @@ http_stream_once(doc) -> http_stream_once(suite) -> []; http_stream_once(Config) when is_list(Config) -> + p("http_stream_once -> entry with" + "~n Config: ~p", [Config]), + + p("http_stream_once -> set ipfamily to inet", []), ok = http:set_options([{ipfamily, inet}]), - DummyServerPid = dummy_server(self(), ipv4), - Port = receive - {port, ServerPort} -> - ServerPort - end, + p("http_stream_once -> start dummy server", []), + {DummyServerPid, Port} = dummy_server(self(), ipv4), PortStr = integer_to_list(Port), + p("http_stream_once -> once", []), once(?URL_START ++ PortStr ++ "/once.html"), + p("http_stream_once -> once_chunked", []), once(?URL_START ++ PortStr ++ "/once_chunked.html"), + p("http_stream_once -> dummy", []), once(?URL_START ++ PortStr ++ "/dummy.html"), + p("http_stream_once -> stop dummy server", []), DummyServerPid ! stop, + p("http_stream_once -> set ipfamily to inet6fb4", []), ok = http:set_options([{ipfamily, inet6fb4}]), % ********** ipfamily = inet6 ************* + p("http_stream_once -> done", []), ok. once(URL) -> + p("once -> issue sync request for ~p", [URL]), {ok, {{_,200,_}, [_ | _], Body}} = http:request(get, {URL, []}, [], []), + p("once -> issue async (self stream) request for ~p", [URL]), {ok, RequestId} = http:request(get, {URL, []}, [], [{sync, false}, {stream, {self, once}}]), - NewPid = receive - {http, {RequestId, stream_start, _Headers, Pid}} -> - Pid; - {http, Msg} -> - test_server:fail(Msg) - end, + p("once -> await stream_start reply for (async) request ~p", [RequestId]), + NewPid = + receive + {http, {RequestId, stream_start, _Headers, Pid}} -> + p("once -> received stream_start reply for (async) request ~p: ~p", + [RequestId, Pid]), + Pid; + {http, Msg} -> + test_server:fail(Msg) + end, - test_server:format("Request handler: ~p~n", [NewPid]), + tsp("once -> request handler: ~p", [NewPid]), + p("once -> await stream reply for (async) request ~p", [RequestId]), BodyPart = receive {http, {RequestId, stream, BinBodyPart}} -> + p("once -> received stream reply for (async) request ~p: " + "~n~p", [RequestId, binary_to_list(BinBodyPart)]), BinBodyPart end, - test_server:format("First body part: ~p~n", - [binary_to_list(BodyPart)]), + tsp("once -> first body part '~p' received", [binary_to_list(BodyPart)]), StreamedBody = receive_streamed_body(RequestId, BinBodyPart, NewPid), Body = binary_to_list(StreamedBody), + + p("once -> done when Bode: ~p", [Body]), ok. @@ -1509,12 +1594,7 @@ ipv6(Config) when is_list(Config) -> case lists:member(list_to_atom(Hostname), ?config(ipv6_hosts, Config)) of true -> - DummyServerPid = dummy_server(self(), ipv6), - - Port = receive - {port, ServerPort} -> - ServerPort - end, + {DummyServerPid, Port} = dummy_server(self(), ipv6), URL = "http://[" ++ ?IPV6_LOCAL_HOST ++ "]:" ++ integer_to_list(Port) ++ "/foobar.html", @@ -1576,12 +1656,7 @@ http_invalid_http(suite) -> []; http_invalid_http(Config) when is_list(Config) -> ok = http:set_options([{ipfamily, inet}]), - DummyServerPid = dummy_server(self(), ipv4), - - Port = receive - {port, ServerPort} -> - ServerPort - end, + {DummyServerPid, Port} = dummy_server(self(), ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/invalid_http.html", @@ -1638,12 +1713,7 @@ transfer_encoding_otp_6807(suite) -> []; transfer_encoding_otp_6807(Config) when is_list(Config) -> ok = http:set_options([{ipfamily, inet}]), - DummyServerPid = dummy_server(self(), ipv4), - - Port = receive - {port, ServerPort} -> - ServerPort - end, + {DummyServerPid, Port} = dummy_server(self(), ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/capital_transfer_encoding.html", @@ -1676,12 +1746,7 @@ empty_response_header_otp_6830(suite) -> []; empty_response_header_otp_6830(Config) when is_list(Config) -> ok = http:set_options([{ipfamily, inet}]), - DummyServerPid = dummy_server(self(), ipv4), - - Port = receive - {port, ServerPort} -> - ServerPort - end, + {DummyServerPid, Port} = dummy_server(self(), ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/no_headers.html", {ok, {{_,200,_}, [], [_ | _]}} = http:request(URL), @@ -1698,12 +1763,7 @@ no_content_204_otp_6982(suite) -> []; no_content_204_otp_6982(Config) when is_list(Config) -> ok = http:set_options([{ipfamily, inet}]), - DummyServerPid = dummy_server(self(), ipv4), - - Port = receive - {port, ServerPort} -> - ServerPort - end, + {DummyServerPid, Port} = dummy_server(self(), ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/no_content.html", {ok, {{_,204,_}, [], []}} = http:request(URL), @@ -1721,12 +1781,7 @@ missing_CR_otp_7304(suite) -> []; missing_CR_otp_7304(Config) when is_list(Config) -> ok = http:set_options([{ipfamily, inet}]), - DummyServerPid = dummy_server(self(), ipv4), - - Port = receive - {port, ServerPort} -> - ServerPort - end, + {DummyServerPid, Port} = dummy_server(self(), ipv4), URL = ?URL_START ++ integer_to_list(Port) ++ "/missing_CR.html", {ok, {{_,200,_}, _, [_ | _]}} = http:request(URL), @@ -1747,13 +1802,8 @@ otp_7883_1(suite) -> otp_7883_1(Config) when is_list(Config) -> ok = http:set_options([{ipfamily, inet}]), - DummyServerPid = dummy_server(self(), ipv4), + {DummyServerPid, Port} = dummy_server(self(), ipv4), - Port = receive - {port, ServerPort} -> - ServerPort - end, - URL = ?URL_START ++ integer_to_list(Port) ++ "/just_close.html", {error, socket_closed_remotely} = http:request(URL), DummyServerPid ! stop, @@ -1768,13 +1818,8 @@ otp_7883_2(suite) -> otp_7883_2(Config) when is_list(Config) -> ok = http:set_options([{ipfamily, inet}]), - DummyServerPid = dummy_server(self(), ipv4), + {DummyServerPid, Port} = dummy_server(self(), ipv4), - Port = receive - {port, ServerPort} -> - ServerPort - end, - URL = ?URL_START ++ integer_to_list(Port) ++ "/just_close.html", Method = get, Request = {URL, []}, @@ -1810,7 +1855,7 @@ otp_8154_1(Config) when is_list(Config) -> {ok, Server, Port} = start_slow_server(RespSeqNumServer), Clients = run_clients(105, Port, ReqSeqNumServer), %% ok = wait_for_clients(Clients), - ok = wait4clients(Clients, timer:minutes(2)), + ok = wait4clients(Clients, timer:minutes(3)), Server ! shutdown, RespSeqNumServer ! shutdown, ReqSeqNumServer ! shutdown, @@ -1820,6 +1865,7 @@ start_inets() -> inets:start(), ok. + %% ----------------------------------------------------- %% A sequence number handler %% The purpose is to be able to pair requests with responses. @@ -1886,25 +1932,25 @@ run_clients(NumClients, ServerPort, SeqNumServer) -> end, lists:seq(1, NumClients)). -wait_for_clients(Clients) -> - lists:foreach( - fun({Id, Pid, MRef}) -> - io:format("waiting for client ~w termination~n", [Id]), - receive - {'DOWN', MRef, process, Pid, normal} -> - io:format("waiting for clients: " - "normal exit from ~w (~p)~n", - [Id, Pid]), - ok; - {'DOWN', MRef, process, Pid, Reason} -> - io:format("waiting for clients: " - "unexpected exit from ~w (~p):" - "~n Reason: ~p" - "~n", [Id, Pid, Reason]), - erlang:error(Reason) - end - end, - Clients). +%% wait_for_clients(Clients) -> +%% lists:foreach( +%% fun({Id, Pid, MRef}) -> +%% io:format("waiting for client ~w termination~n", [Id]), +%% receive +%% {'DOWN', MRef, process, Pid, normal} -> +%% io:format("waiting for clients: " +%% "normal exit from ~w (~p)~n", +%% [Id, Pid]), +%% ok; +%% {'DOWN', MRef, process, Pid, Reason} -> +%% io:format("waiting for clients: " +%% "unexpected exit from ~w (~p):" +%% "~n Reason: ~p" +%% "~n", [Id, Pid, Reason]), +%% erlang:error(Reason) +%% end +%% end, +%% Clients). wait4clients([], _Timeout) -> @@ -2074,6 +2120,201 @@ f(F, A) -> lists:flatten(io_lib:format(F,A)). +%%------------------------------------------------------------------------- + +otp_8106(suite) -> + [ + otp_8106_pid, + otp_8106_fun, + otp_8106_mfa + ]. + + +otp_8106_pid(doc) -> + ["OTP-8106 - deliver reply info using \"other\" pid"]; +otp_8106_pid(suite) -> + []; +otp_8106_pid(Config) when is_list(Config) -> + case ?config(local_server, Config) of + ok -> + ReceiverPid = create_receiver(pid), + Receiver = ReceiverPid, + + otp8106(ReceiverPid, Receiver, Config), + + stop_receiver(ReceiverPid), + + ok; + _ -> + {skip, "Failed to start local http-server"} + end. + + +otp_8106_fun(doc) -> + ["OTP-8106 - deliver reply info using fun"]; +otp_8106_fun(suite) -> + []; +otp_8106_fun(Config) when is_list(Config) -> + case ?config(local_server, Config) of + ok -> + ReceiverPid = create_receiver(function), + Receiver = otp_8106_deliver_fun(ReceiverPid), + + otp8106(ReceiverPid, Receiver, Config), + + stop_receiver(ReceiverPid), + + ok; + _ -> + {skip, "Failed to start local http-server"} + end. + + +otp_8106_mfa(doc) -> + ["OTP-8106 - deliver reply info using mfa callback"]; +otp_8106_mfa(suite) -> + []; +otp_8106_mfa(Config) when is_list(Config) -> + case ?config(local_server, Config) of + ok -> + ReceiverPid = create_receiver(mfa), + Receiver = {?MODULE, otp_8106_deliver, [mfa, ReceiverPid]}, + + otp8106(ReceiverPid, Receiver, Config), + + stop_receiver(ReceiverPid), + + ok; + _ -> + {skip, "Failed to start local http-server"} + end. + + + otp8106(ReceiverPid, Receiver, Config) -> + Port = ?config(local_port, Config), + URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", + Request = {URL, []}, + HTTPOptions = [], + Options = [{sync, false}, {receiver, Receiver}], + + {ok, RequestId} = + httpc:request(get, Request, HTTPOptions, Options), + + Body = + receive + {reply, ReceiverPid, {RequestId, {{_, 200, _}, _, B}}} -> + B; + {reply, ReceiverPid, Msg} -> + tsf(Msg); + {bad_reply, ReceiverPid, Msg} -> + tsf(Msg) + end, + + inets_test_lib:check_body(binary_to_list(Body)), + ok. + + +create_receiver(Type) -> + Parent = self(), + Receiver = fun() -> receiver(Type, Parent) end, + spawn_link(Receiver). + +stop_receiver(Pid) -> + Pid ! {stop, self()}. + +receiver(Type, Parent) -> + receive + {stop, Parent} -> + exit(normal); + + {http, ReplyInfo} when (Type =:= pid) -> + Parent ! {reply, self(), ReplyInfo}, + receiver(Type, Parent); + + {Type, ReplyInfo} -> + Parent ! {reply, self(), ReplyInfo}, + receiver(Type, Parent); + + Crap -> + Parent ! {reply, self(), {bad_reply, Crap}}, + receiver(Type, Parent) + end. + + +otp_8106_deliver_fun(ReceiverPid) -> + fun(ReplyInfo) -> otp_8106_deliver(ReplyInfo, function, ReceiverPid) end. + +otp_8106_deliver(ReplyInfo, Type, ReceiverPid) -> + ReceiverPid ! {Type, ReplyInfo}, + ok. + + + +%%------------------------------------------------------------------------- + +otp_8056(doc) -> + "OTP-8056"; +otp_8056(suite) -> + []; +otp_8056(Config) when is_list(Config) -> + Method = get, + Port = ?config(local_port, Config), + URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", + Request = {URL, []}, + HTTPOptions = [], + Options1 = [{sync, true}, {stream, {self, once}}], + Options2 = [{sync, true}, {stream, self}], + {error, streaming_error} = httpc:request(Method, Request, + HTTPOptions, Options1), + tsp("request 1 failed as expected"), + {error, streaming_error} = httpc:request(Method, Request, + HTTPOptions, Options2), + tsp("request 2 failed as expected"), + ok. + + +%%------------------------------------------------------------------------- + +otp_8371(doc) -> + ["OTP-8371"]; +otp_8371(suite) -> + []; +otp_8371(Config) when is_list(Config) -> + ok = http:set_options([{ipv6, disabled}]), % also test the old option + {DummyServerPid, Port} = dummy_server(self(), ipv4), + + URL = ?URL_START ++ integer_to_list(Port) ++ + "/ensure_host_header_with_port.html", + + case http:request(get, {URL, []}, [], []) of + {ok, Result} -> + case Result of + {{_, 200, _}, _Headers, Body} -> + tsp("expected response with" + "~n Body: ~p", [Body]), + ok; + {StatusLine, Headers, Body} -> + tsp("expected response with" + "~n StatusLine: ~p" + "~n Headers: ~p" + "~n Body: ~p", [StatusLine, Headers, Body]), + tsf({unexpected_result, + [{status_line, StatusLine}, + {headers, Headers}, + {body, Body}]}); + _ -> + tsf({unexpected_result, Result}) + end; + Error -> + tsf({request_failed, Error}) + end, + + DummyServerPid ! stop, + ok = http:set_options([{ipv6, enabled}]), + ok. + + + %%-------------------------------------------------------------------- %% Internal functions %%-------------------------------------------------------------------- @@ -2171,7 +2412,7 @@ receive_streamed_body(RequestId, Body) -> receive_streamed_body(RequestId, Body, Pid) -> http:stream_next(Pid), - test_server:format("Requested next stream ~n", []), + test_server:format("~p:receive_streamed_body -> requested next stream ~n", [?MODULE]), receive {http, {RequestId, stream, BinBodyPart}} -> receive_streamed_body(RequestId, @@ -2186,7 +2427,11 @@ receive_streamed_body(RequestId, Body, Pid) -> dummy_server(Caller, IpV) -> - spawn(httpc_SUITE, dummy_server_init, [Caller, IpV]). + Pid = spawn(httpc_SUITE, dummy_server_init, [Caller, IpV]), + receive + {port, Port} -> + {Pid, Port} + end. dummy_server_init(Caller, IpV) -> {ok, ListenSocket} = @@ -2201,7 +2446,7 @@ dummy_server_init(Caller, IpV) -> {active, false}]) end, {ok, Port} = inet:port(ListenSocket), - test_server:format("Port: ~p~n", [Port]), + tsp("dummy_server_init -> Port: ~p", [Port]), Caller ! {port, Port}, dummy_server_loop({httpd_request, parse, [?HTTP_MAX_HEADER_SIZE]}, [], ListenSocket). @@ -2209,8 +2454,7 @@ dummy_server_init(Caller, IpV) -> dummy_server_loop(MFA, Handlers, ListenSocket) -> receive stop -> - lists:foreach(fun(Handler) -> Handler ! stop end, - Handlers) + lists:foreach(fun(Handler) -> Handler ! stop end, Handlers) after 0 -> {ok, Socket} = gen_tcp:accept(ListenSocket), HandlerPid = dummy_request_handler(MFA, Socket), @@ -2231,9 +2475,13 @@ dummy_request_handler_init(MFA, Socket) -> dummy_request_handler_loop(MFA, Socket). dummy_request_handler_loop({Module, Function, Args}, Socket) -> + tsp("dummy_request_handler_loop -> entry with" + "~n Module: ~p" + "~n Function: ~p" + "~n Args: ~p", [Module, Function, Args]), receive {tcp, _, Data} -> - test_server:format("dummy_request_handler_loop -> Data ~p~n", [Data]), + tsp("dummy_request_handler_loop -> Data ~p", [Data]), case handle_request(Module, Function, [Data | Args], Socket) of stop -> gen_tcp:close(Socket); @@ -2245,48 +2493,59 @@ dummy_request_handler_loop({Module, Function, Args}, Socket) -> end. handle_request(Module, Function, Args, Socket) -> + tsp("handle_request -> entry with" + "~n Module: ~p" + "~n Function: ~p" + "~n Args: ~p", [Module, Function, Args]), case Module:Function(Args) of {ok, Result} -> - case handle_http_msg(Result, Socket) of + tsp("handle_request -> ok" + "~n Result: ~p", [Result]), + case (catch handle_http_msg(Result, Socket)) of stop -> stop; <<>> -> - {httpd_request, parse, [?HTTP_MAX_HEADER_SIZE]}; + tsp("handle_request -> empty data"), + {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) end; NewMFA -> + tsp("handle_request -> " + "~n NewMFA: ~p", [NewMFA]), NewMFA end. handle_http_msg({_, RelUri, _, {_, Headers}, Body}, Socket) -> - - NextRequest = case RelUri of - "/dummy_headers.html" -> - <<>>; - "/no_headers.html" -> - stop; - "/just_close.html" -> - stop; - _ -> - ContentLength = content_length(Headers), - case size(Body) - ContentLength of - 0 -> - <<>>; - _ -> - <<_BodyThisReq:ContentLength/binary, - Next/binary>> = Body, - Next - end - end, + tsp("handle_http_msg -> entry with: " + "~n RelUri: ~p" + "~n Headers: ~p" + "~n Body: ~p", [RelUri, Headers, Body]), + NextRequest = + case RelUri of + "/dummy_headers.html" -> + <<>>; + "/no_headers.html" -> + stop; + "/just_close.html" -> + stop; + _ -> + ContentLength = content_length(Headers), + case size(Body) - ContentLength of + 0 -> + <<>>; + _ -> + <<_BodyThisReq:ContentLength/binary, + Next/binary>> = Body, + Next + end + end, - test_server:format("NextRequest: ~p~n", [NextRequest]), - + tsp("handle_http_msg -> NextRequest: ~p", [NextRequest]), case (catch ets:lookup(cookie, cookies)) of [{cookies, true}]-> - test_server:format("Headers ~p~n", [Headers]), + tsp("handle_http_msg -> check cookies ~p", []), check_cookie(Headers); _ -> ok @@ -2304,6 +2563,26 @@ handle_http_msg({_, RelUri, _, {_, Headers}, Body}, Socket) -> "HTTP/1.0 204 No Content\r\n\r\n"; "/no_headers.html" -> "HTTP/1.0 200 OK\r\n\r\nTEST"; + "/ensure_host_header_with_port.html" -> + %% tsp("handle_http_msg -> validate host with port"), + case ensure_host_header_with_port(Headers) of + true -> + B = + "" ++ + "host with port" ++ + "", + Len = integer_to_list(length(B)), + "HTTP/1.1 200 ok\r\n" ++ + "Content-Length:" ++ Len ++ "\r\n\r\n" ++ B; + false -> + B = + "" ++ + "Internal Server Error - host without port" ++ + "", + Len = integer_to_list(length(B)), + "HTTP/1.1 500 Internal Server Error\r\n" ++ + "Content-Length:" ++ Len ++ "\r\n\r\n" ++ B + end; "/300.html" -> NewUri = ?URL_START ++ integer_to_list(?IP_PORT) ++ "/dummy.html", @@ -2337,7 +2616,7 @@ handle_http_msg({_, RelUri, _, {_, Headers}, Body}, Socket) -> "/500.html" -> "HTTP/1.1 500 Internal Server Error\r\n" ++ "Content-Length:47\r\n\r\n" ++ - "Internal Server Error"; + "Internal Server Error"; "/503.html" -> case ets:lookup(unavailable, 503) of [{503, unavailable}] -> @@ -2452,16 +2731,35 @@ handle_http_msg({_, RelUri, _, {_, Headers}, Body}, Socket) -> DefaultResponse end, - test_server:format("Msg: ~p~n", [Msg]), + tsp("handle_http_msg -> Msg: ~p", [Msg]), case Msg of + ok -> + %% Previously, this resulted in an {error, einval}. Now what? + ok; close -> %% Nothing to send, just close gen_tcp:close(Socket); - _ -> + _ when is_list(Msg) orelse is_binary(Msg) -> gen_tcp:send(Socket, Msg) end, + tsp("handle_http_msg -> done"), NextRequest. +ensure_host_header_with_port([]) -> + false; +ensure_host_header_with_port(["host: " ++ Host| _]) -> + case string:tokens(Host, [$:]) of + [ActualHost, Port] -> + tsp("ensure_host_header_with_port -> " + "~n ActualHost: ~p" + "~n Port: ~p", [ActualHost, Port]), + true; + _ -> + false + end; +ensure_host_header_with_port([_|T]) -> + ensure_host_header_with_port(T). + auth_header([]) -> auth_header_not_found; auth_header(["authorization:" ++ Value | _]) -> @@ -2507,9 +2805,10 @@ provocate_not_modified_bug(Url) -> []) of {ok, {{_, 304, _}, _, _}} -> %% The expected reply page_unchanged; - {ok, {{_, 200, _}, _, _}} -> %% If the page has changed since the - %% last request we retry to - %% trigger the bug + {ok, {{_, 200, _}, _, _}} -> + %% If the page has changed since the + %% last request we retry to + %% trigger the bug provocate_not_modified_bug(Url); {error, timeout} -> %% Not what we expected. Tcpdump can be used to @@ -2528,5 +2827,20 @@ pick_header(Headers, Name) -> end. -%% p(F, A) -> -%% io:format("~p ~w:" ++ F ++ "~n", [self(), ?MODULE | A]). +not_implemented_yet() -> + exit(not_implemented_yet). + + +p(F) -> + p(F, []). + +p(F, A) -> + io:format("~p ~w:" ++ F ++ "~n", [self(), ?MODULE | A]). + +tsp(F) -> + tsp(F, []). +tsp(F, A) -> + test_server:format("~p ~p:" ++ F ++ "~n", [self(), ?MODULE | A]). + +tsf(Reason) -> + test_server:fail(Reason). diff --git a/lib/inets/test/httpc_cookie_SUITE.erl b/lib/inets/test/httpc_cookie_SUITE.erl index 7d91631934..ad5df656c6 100644 --- a/lib/inets/test/httpc_cookie_SUITE.erl +++ b/lib/inets/test/httpc_cookie_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -31,7 +31,7 @@ domain_cookie/1, secure_cookie/1, update_cookie/1, update_cookie_session/1, cookie_attributes/1]). --define(URL, "http://myhost.cookie.test.org"). +-define(URL, "http://myhost.cookie.test.org"). -define(URL_DOMAIN, "http://myhost2.cookie.test.org"). -define(URL_SECURE, "https://myhost.cookie.test.org"). @@ -50,15 +50,21 @@ %% variable, but should NOT alter/remove any existing entries. %% Description: Initiation before each test case %%-------------------------------------------------------------------- -init_per_testcase(session_cookies_only, Config) -> +init_per_testcase(session_cookies_only = Case, Config0) -> + tsp("init_per_testcase(~p) -> entry with" + "~n Config0: ~p", [Case, Config0]), + Config = init_workdir(Case, Config0), application:start(inets), http:set_options([{cookies, verify}]), watch_dog(Config); -init_per_testcase(_, Config) -> - PrivDir = ?config(priv_dir, Config), +init_per_testcase(Case, Config0) -> + tsp("init_per_testcase(~p) -> entry with" + "~n Config0: ~p", [Case, Config0]), + Config = init_workdir(Case, Config0), + CaseDir = ?config(case_top_dir, Config), application:load(inets), - application:set_env(inets, services, [{httpc,{default, PrivDir}}]), + application:set_env(inets, services, [{httpc, {default, CaseDir}}]), application:start(inets), http:set_options([{cookies, verify}]), watch_dog(Config). @@ -68,6 +74,24 @@ watch_dog(Config) -> NewConfig = lists:keydelete(watchdog, 1, Config), [{watchdog, Dog} | NewConfig]. +init_workdir(Case, Config) -> + PrivDir = ?config(priv_dir, Config), + SuiteTopDir = filename:join(PrivDir, ?MODULE), + case file:make_dir(SuiteTopDir) of + ok -> + ok; + {error, eexist} -> + ok; + Error -> + tsf({failed_creating_subsuite_top_dir, Error}) + end, + + CaseTopDir = filename:join(SuiteTopDir, Case), + ?line ok = file:make_dir(CaseTopDir), + [{suite_top_dir, SuiteTopDir}, + {case_top_dir, CaseTopDir} | Config]. + + %%-------------------------------------------------------------------- %% Function: end_per_testcase(TestCase, Config) -> _ %% Case - atom() @@ -76,10 +100,10 @@ watch_dog(Config) -> %% A list of key/value pairs, holding the test case configuration. %% Description: Cleanup after each test case %%-------------------------------------------------------------------- -end_per_testcase(_TestCase, Config) -> +end_per_testcase(Case, Config) -> + tsp("end_per_testcase(~p) -> entry with" + "~n Config: ~p", [Case, Config]), application:stop(inets), - File = filename:join(?config(priv_dir, Config), "http_default_cookie_db"), - file:delete(File), Dog = ?config(watchdog, Config), test_server:timetrap_cancel(Dog), ok. @@ -96,9 +120,18 @@ all(doc) -> ["Describe the main purpose of this suite"]; all(suite) -> - [session_cookies_only, netscape_cookies, cookie_cancel, - cookie_expires, persistent_cookie, domain_cookie, secure_cookie, - update_cookie, update_cookie_session, cookie_attributes]. + [ + session_cookies_only, + netscape_cookies, + cookie_cancel, + cookie_expires, + persistent_cookie, + domain_cookie, + secure_cookie, + update_cookie, + update_cookie_session, + cookie_attributes + ]. %% Test cases starts here. %%-------------------------------------------------------------------- @@ -108,6 +141,8 @@ session_cookies_only(doc) -> session_cookies_only(suite) -> []; session_cookies_only(Config) when is_list(Config) -> + tsp("session_cookies_only -> Cookies 1: ~p", [httpc:which_cookies()]), + SetCookieHeaders = [{"set-cookie", "test_cookie=true; path=/;" ";max-age=60000"}], http:verify_cookies(SetCookieHeaders, ?URL), @@ -115,8 +150,9 @@ session_cookies_only(Config) when is_list(Config) -> = http:cookie_header(?URL), application:stop(inets), application:start(inets), - {"cookie",""} - = http:cookie_header(?URL), + {"cookie",""} = http:cookie_header(?URL), + + tsp("session_cookies_only -> Cookies 2: ~p", [httpc:which_cookies()]), ok. netscape_cookies(doc) -> @@ -124,12 +160,16 @@ netscape_cookies(doc) -> netscape_cookies(suite) -> []; netscape_cookies(Config) when is_list(Config) -> + tsp("netscape_cookies -> Cookies 1: ~p", [httpc:which_cookies()]), + Expires = future_netscape_date(), SetCookieHeaders = [{"set-cookie", "test_cookie=true; path=/; " "expires=" ++ Expires}], http:verify_cookies(SetCookieHeaders, ?URL), - {"cookie","$Version=0; test_cookie=true; $Path=/"} - = http:cookie_header(?URL), + {"cookie","$Version=0; test_cookie=true; $Path=/"} = + http:cookie_header(?URL), + + tsp("netscape_cookies -> Cookies 2: ~p", [httpc:which_cookies()]), ok. cookie_cancel(doc) -> @@ -138,6 +178,8 @@ cookie_cancel(doc) -> cookie_cancel(suite) -> []; cookie_cancel(Config) when is_list(Config) -> + tsp("cookie_cancel -> Cookies 1: ~p", [httpc:which_cookies()]), + SetCookieHeaders = [{"set-cookie", "test_cookie=true; path=/;" "max-age=60000"}], http:verify_cookies(SetCookieHeaders, ?URL), @@ -147,6 +189,8 @@ cookie_cancel(Config) when is_list(Config) -> "max-age=0"}], http:verify_cookies(NewSetCookieHeaders, ?URL), {"cookie", ""} = http:cookie_header(?URL), + + tsp("cookie_cancel -> Cookies 2: ~p", [httpc:which_cookies()]), ok. cookie_expires(doc) -> @@ -154,6 +198,8 @@ cookie_expires(doc) -> cookie_expires(suite) -> []; cookie_expires(Config) when is_list(Config) -> + tsp("cookie_expires -> Cookies 1: ~p", [httpc:which_cookies()]), + SetCookieHeaders = [{"set-cookie", "test_cookie=true; path=/;" "max-age=5"}], http:verify_cookies(SetCookieHeaders, ?URL), @@ -161,56 +207,95 @@ cookie_expires(Config) when is_list(Config) -> = http:cookie_header(?URL), test_server:sleep(10000), {"cookie", ""} = http:cookie_header(?URL), + + tsp("cookie_expires -> Cookies 2: ~p", [httpc:which_cookies()]), ok. -persistent_cookie(doc)-> +persistent_cookie(doc) -> ["Test domian cookie attribute"]; persistent_cookie(suite) -> []; persistent_cookie(Config) when is_list(Config)-> + tsp("persistent_cookie -> Cookies 1: ~p", [httpc:which_cookies()]), + SetCookieHeaders = [{"set-cookie", "test_cookie=true; path=/;" "max-age=60000"}], http:verify_cookies(SetCookieHeaders, ?URL), - {"cookie","$Version=0; test_cookie=true; $Path=/"} - = http:cookie_header(?URL), - PrivDir = ?config(priv_dir, Config), + {"cookie","$Version=0; test_cookie=true; $Path=/"} = + http:cookie_header(?URL), + CaseDir = ?config(case_top_dir, Config), application:stop(inets), application:load(inets), - application:set_env(inets, services, [{httpc,{default, PrivDir}}]), + application:set_env(inets, services, [{httpc, {default, CaseDir}}]), application:start(inets), - http:set_options([{cookies, enabled}]), - {"cookie","$Version=0; test_cookie=true; $Path=/"} - = http:cookie_header(?URL), + http:set_options([{cookies, enabled}]), + {"cookie","$Version=0; test_cookie=true; $Path=/"} = http:cookie_header(?URL), + + tsp("persistent_cookie -> Cookies 2: ~p", [httpc:which_cookies()]), ok. -domain_cookie(doc)-> + +domain_cookie(doc) -> ["Test the domian cookie attribute"]; domain_cookie(suite) -> []; -domain_cookie(Config) when is_list(Config)-> +domain_cookie(Config) when is_list(Config) -> + tsp("domain_cookie -> Cookies 1: ~p", [httpc:which_cookies()]), + SetCookieHeaders = [{"set-cookie", "test_cookie=true; path=/;" "domain=.cookie.test.org"}], http:verify_cookies(SetCookieHeaders, ?URL), {"cookie","$Version=0; test_cookie=true; $Path=/; " - "$Domain=.cookie.test.org"} - = http:cookie_header(?URL_DOMAIN), + "$Domain=.cookie.test.org"} = + http:cookie_header(?URL_DOMAIN), + + tsp("domain_cookie -> Cookies 2: ~p", [httpc:which_cookies()]), ok. -secure_cookie(doc)-> + +secure_cookie(doc) -> ["Test the secure cookie attribute"]; secure_cookie(suite) -> []; -secure_cookie(Config) when is_list(Config)-> +secure_cookie(Config) when is_list(Config) -> + tsp("secure_cookie -> entry with" + "~n Config: ~p", [Config]), + + inets:enable_trace(max, io, httpc), + + %% httpc:reset_cookies(), + + tsp("secure_cookie -> Cookies 1: ~p", [httpc:which_cookies()]), + SetCookieHeaders = [{"set-cookie", "test_cookie=true; path=/; secure"}], - http:verify_cookies(SetCookieHeaders, ?URL), - {"cookie","$Version=0; test_cookie=true; $Path=/"} - = http:cookie_header(?URL_SECURE), - {"cookie",""} - = http:cookie_header(?URL), + tsp("secure_cookie -> verify cookies (1)"), + ok = http:verify_cookies(SetCookieHeaders, ?URL), + + tsp("secure_cookie -> Cookies 2: ~p", [httpc:which_cookies()]), + + tsp("secure_cookie -> check cookie (secure)"), + check_cookie("$Version=0; test_cookie=true; $Path=/", ?URL_SECURE), + + tsp("secure_cookie -> check cookie (plain)"), + check_cookie("", ?URL), + + tsp("secure_cookie -> verify cookies (2)"), SetCookieHeaders1 = [{"set-cookie", "test1_cookie=true; path=/; secure"}], - http:verify_cookies(SetCookieHeaders1, ?URL), - {"cookie","$Version=0; test_cookie=true; $Path=/; " - "test1_cookie=true; $Path=/"} = http:cookie_header(?URL_SECURE), + ok = http:verify_cookies(SetCookieHeaders1, ?URL), + + tsp("secure_cookie -> Cookies 3: ~p", [httpc:which_cookies()]), + + tsp("secure_cookie -> cookie header (3)"), + check_cookie("$Version=0; test_cookie=true; $Path=/; " + "test1_cookie=true; $Path=/", + ?URL_SECURE), +%% {"cookie","$Version=0; test_cookie=true; $Path=/; " +%% "test1_cookie=true; $Path=/"} = http:cookie_header(?URL_SECURE), + + tsp("secure_cookie -> Cookies 4: ~p", [httpc:which_cookies()]), + + inets:disable_trace(), + tsp("secure_cookie -> done"), ok. update_cookie(doc)-> @@ -257,13 +342,31 @@ cookie_attributes(Config) when is_list(Config) -> "foo=bar;" %% Nonsense should be ignored "max-age=60000"}], http:verify_cookies(SetCookieHeaders, ?URL), - {"cookie","$Version=1; test_cookie=true"} - = http:cookie_header(?URL), + {"cookie","$Version=1; test_cookie=true"} = http:cookie_header(?URL), ok. + %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- + +check_cookie(Expect, URL) -> + case http:cookie_header(URL) of + {"cookie", Expect} -> + ok; + {"cookie", Unexpected} -> + case lists:prefix(Expect, Unexpected) of + true -> + Extra = Unexpected -- Expect, + tsf({extra_cookie_info, Extra}); + false -> + tsf({unknown_cookie, Expect, Unexpected}) + end; + Bad -> + tsf({bad_cookies, Bad}) + end. + + future_netscape_date() -> [Day, DD, Mon, YYYY] = netscape_date(date()), lists:flatten(io_lib:format("~s, ~s ~s ~s 12:30:00 GMT", @@ -336,3 +439,13 @@ month_str(9) ->"Sep"; month_str(10) ->"Oct"; month_str(11) ->"Nov"; month_str(12) ->"Dec". + + +tsp(F) -> + tsp(F, []). +tsp(F, A) -> + test_server:format("~p ~p:" ++ F ++ "~n", [self(), ?MODULE | A]). + +tsf(Reason) -> + test_server:fail(Reason). + diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl index b7e97aa3ec..7403d4a643 100644 --- a/lib/inets/test/httpd_SUITE.erl +++ b/lib/inets/test/httpd_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -444,35 +444,35 @@ ip(doc) -> ["HTTP tests using TCP/IP"]; ip(suite) -> [ -%% ip_mod_alias, -%% ip_mod_actions, -%% ip_mod_security, -%% ip_mod_auth, -%% ip_mod_auth_api, -%% ip_mod_auth_mnesia_api, -%% ip_mod_htaccess, -%% ip_mod_cgi, -%% ip_mod_esi, -%% ip_mod_get, -%% ip_mod_head, -%% ip_mod_all, -%% ip_load_light, -%% ip_load_medium, -%% ip_load_heavy, -%% ip_dos_hostname, -%% ip_time_test, -%% ip_block_disturbing_idle, -%% ip_block_non_disturbing_idle, -%% ip_block_503, -%% ip_block_disturbing_active, -%% ip_block_non_disturbing_active, -%% ip_block_disturbing_active_timeout_not_released, -%% ip_block_disturbing_active_timeout_released, -%% ip_block_non_disturbing_active_timeout_not_released, -%% ip_block_non_disturbing_active_timeout_released, -%% ip_block_disturbing_blocker_dies, -%% ip_block_non_disturbing_blocker_dies, -%% ip_restart_no_block, + ip_mod_alias, + ip_mod_actions, + ip_mod_security, + ip_mod_auth, + ip_mod_auth_api, + ip_mod_auth_mnesia_api, + ip_mod_htaccess, + ip_mod_cgi, + ip_mod_esi, + ip_mod_get, + ip_mod_head, + ip_mod_all, + ip_load_light, + ip_load_medium, + ip_load_heavy, + ip_dos_hostname, + ip_time_test, + ip_block_disturbing_idle, + ip_block_non_disturbing_idle, + ip_block_503, + ip_block_disturbing_active, + ip_block_non_disturbing_active, + ip_block_disturbing_active_timeout_not_released, + ip_block_disturbing_active_timeout_released, + ip_block_non_disturbing_active_timeout_not_released, + ip_block_non_disturbing_active_timeout_released, + ip_block_disturbing_blocker_dies, + ip_block_non_disturbing_blocker_dies, + ip_restart_no_block, ip_restart_disturbing_block, ip_restart_non_disturbing_block ]. @@ -482,37 +482,37 @@ ssl(doc) -> ["HTTP test using SSL"]; ssl(suite) -> [ -%% ssl_mod_alias, -%% ssl_mod_actions, -%% ssl_mod_security, -%% ssl_mod_auth, -%% ssl_mod_auth_api, -%% ssl_mod_auth_mnesia_api, -%% ssl_mod_htaccess, -%% ssl_mod_cgi, -%% ssl_mod_esi, -%% ssl_mod_get, -%% ssl_mod_head, -%% ssl_mod_all, -%% ssl_load_light, -%% ssl_load_medium, -%% ssl_load_heavy, -%% ssl_dos_hostname, -%% ssl_time_test, -%% ssl_restart_no_block, + ssl_mod_alias, + ssl_mod_actions, + ssl_mod_security, + ssl_mod_auth, + ssl_mod_auth_api, + ssl_mod_auth_mnesia_api, + ssl_mod_htaccess, + ssl_mod_cgi, + ssl_mod_esi, + ssl_mod_get, + ssl_mod_head, + ssl_mod_all, + ssl_load_light, + ssl_load_medium, + ssl_load_heavy, + ssl_dos_hostname, + ssl_time_test, + ssl_restart_no_block, ssl_restart_disturbing_block, - ssl_restart_non_disturbing_block%% , -%% ssl_block_disturbing_idle, -%% ssl_block_non_disturbing_idle, -%% ssl_block_503, -%% ssl_block_disturbing_active, -%% ssl_block_non_disturbing_active, -%% ssl_block_disturbing_active_timeout_not_released, -%% ssl_block_disturbing_active_timeout_released, -%% ssl_block_non_disturbing_active_timeout_not_released, -%% ssl_block_non_disturbing_active_timeout_released, -%% ssl_block_disturbing_blocker_dies, -%% ssl_block_non_disturbing_blocker_dies + ssl_restart_non_disturbing_block, + ssl_block_disturbing_idle, + ssl_block_non_disturbing_idle, + ssl_block_503, + ssl_block_disturbing_active, + ssl_block_non_disturbing_active, + ssl_block_disturbing_active_timeout_not_released, + ssl_block_disturbing_active_timeout_released, + ssl_block_non_disturbing_active_timeout_not_released, + ssl_block_non_disturbing_active_timeout_released, + ssl_block_disturbing_blocker_dies, + ssl_block_non_disturbing_blocker_dies ]. %%------------------------------------------------------------------------- diff --git a/lib/inets/test/inets_SUITE.erl b/lib/inets/test/inets_SUITE.erl index c249bdf81b..56983caace 100644 --- a/lib/inets/test/inets_SUITE.erl +++ b/lib/inets/test/inets_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -21,12 +21,12 @@ -include("test_server.hrl"). -include("test_server_line.hrl"). +-include("inets_test_lib.hrl"). %% Note: This directive should only be used in test suites. -compile(export_all). -define(NUM_DEFAULT_SERVICES, 1). --define(FTP_HOST,"tuor"). all(doc) -> ["Test suites for the inets application."]; @@ -35,14 +35,20 @@ all(suite) -> [ app_test, appup_test, + services_test, + httpd_reload + ]. + +services_test(suite) -> + [ start_inets, start_httpc, start_httpd, start_ftpc, - start_tftpd, - httpd_reload + start_tftpd ]. + %%-------------------------------------------------------------------- %% Function: init_per_suite(Config) -> Config %% Config - [tuple()] @@ -139,40 +145,88 @@ start_httpc(suite) -> []; start_httpc(Config) when is_list(Config) -> process_flag(trap_exit, true), + tsp("start_httpc -> entry with" + "~n Config: ~p", [Config]), + PrivDir = ?config(priv_dir, Config), + + tsp("start_httpc -> start (empty) inets"), ok = inets:start(), + + tsp("start_httpc -> start httpc (as inets service) with profile foo"), {ok, Pid0} = inets:start(httpc, [{profile, foo}]), + + tsp("start_httpc -> check running services"), Pids0 = [ServicePid || {_, ServicePid} <- inets:services()], true = lists:member(Pid0, Pids0), [_|_] = inets:services_info(), + + tsp("start_httpc -> stop httpc"), inets:stop(httpc, Pid0), + + tsp("start_httpc -> sleep some"), test_server:sleep(100), + + tsp("start_httpc -> check running services"), Pids1 = [ServicePid || {_, ServicePid} <- inets:services()], false = lists:member(Pid0, Pids1), + + tsp("start_httpc -> start httpc (stand-alone) with profile bar"), {ok, Pid1} = inets:start(httpc, [{profile, bar}], stand_alone), + + tsp("start_httpc -> check running services"), Pids2 = [ServicePid || {_, ServicePid} <- inets:services()], false = lists:member(Pid1, Pids2), + + tsp("start_httpc -> stop httpc"), ok = inets:stop(stand_alone, Pid1), receive {'EXIT', Pid1, shutdown} -> ok after 100 -> - test_server:fail(stand_alone_not_shutdown) + tsf(stand_alone_not_shutdown) end, + + tsp("start_httpc -> stop inets"), ok = inets:stop(), + + tsp("start_httpc -> unload inets"), application:load(inets), + + tsp("start_httpc -> set inets environment (httpc profile foo)"), application:set_env(inets, services, [{httpc,[{profile, foo}, {data_dir, PrivDir}]}]), + + tsp("start_httpc -> start inets"), ok = inets:start(), + + tsp("start_httpc -> check running services"), (?NUM_DEFAULT_SERVICES + 1) = length(inets:services()), + + tsp("start_httpc -> unset inets env"), application:unset_env(inets, services), + + tsp("start_httpc -> stop inets"), ok = inets:stop(), + + tsp("start_httpc -> start (empty) inets"), ok = inets:start(), + + tsp("start_httpc -> start inets httpc service with profile foo"), {ok, Pid3} = inets:start(httpc, [{profile, foo}]), + + tsp("start_httpc -> stop inets service httpc with profile foo"), ok = inets:stop(httpc, foo), + + tsp("start_httpc -> check running services"), Pids3 = [ServicePid || {_, ServicePid} <- inets:services()], false = lists:member(Pid3, Pids3), - ok = inets:stop(). + + tsp("start_httpc -> stop inets"), + ok = inets:stop(), + + tsp("start_httpc -> done"), + ok. %%------------------------------------------------------------------------- @@ -191,11 +245,13 @@ start_httpd(Config) when is_list(Config) -> i("start_httpd -> start inets"), ok = inets:start(), + i("start_httpd -> start httpd service"), {ok, Pid0} = inets:start(httpd, [{port, 0}, {ipfamily, inet} | HttpdConf]), Pids0 = [ServicePid || {_, ServicePid} <- inets:services()], true = lists:member(Pid0, Pids0), [_|_] = inets:services_info(), + i("start_httpd -> stop httpd service"), inets:stop(httpd, Pid0), test_server:sleep(500), @@ -310,30 +366,49 @@ start_ftpc(suite) -> []; start_ftpc(Config) when is_list(Config) -> process_flag(trap_exit, true), + inets:disable_trace(), + inets:enable_trace(max, io, ftpc), ok = inets:start(), - case inets:start(ftpc, [{host, ?FTP_HOST}]) of - {ok, Pid0} -> - Pids0 = [ServicePid || {_, ServicePid} <- inets:services()], - true = lists:member(Pid0, Pids0), - [_|_] = inets:services_info(), - inets:stop(ftpc, Pid0), - test_server:sleep(100), - Pids1 = [ServicePid || {_, ServicePid} <- inets:services()], - false = lists:member(Pid0, Pids1), - {ok, Pid1} = inets:start(ftpc, [{host, ?FTP_HOST}], stand_alone), - Pids2 = [ServicePid || {_, ServicePid} <- inets:services()], - false = lists:member(Pid1, Pids2), - ok = inets:stop(stand_alone, Pid1), - receive - {'EXIT', Pid1, shutdown} -> - ok - after 100 -> - test_server:fail(stand_alone_not_shutdown) - end, - ok = inets:stop(); - _ -> - {skip, "Unable to reach test FTP server " ++ ?FTP_HOST} + try + begin + {_Tag, FtpdHost} = ftp_suite_lib:dirty_select_ftpd_host(Config), + case inets:start(ftpc, [{host, FtpdHost}]) of + {ok, Pid0} -> + Pids0 = [ServicePid || {_, ServicePid} <- + inets:services()], + true = lists:member(Pid0, Pids0), + [_|_] = inets:services_info(), + inets:stop(ftpc, Pid0), + test_server:sleep(100), + Pids1 = [ServicePid || {_, ServicePid} <- + inets:services()], + false = lists:member(Pid0, Pids1), + {ok, Pid1} = + inets:start(ftpc, [{host, FtpdHost}], stand_alone), + Pids2 = [ServicePid || {_, ServicePid} <- + inets:services()], + false = lists:member(Pid1, Pids2), + ok = inets:stop(stand_alone, Pid1), + receive + {'EXIT', Pid1, shutdown} -> + ok + after 100 -> + tsf(stand_alone_not_shutdown) + end, + ok = inets:stop(), + inets:disable_trace(), + ok; + _ -> + inets:disable_trace(), + {skip, "Unable to reach selected FTP server " ++ FtpdHost} + end + end + catch + throw:{error, not_found} -> + inets:disable_trace(), + {skip, "No available FTP servers"} end. + %%------------------------------------------------------------------------- @@ -478,15 +553,24 @@ httpd_reload(Config) when is_list(Config) -> ok. +tsf(Reason) -> + test_server:fail(Reason). + +tsp(F) -> + tsp(F, []). +tsp(F, A) -> + Timestamp = formated_timestamp(), + test_server:format("** ~s ** ~p ~p:" ++ F ++ "~n", [Timestamp, self(), ?MODULE | A]). + i(F) -> i(F, []). i(F, A) -> Timestamp = formated_timestamp(), - io:format("*** ~s ~w:~w:" ++ F ++ "~n", [Timestamp, ?MODULE, ?LINE | A]). + io:format("*** ~s ~w:" ++ F ++ "~n", [Timestamp, ?MODULE | A]). formated_timestamp() -> - format_timestamp( now() ). + format_timestamp( os:timestamp() ). format_timestamp({_N1, _N2, N3} = Now) -> {Date, Time} = calendar:now_to_datetime(Now), @@ -496,3 +580,4 @@ format_timestamp({_N1, _N2, N3} = Now) -> 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). + diff --git a/lib/inets/test/inets_sup_SUITE.erl b/lib/inets/test/inets_sup_SUITE.erl index 755ab594ed..ba41e0960c 100644 --- a/lib/inets/test/inets_sup_SUITE.erl +++ b/lib/inets/test/inets_sup_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @@ -26,8 +26,6 @@ %% Note: This directive should only be used in test suites. -compile(export_all). --define(FTP_HOST, "tuor"). - all(doc) -> ["Test that the inets supervisorstructur is the expected one."]; all(suite) -> @@ -223,20 +221,34 @@ ftpc_worker(doc) -> ftpc_worker(suite) -> []; ftpc_worker(Config) when is_list(Config) -> + inets:disable_trace(), + inets:enable_trace(max, io, ftpc), [] = supervisor:which_children(ftp_sup), - case inets:start(ftpc, [{host, ?FTP_HOST}]) of - {ok, Pid} -> - case supervisor:which_children(ftp_sup) of - [{_,_, worker, [ftp]}] -> - inets:stop(ftpc, Pid), - test_server:sleep(5000), - [] = supervisor:which_children(ftp_sup), - ok; - Children -> - exit({unexpected_children, Children}) - end; - _ -> - {skip, "Unable to reach test FTP server"} + try + begin + {_Tag, FtpdHost} = ftp_suite_lib:dirty_select_ftpd_host(Config), + case inets:start(ftpc, [{host, FtpdHost}]) of + {ok, Pid} -> + case supervisor:which_children(ftp_sup) of + [{_,_, worker, [ftp]}] -> + inets:stop(ftpc, Pid), + test_server:sleep(5000), + [] = supervisor:which_children(ftp_sup), + inets:disable_trace(), + ok; + Children -> + inets:disable_trace(), + exit({unexpected_children, Children}) + end; + _ -> + inets:disable_trace(), + {skip, "Unable to reach test FTP server"} + end + end + catch + throw:{error, not_found} -> + inets:disable_trace(), + {skip, "No available FTP servers"} end. @@ -252,7 +264,7 @@ tftpd_worker(Config) when is_list(Config) -> {ok, Pid0} = inets:start(tftpd, [{host, "localhost"}, {port, inet_port()}]), {ok, _Pid1} = inets:start(tftpd, [{host, "localhost"}, - {port, inet_port()}], stand_alone), + {port, inet_port()}], stand_alone), [{_,Pid0, worker, _}] = supervisor:which_children(tftp_sup), inets:stop(tftpd, Pid0), @@ -356,25 +368,33 @@ httpc_subtree(doc) -> httpc_subtree(suite) -> []; httpc_subtree(Config) when is_list(Config) -> - io:format("httpd_subtree -> entry with" - "~n Config: ~p" - "~n", [Config]), + tsp("httpc_subtree -> entry with" + "~n Config: ~p", [Config]), + tsp("httpc_subtree -> start inets service httpc with profile foo"), {ok, Foo} = inets:start(httpc, [{profile, foo}]), - io:format("httpc_subtree -> foo started~n", []), + + tsp("httpc_subtree -> " + "start stand-alone inets service httpc with profile bar"), {ok, Bar} = inets:start(httpc, [{profile, bar}], stand_alone), - io:format("httpc_subtree -> bar started~n", []), - + + tsp("httpc_subtree -> retreive list of httpc instances"), HttpcChildren = supervisor:which_children(httpc_profile_sup), - io:format("httpc_subtree -> HttpcChildren: ~p~n", [HttpcChildren]), + tsp("httpc_subtree -> HttpcChildren: ~n~p", [HttpcChildren]), - {value, {httpc_manager, _, worker,[httpc_manager]}} = + tsp("httpc_subtree -> verify httpc stand-alone instances"), + {value, {httpc_manager, _, worker, [httpc_manager]}} = lists:keysearch(httpc_manager, 1, HttpcChildren), - {value,{{http,foo}, Pid, worker,[httpc_manager]}} = - lists:keysearch({http, foo}, 1, HttpcChildren), - false = lists:keysearch({http, bar}, 1, HttpcChildren), + + tsp("httpc_subtree -> verify httpc (named) instances"), + {value,{{httpc,foo}, Pid, worker, [httpc_manager]}} = + lists:keysearch({httpc, foo}, 1, HttpcChildren), + false = lists:keysearch({httpc, bar}, 1, HttpcChildren), + tsp("httpc_subtree -> stop inets"), inets:stop(httpc, Pid), + + tsp("httpc_subtree -> done"), ok. inet_port() -> @@ -384,3 +404,11 @@ inet_port() -> Port. +tsp(F) -> + tsp(F, []). +tsp(F, A) -> + test_server:format("~p ~p:" ++ F ++ "~n", [self(), ?MODULE | A]). + +tsf(Reason) -> + test_server:fail(Reason). + -- cgit v1.2.3