aboutsummaryrefslogtreecommitdiffstats
path: root/lib/inets/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/inets/src')
-rw-r--r--lib/inets/src/ftp/Makefile10
-rw-r--r--lib/inets/src/ftp/ftp.erl2
-rw-r--r--lib/inets/src/http_client/Makefile10
-rw-r--r--lib/inets/src/http_client/httpc.erl110
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl50
-rw-r--r--lib/inets/src/http_client/httpc_manager.erl255
-rw-r--r--lib/inets/src/http_client/httpc_response.erl18
-rw-r--r--lib/inets/src/http_lib/Makefile10
-rw-r--r--lib/inets/src/http_lib/http_uri.erl127
-rw-r--r--lib/inets/src/http_server/Makefile14
-rw-r--r--lib/inets/src/http_server/httpd_conf.erl110
-rw-r--r--lib/inets/src/http_server/httpd_response.erl27
-rw-r--r--lib/inets/src/http_server/httpd_script_env.erl59
-rw-r--r--lib/inets/src/http_server/httpd_sup.erl19
-rw-r--r--lib/inets/src/http_server/mod_get.erl18
-rw-r--r--lib/inets/src/inets_app/Makefile17
-rw-r--r--lib/inets/src/inets_app/inets.app.src5
-rw-r--r--lib/inets/src/inets_app/inets.appup.src92
-rw-r--r--lib/inets/src/inets_app/inets.erl269
-rw-r--r--lib/inets/src/inets_app/inets.mk8
-rw-r--r--lib/inets/src/inets_app/inets_app.erl4
-rw-r--r--lib/inets/src/inets_app/inets_internal.hrl6
-rw-r--r--lib/inets/src/inets_app/inets_service.erl17
-rw-r--r--lib/inets/src/inets_app/inets_sup.erl12
-rw-r--r--lib/inets/src/inets_app/inets_trace.erl357
-rw-r--r--lib/inets/src/tftp/Makefile23
-rw-r--r--lib/inets/src/tftp/tftp.erl18
27 files changed, 1140 insertions, 527 deletions
diff --git a/lib/inets/src/ftp/Makefile b/lib/inets/src/ftp/Makefile
index 19b93870df..426286f254 100644
--- a/lib/inets/src/ftp/Makefile
+++ b/lib/inets/src/ftp/Makefile
@@ -88,11 +88,11 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/ftp
- $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/ftp
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/ftp"
+ $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/src/ftp"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/inets/src/ftp/ftp.erl b/lib/inets/src/ftp/ftp.erl
index 560ee55271..fe25c23316 100644
--- a/lib/inets/src/ftp/ftp.erl
+++ b/lib/inets/src/ftp/ftp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2012. 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
diff --git a/lib/inets/src/http_client/Makefile b/lib/inets/src/http_client/Makefile
index d490e59929..850c790bd1 100644
--- a/lib/inets/src/http_client/Makefile
+++ b/lib/inets/src/http_client/Makefile
@@ -89,11 +89,11 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/http_client
- $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/http_client
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/http_client"
+ $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/src/http_client"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl
index ae87ceed93..b6e7708353 100644
--- a/lib/inets/src/http_client/httpc.erl
+++ b/lib/inets/src/http_client/httpc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. 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
@@ -31,12 +31,15 @@
-export([
request/1, request/2, request/4, request/5,
cancel_request/1, cancel_request/2,
- set_option/2, set_option/3,
+ set_option/2, set_option/3,
set_options/1, set_options/2,
+ get_option/1, get_option/2,
+ get_options/1, get_options/2,
store_cookies/2, store_cookies/3,
cookie_header/1, cookie_header/2, cookie_header/3,
which_cookies/0, which_cookies/1,
reset_cookies/0, reset_cookies/1,
+ which_sessions/0, which_sessions/1,
stream_next/1,
default_profile/0,
profile_name/1, profile_name/2,
@@ -156,7 +159,7 @@ request(Method,
{http_options, HTTPOptions},
{options, Options},
{profile, Profile}]),
- case http_uri:parse(Url, Options) of
+ case uri_parse(Url, Options) of
{error, Reason} ->
{error, Reason};
{ok, ParsedUrl} ->
@@ -177,7 +180,7 @@ request(Method,
{http_options, HTTPOptions},
{options, Options},
{profile, Profile}]),
- case http_uri:parse(Url, Options) of
+ case uri_parse(Url, Options) of
{error, Reason} ->
{error, Reason};
{ok, ParsedUrl} ->
@@ -230,7 +233,7 @@ cancel_request(RequestId, Profile)
set_options(Options) ->
set_options(Options, default_profile()).
set_options(Options, Profile) when is_atom(Profile) orelse is_pid(Profile) ->
- ?hcrt("set cookies", [{options, Options}, {profile, Profile}]),
+ ?hcrt("set options", [{options, Options}, {profile, Profile}]),
case validate_options(Options) of
{ok, Opts} ->
try
@@ -253,6 +256,59 @@ set_option(Key, Value, Profile) ->
%%--------------------------------------------------------------------------
+%% get_options(OptionItems) -> {ok, Values} | {error, Reason}
+%% get_options(OptionItems, Profile) -> {ok, Values} | {error, Reason}
+%% OptionItems - all | [option_item()]
+%% option_item() - proxy | pipeline_timeout | max_pipeline_length |
+%% keep_alive_timeout | max_keep_alive_length |
+%% max_sessions | verbose |
+%% cookies | ipfamily | ip | port | socket_opts
+%% Profile - atom()
+%% Values - [{option_item(), term()}]
+%% Reason - term()
+%% Description: Retrieves the current options.
+%%-------------------------------------------------------------------------
+
+get_options() ->
+ record_info(fields, options).
+
+get_options(Options) ->
+ get_options(Options, default_profile()).
+
+get_options(all = _Options, Profile) ->
+ get_options(get_options(), Profile);
+get_options(Options, Profile)
+ when (is_list(Options) andalso
+ (is_atom(Profile) orelse is_pid(Profile))) ->
+ ?hcrt("get options", [{options, Options}, {profile, Profile}]),
+ case Options -- get_options() of
+ [] ->
+ try
+ begin
+ {ok, httpc_manager:get_options(Options,
+ profile_name(Profile))}
+ end
+ catch
+ exit:{noproc, _} ->
+ {error, inets_not_started}
+ end;
+ InvalidGetOptions ->
+ {error, {invalid_options, InvalidGetOptions}}
+ end.
+
+get_option(Key) ->
+ get_option(Key, default_profile()).
+
+get_option(Key, Profile) ->
+ case get_options([Key], Profile) of
+ {ok, [{Key, Value}]} ->
+ {ok, Value};
+ Error ->
+ Error
+ end.
+
+
+%%--------------------------------------------------------------------------
%% store_cookies(SetCookieHeaders, Url [, Profile]) -> ok | {error, reason}
%%
%%
@@ -274,7 +330,7 @@ store_cookies(SetCookieHeaders, Url, Profile)
%% Since the Address part is not actually used
%% by the manager when storing cookies, we dont
%% care about ipv6-host-with-brackets.
- {ok, {_, _, Host, Port, Path, _}} = http_uri:parse(Url),
+ {ok, {_, _, Host, Port, Path, _}} = uri_parse(Url),
Address = {Host, Port},
ProfileName = profile_name(Profile),
Cookies = httpc_cookie:cookies(SetCookieHeaders, Path, Host),
@@ -319,8 +375,6 @@ cookie_header(Url, Opts, Profile)
{error, {not_started, Profile}}
end.
-
-
%%--------------------------------------------------------------------------
%% which_cookies() -> [cookie()]
@@ -344,10 +398,32 @@ which_cookies(Profile) ->
%%--------------------------------------------------------------------------
+%% which_sessions() -> {GoodSession, BadSessions, NonSessions}
+%% which_sessions(Profile) -> {GoodSession, BadSessions, NonSessions}
+%%
+%% Description: Debug function, dumping the sessions database, sorted
+%% into three groups (Good-, Bad- and Non-sessions).
+%%-------------------------------------------------------------------------
+which_sessions() ->
+ which_sessions(default_profile()).
+
+which_sessions(Profile) ->
+ ?hcrt("which sessions", [{profile, Profile}]),
+ try
+ begin
+ httpc_manager:which_sessions(profile_name(Profile))
+ end
+ catch
+ exit:{noproc, _} ->
+ {[], [], []}
+ end.
+
+
+%%--------------------------------------------------------------------------
%% info() -> list()
%% info(Profile) -> list()
%%
-%% Description: Debug function, retreive info about the profile
+%% Description: Debug function, retrieve info about the profile
%%-------------------------------------------------------------------------
info() ->
info(default_profile()).
@@ -1144,6 +1220,22 @@ validate_headers(RequestHeaders, _, _) ->
RequestHeaders.
+%%--------------------------------------------------------------------------
+%% These functions is just simple wrappers to parse specifically HTTP URIs
+%%--------------------------------------------------------------------------
+
+scheme_defaults() ->
+ [{http, 80}, {https, 443}].
+
+uri_parse(URI) ->
+ http_uri:parse(URI, [{scheme_defaults, scheme_defaults()}]).
+
+uri_parse(URI, Opts) ->
+ http_uri:parse(URI, [{scheme_defaults, scheme_defaults()} | Opts]).
+
+
+%%--------------------------------------------------------------------------
+
child_name2info(undefined) ->
{error, no_such_service};
child_name2info(httpc_manager) ->
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index bfe9b14ef6..6fe05dec80 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2012. 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
@@ -851,14 +851,17 @@ connect(SocketType, ToAddress,
case IpFamily of
inet6fb4 ->
Opts3 = [inet6 | Opts2],
- case http_transport:connect(SocketType, ToAddress, Opts3, Timeout) of
- {error, _Reason} = Error ->
+ case http_transport:connect(SocketType,
+ ToAddress, Opts3, Timeout) of
+ {error, Reason6} ->
Opts4 = [inet | Opts2],
case http_transport:connect(SocketType,
ToAddress, Opts4, Timeout) of
- {error, _} ->
- %% Reply with the "original" error
- Error;
+ {error, Reason4} ->
+ {error, {failed_connect,
+ [{to_address, ToAddress},
+ {inet6, Opts3, Reason6},
+ {inet, Opts4, Reason4}]}};
OK ->
OK
end;
@@ -867,7 +870,13 @@ connect(SocketType, ToAddress,
end;
_ ->
Opts3 = [IpFamily | Opts2],
- http_transport:connect(SocketType, ToAddress, Opts3, Timeout)
+ case http_transport:connect(SocketType, ToAddress, Opts3, Timeout) of
+ {error, Reason} ->
+ {error, {failed_connect, [{to_address, ToAddress},
+ {IpFamily, Opts3, Reason}]}};
+ Else ->
+ Else
+ end
end.
connect_and_send_first_request(Address, Request, #state{options = Options} = State) ->
@@ -1704,7 +1713,32 @@ update_session(ProfileName, #session{id = SessionId} = Session, Pos, Value) ->
catch
error:undef -> % This could happen during code upgrade
Session2 = erlang:setelement(Pos, Session, Value),
- insert_session(Session2, ProfileName)
+ insert_session(Session2, ProfileName);
+ T:E ->
+ error_logger:error_msg("Failed updating session: "
+ "~n ProfileName: ~p"
+ "~n SessionId: ~p"
+ "~n Pos: ~p"
+ "~n Value: ~p"
+ "~nwhen"
+ "~n Session (db) info: ~p"
+ "~n Session (db): ~p"
+ "~n Session (record): ~p"
+ "~n T: ~p"
+ "~n E: ~p",
+ [ProfileName, SessionId, Pos, Value,
+ (catch httpc_manager:which_session_info(ProfileName)),
+ Session,
+ (catch httpc_manager:lookup_session(ProfileName, SessionId)),
+ T, E]),
+ exit({failed_updating_session,
+ [{profile, ProfileName},
+ {session_id, SessionId},
+ {pos, Pos},
+ {value, Value},
+ {etype, T},
+ {error, E},
+ {stacktrace, erlang:get_stacktrace()}]})
end.
diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl
index 453081da21..3612b331e7 100644
--- a/lib/inets/src/http_client/httpc_manager.erl
+++ b/lib/inets/src/http_client/httpc_manager.erl
@@ -34,9 +34,13 @@
retry_request/2,
redirect_request/2,
insert_session/2,
+ lookup_session/2,
update_session/4,
delete_session/2,
+ which_sessions/1,
+ which_session_info/1,
set_options/2,
+ get_options/2,
store_cookies/3,
which_cookies/1, which_cookies/2, which_cookies/3,
reset_cookies/1,
@@ -58,17 +62,9 @@
options = #options{}
}).
--record(handler_info,
- {
- id, % Id of the request: request_id()
- starter, % Pid of the handler starter process (temp): pid()
- handler, % Pid of the handler process: pid()
- from, % From for the request: from()
- state % State of the handler: initiating | started | operational | canceled
- }).
-
-define(DELAY, 500).
+
%%====================================================================
%% Internal Application API
%%====================================================================
@@ -194,13 +190,28 @@ insert_session(Session, ProfileName) ->
%%--------------------------------------------------------------------
+%% Function: lookup_session(SessionId, ProfileName) -> _
+%% SessionId - term()
+%% ProfileName - atom()
+%%
+%% Description: Looks up a session record in the httpc manager
+%% table <ProfileName>__session_db.
+%%--------------------------------------------------------------------
+
+lookup_session(SessionId, ProfileName) ->
+ SessionDbName = session_db_name(ProfileName),
+ ?hcrt("lookup session", [{session_id, SessionId}, {profile, ProfileName}]),
+ ets:lookup(SessionDbName, SessionId).
+
+
+%%--------------------------------------------------------------------
%% Function: update_session(ProfileName, SessionId, Pos, Value) -> _
%% Session - #session{}
%% ProfileName - atom()
%%
%% Description: Update, only one field (Pos) of the session record
%% identified by the SessionId, the session information
-%% of the httpc manager table <ProfileName>_session_db.
+%% of the httpc manager table <ProfileName>__session_db.
%% Intended to be called by the httpc request handler process.
%%--------------------------------------------------------------------
@@ -215,12 +226,12 @@ update_session(ProfileName, SessionId, Pos, Value) ->
%%--------------------------------------------------------------------
-%% Function: delete_session(SessionId, ProfileName) -> _
+%% Function: delete_session(SessionId, ProfileName) -> void()
%% SessionId - {{Host, Port}, HandlerPid}
%% ProfileName - atom()
%%
%% Description: Deletes session information from the httpc manager
-%% table httpc_manager_session_db_<Profile>. Intended to be called by
+%% table <ProfileName>__session_db. Intended to be called by
%% the httpc request handler process.
%%--------------------------------------------------------------------
@@ -231,6 +242,57 @@ delete_session(SessionId, ProfileName) ->
%%--------------------------------------------------------------------
+%% Function: which sessions(ProfileName) -> SessionsInfo
+%% ProfileName - atom()
+%% SessionsInfo - {GoodSessions, BadSessions, NonSessions}
+%% GoodSessions - [#session{}]
+%% BadSessions - [tuple()]
+%% NonSessions - [term()]
+%%
+%% Description: Produces a list of all sessions in the session db.
+%% Used for debugging and since that is the intent, there is some
+%% checking and transforming done, which produces the results.
+%%--------------------------------------------------------------------
+
+which_sessions(ProfileName) ->
+ ?hcrt("which_sessions", [{profile, ProfileName}]),
+ SessionDbName = session_db_name(ProfileName),
+ which_sessions2(SessionDbName).
+
+which_sessions2(SessionDbName) ->
+ Sessions = which_sessions_order(ets:tab2list(SessionDbName)),
+ GoodSessions = [GoodSession || {good_session, GoodSession} <- Sessions],
+ BadSessions = [BadSession || {bad_session, BadSession} <- Sessions],
+ NonSessions = [NonSession || {non_session, NonSession} <- Sessions],
+ {lists:keysort(#session.id, GoodSessions),
+ lists:keysort(#session.id, BadSessions),
+ lists:sort(NonSessions)}.
+
+which_sessions_order([]) ->
+ [];
+which_sessions_order([Session|Sessions]) when is_record(Session, session) ->
+ [{good_session, Session} | which_sessions_order(Sessions)];
+which_sessions_order([BadSession|Sessions])
+ when is_tuple(BadSession) andalso
+ (element(1, BadSession) =:= session) ->
+ [{bad_session, BadSession} | which_sessions_order(Sessions)];
+which_sessions_order([NonSession|Sessions]) ->
+ [{non_session, NonSession} | which_sessions_order(Sessions)].
+
+
+%%--------------------------------------------------------------------
+%% Function: which session_info(ProfileName) -> list()
+%%
+%% Description: Produces a ets table info list of the sessions table
+%%--------------------------------------------------------------------
+
+which_session_info(ProfileName) ->
+ SessionDbName = session_db_name(ProfileName),
+ ?hcrt("which_session_info", [{profile, ProfileName}]),
+ ets:info(SessionDbName).
+
+
+%%--------------------------------------------------------------------
%% Function: set_options(Options, ProfileName) -> ok
%%
%% Options = [Option]
@@ -250,6 +312,21 @@ set_options(Options, ProfileName) ->
%%--------------------------------------------------------------------
+%% Function: get_options(OptionItems, ProfileName) -> Values
+%%
+%% OptionItems = [OptionItem]
+%% OptionItem = Any or all fields of the current #options{} record
+%% Values = [{OptionItem, Value}]
+%% Value = term()
+%%
+%% Description: Gets the specified options used by the client.
+%%--------------------------------------------------------------------
+
+get_options(Options, ProfileName) ->
+ call(ProfileName, {get_options, Options}).
+
+
+%%--------------------------------------------------------------------
%% Function: store_cookies(Cookies, Address, ProfileName) -> ok
%%
%% Cookies = [Cookie]
@@ -363,8 +440,7 @@ do_init(ProfileName, CookiesDir) ->
%% Create handler db
?hcrt("create handler/request db", []),
HandlerDbName = handler_db_name(ProfileName),
- ets:new(HandlerDbName,
- [protected, set, named_table, {keypos, #handler_info.id}]),
+ ets:new(HandlerDbName, [protected, set, named_table, {keypos, 1}]),
%% Cookie DB
?hcrt("create cookie db", []),
@@ -398,9 +474,10 @@ handle_call({request, Request}, _, State) ->
{stop, Error, httpc_response:error(Request, Error), State}
end;
-handle_call({cancel_request, RequestId}, From, State) ->
+handle_call({cancel_request, RequestId}, From,
+ #state{handler_db = HandlerDb} = State) ->
?hcri("cancel_request", [{request_id, RequestId}]),
- case ets:lookup(State#state.handler_db, RequestId) of
+ case ets:lookup(HandlerDb, RequestId) of
[] ->
%% The request has allready compleated make sure
%% it is deliverd to the client process queue so
@@ -412,9 +489,9 @@ handle_call({cancel_request, RequestId}, From, State) ->
{noreply, State};
[{_, Pid, _}] ->
httpc_handler:cancel(RequestId, Pid, From),
- {noreply, State#state{cancel =
- [{RequestId, Pid, From} |
- State#state.cancel]}}
+ {noreply,
+ State#state{cancel =
+ [{RequestId, Pid, From} | State#state.cancel]}}
end;
handle_call(reset_cookies, _, #state{cookie_db = CookieDb} = State) ->
@@ -430,7 +507,7 @@ handle_call(which_cookies, _, #state{cookie_db = CookieDb} = State) ->
handle_call({which_cookies, Url, Options}, _,
#state{cookie_db = CookieDb} = State) ->
?hcrv("which cookies", [{url, Url}, {options, Options}]),
- case http_uri:parse(Url, Options) of
+ case uri_parse(Url, Options) of
{ok, {Scheme, _, Host, Port, Path, _}} ->
CookieHeaders =
httpc_cookie:header(CookieDb, Scheme, {Host, Port}, Path),
@@ -439,6 +516,12 @@ handle_call({which_cookies, Url, Options}, _,
{reply, ERROR, State}
end;
+handle_call({get_options, OptionItems}, _, #state{options = Options} = State) ->
+ ?hcrv("get options", [{option_items, OptionItems}]),
+ Reply = [{OptionItem, get_option(OptionItem, Options)} ||
+ OptionItem <- OptionItems],
+ {reply, Reply, State};
+
handle_call(info, _, State) ->
?hcrv("info", []),
Info = get_manager_info(State),
@@ -623,7 +706,7 @@ code_change(_,
code_change(_, State, _) ->
{ok, State}.
-%% This function is to catch everything that calls through the cracks...
+%% This function is used to catch everything that falls through the cracks...
update_session_table(SessionDB, Transform) ->
ets:safe_fixtable(SessionDB, true),
update_session_table(SessionDB, ets:first(SessionDB), Transform),
@@ -651,40 +734,56 @@ update_session_table(SessionDB, Key, Transform) ->
%%--------------------------------------------------------------------
get_manager_info(#state{handler_db = HDB,
- cookie_db = CDB} = _State) ->
+ session_db = SDB,
+ cookie_db = CDB,
+ options = Options} = _State) ->
HandlerInfo = get_handler_info(HDB),
+ SessionInfo = which_sessions2(SDB),
+ OptionsInfo =
+ [{Item, get_option(Item, Options)} ||
+ Item <- record_info(fields, options)],
CookieInfo = httpc_cookie:which_cookies(CDB),
- [{handlers, HandlerInfo}, {cookies, CookieInfo}].
+ [{handlers, HandlerInfo},
+ {sessions, SessionInfo},
+ {options, OptionsInfo},
+ {cookies, CookieInfo}].
+
+sort_handlers(Unsorted) ->
+ sort_handlers2(lists:keysort(1, Unsorted)).
+
+sort_handlers2([]) ->
+ [];
+sort_handlers2([{HandlerPid, RequestId}|L]) ->
+ {Handler, Rest} = sort_handlers2(HandlerPid, [RequestId], L),
+ [Handler | sort_handlers2(Rest)].
+
+sort_handlers2(HandlerPid, Reqs, []) ->
+ {{HandlerPid, lists:sort(Reqs)}, []};
+sort_handlers2(HandlerPid, Reqs, [{HandlerPid, ReqId}|Rest]) ->
+ sort_handlers2(HandlerPid, [ReqId|Reqs], Rest);
+sort_handlers2(HandlerPid1, Reqs, [{HandlerPid2, _}|_] = Rest)
+ when HandlerPid1 =/= HandlerPid2 ->
+ {{HandlerPid1, lists:sort(Reqs)}, Rest}.
get_handler_info(Tab) ->
- Pattern = #handler_info{handler = '$1',
- state = '$2',
- _ = '_'},
- Handlers1 = [{Pid, State} || [Pid, State] <- ets:match(Tab, Pattern)],
- F = fun({Pid, State} = Elem, Acc) when State =/= canceled ->
- case lists:keymember(Pid, 1, Acc) of
- true ->
- Acc;
- false ->
- [Elem | Acc]
- end;
- (_, Acc) ->
- Acc
- end,
- Handlers2 = lists:foldl(F, [], Handlers1),
- Handlers3 = [{Pid, State,
- case (catch httpc_handler:info(Pid)) of
- {'EXIT', _} ->
+ Pattern = {'$2', '$1', '_'},
+ Handlers1 = [{Pid, Id} || [Pid, Id] <- ets:match(Tab, Pattern)],
+ Handlers2 = sort_handlers(Handlers1),
+ Handlers3 = [{Pid, Reqs,
+ try
+ begin
+ httpc_handler:info(Pid)
+ end
+ catch
+ _:_ ->
%% Why would this crash?
%% Only if the process has died, but we don't
%% know about it?
- [];
- Else ->
- Else
- end} ||
- {Pid, State} <- Handlers2],
+ []
+ end} || {Pid, Reqs} <- Handlers2],
Handlers3.
+
handle_request(#request{settings =
#http_options{version = "HTTP/0.9"}} = Request,
State) ->
@@ -736,19 +835,21 @@ handle_request(Request, State = #state{options = Options}) ->
{reply, {ok, NewRequest#request.id}, State}.
-start_handler(Request, State) ->
+start_handler(#request{id = Id,
+ from = From} = Request,
+ #state{profile_name = ProfileName,
+ handler_db = HandlerDb,
+ options = Options}) ->
{ok, Pid} =
case is_inets_manager() of
true ->
httpc_handler_sup:start_child([whereis(httpc_handler_sup),
- Request, State#state.options,
- State#state.profile_name]);
+ Request, Options, ProfileName]);
false ->
- httpc_handler:start_link(self(), Request, State#state.options,
- State#state.profile_name)
+ httpc_handler:start_link(self(), Request, Options, ProfileName)
end,
- ets:insert(State#state.handler_db, {Request#request.id,
- Pid, Request#request.from}),
+ HandlerInfo = {Id, Pid, From},
+ ets:insert(HandlerDb, HandlerInfo),
erlang:monitor(process, Pid).
@@ -805,12 +906,14 @@ select_session(Candidates, Max) ->
{ok, HandlerPid}
end.
-pipeline_or_keep_alive(Request, HandlerPid, State) ->
+pipeline_or_keep_alive(#request{id = Id,
+ from = From} = Request,
+ HandlerPid,
+ #state{handler_db = HandlerDb} = State) ->
case (catch httpc_handler:send(Request, HandlerPid)) of
ok ->
- ets:insert(State#state.handler_db, {Request#request.id,
- HandlerPid,
- Request#request.from});
+ HandlerInfo = {Id, HandlerPid, From},
+ ets:insert(HandlerDb, HandlerInfo);
_ -> % timeout pipelining failed
start_handler(Request, State)
end.
@@ -872,6 +975,19 @@ make_db_name(ProfileName, Post) ->
list_to_atom(atom_to_list(ProfileName) ++ Post).
+%%--------------------------------------------------------------------------
+%% These functions is just simple wrappers to parse specifically HTTP URIs
+%%--------------------------------------------------------------------------
+
+scheme_defaults() ->
+ [{http, 80}, {https, 443}].
+
+uri_parse(URI, Opts) ->
+ http_uri:parse(URI, [{scheme_defaults, scheme_defaults()} | Opts]).
+
+
+%%--------------------------------------------------------------------------
+
call(ProfileName, Msg) ->
Timeout = infinity,
@@ -883,6 +999,31 @@ cast(ProfileName, Msg) ->
gen_server:cast(ProfileName, Msg).
+get_option(proxy, #options{proxy = Proxy}) ->
+ Proxy;
+get_option(pipeline_timeout, #options{pipeline_timeout = Timeout}) ->
+ Timeout;
+get_option(max_pipeline_length, #options{max_pipeline_length = Length}) ->
+ Length;
+get_option(keep_alive_timeout, #options{keep_alive_timeout = Timeout}) ->
+ Timeout;
+get_option(max_keep_alive_length, #options{max_keep_alive_length = Length}) ->
+ Length;
+get_option(max_sessions, #options{max_sessions = MaxSessions}) ->
+ MaxSessions;
+get_option(cookies, #options{cookies = Cookies}) ->
+ Cookies;
+get_option(verbose, #options{verbose = Verbose}) ->
+ Verbose;
+get_option(ipfamily, #options{ipfamily = IpFamily}) ->
+ IpFamily;
+get_option(ip, #options{ip = IP}) ->
+ IP;
+get_option(port, #options{port = Port}) ->
+ Port;
+get_option(socket_opts, #options{socket_opts = SocketOpts}) ->
+ SocketOpts.
+
get_proxy(Opts, #options{proxy = Default}) ->
proplists:get_value(proxy, Opts, Default).
diff --git a/lib/inets/src/http_client/httpc_response.erl b/lib/inets/src/http_client/httpc_response.erl
index 919115a23a..04976447cc 100644
--- a/lib/inets/src/http_client/httpc_response.erl
+++ b/lib/inets/src/http_client/httpc_response.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2012. 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
@@ -342,7 +342,7 @@ redirect(Response = {StatusLine, Headers, Body}, Request) ->
RedirUrl ->
UrlParseOpts = [{ipv6_host_with_brackets,
Request#request.ipv6_host_with_brackets}],
- case http_uri:parse(RedirUrl, UrlParseOpts) of
+ case uri_parse(RedirUrl, UrlParseOpts) of
{error, no_scheme} when
(Request#request.settings)#http_options.relaxed ->
NewLocation = fix_relative_uri(Request, RedirUrl),
@@ -437,3 +437,17 @@ format_response({StatusLine, Headers, Body}) ->
end,
{{StatusLine, http_response:header_list(Headers), NewBody}, Data}.
+%%--------------------------------------------------------------------------
+%% These functions is just simple wrappers to parse specifically HTTP URIs
+%%--------------------------------------------------------------------------
+
+scheme_defaults() ->
+ [{http, 80}, {https, 443}].
+
+uri_parse(URI, Opts) ->
+ http_uri:parse(URI, [{scheme_defaults, scheme_defaults()} | Opts]).
+
+
+%%--------------------------------------------------------------------------
+
+
diff --git a/lib/inets/src/http_lib/Makefile b/lib/inets/src/http_lib/Makefile
index aaf3cfb995..3ec6ce7436 100644
--- a/lib/inets/src/http_lib/Makefile
+++ b/lib/inets/src/http_lib/Makefile
@@ -87,11 +87,11 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/http_lib
- $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/http_lib
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/http_lib"
+ $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/src/http_lib"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/inets/src/http_lib/http_uri.erl b/lib/inets/src/http_lib/http_uri.erl
index 32c6305a79..5962001c3a 100644
--- a/lib/inets/src/http_lib/http_uri.erl
+++ b/lib/inets/src/http_lib/http_uri.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2012. 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
@@ -17,39 +17,95 @@
%% %CopyrightEnd%
%%
%%
-%% RFC 3986
+%% This is from chapter 3, Syntax Components, of RFC 3986:
+%%
+%% The generic URI syntax consists of a hierarchical sequence of
+%% components referred to as the scheme, authority, path, query, and
+%% fragment.
+%%
+%% URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+%%
+%% hier-part = "//" authority path-abempty
+%% / path-absolute
+%% / path-rootless
+%% / path-empty
+%%
+%% The scheme and path components are required, though the path may be
+%% empty (no characters). When authority is present, the path must
+%% either be empty or begin with a slash ("/") character. When
+%% authority is not present, the path cannot begin with two slash
+%% characters ("//"). These restrictions result in five different ABNF
+%% rules for a path (Section 3.3), only one of which will match any
+%% given URI reference.
+%%
+%% The following are two example URIs and their component parts:
+%%
+%% foo://example.com:8042/over/there?name=ferret#nose
+%% \_/ \______________/\_________/ \_________/ \__/
+%% | | | | |
+%% scheme authority path query fragment
+%% | _____________________|__
+%% / \ / \
+%% urn:example:animal:ferret:nose
+%%
+%% scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+%% authority = [ userinfo "@" ] host [ ":" port ]
+%% userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
+%%
%%
-module(http_uri).
-export([parse/1, parse/2,
+ scheme_defaults/0,
encode/1, decode/1]).
+-export_type([scheme/0, default_scheme_port_number/0]).
+
%%%=========================================================================
%%% API
%%%=========================================================================
+
+-type scheme() :: atom().
+-type default_scheme_port_number() :: pos_integer().
+
+-spec scheme_defaults() ->
+ [{scheme(), default_scheme_port_number()}].
+
+scheme_defaults() ->
+ [{http, 80},
+ {https, 443},
+ {ftp, 21},
+ {ssh, 22},
+ {sftp, 22},
+ {tftp, 69}].
+
parse(AbsURI) ->
parse(AbsURI, []).
parse(AbsURI, Opts) ->
- case parse_scheme(AbsURI) of
+ case parse_scheme(AbsURI, Opts) of
{error, Reason} ->
{error, Reason};
- {Scheme, Rest} ->
- case (catch parse_uri_rest(Scheme, Rest, Opts)) of
- {UserInfo, Host, Port, Path, Query} ->
+ {Scheme, DefaultPort, Rest} ->
+ case (catch parse_uri_rest(Scheme, DefaultPort, Rest, Opts)) of
+ {ok, {UserInfo, Host, Port, Path, Query}} ->
{ok, {Scheme, UserInfo, Host, Port, Path, Query}};
+ {error, Reason} ->
+ {error, {Reason, Scheme, AbsURI}};
_ ->
- {error, {malformed_url, AbsURI}}
+ {error, {malformed_url, Scheme, AbsURI}}
end
end.
+reserved() ->
+ sets:from_list([$;, $:, $@, $&, $=, $+, $,, $/, $?,
+ $#, $[, $], $<, $>, $\", ${, $}, $|,
+ $\\, $', $^, $%, $ ]).
+
encode(URI) ->
- Reserved = sets:from_list([$;, $:, $@, $&, $=, $+, $,, $/, $?,
- $#, $[, $], $<, $>, $\", ${, $}, $|,
- $\\, $', $^, $%, $ ]),
- %% lists:append(lists:map(fun(Char) -> uri_encode(Char, Reserved) end, URI)).
+ Reserved = reserved(),
lists:append([uri_encode(Char, Reserved) || Char <- URI]).
decode(String) ->
@@ -67,20 +123,31 @@ do_decode([]) ->
%%% Internal functions
%%%========================================================================
-parse_scheme(AbsURI) ->
+which_scheme_defaults(Opts) ->
+ Key = scheme_defaults,
+ case lists:keysearch(Key, 1, Opts) of
+ {value, {Key, SchemeDefaults}} ->
+ SchemeDefaults;
+ false ->
+ scheme_defaults()
+ end.
+
+parse_scheme(AbsURI, Opts) ->
case split_uri(AbsURI, ":", {error, no_scheme}, 1, 1) of
{error, no_scheme} ->
{error, no_scheme};
- {StrScheme, Rest} ->
- case list_to_atom(http_util:to_lower(StrScheme)) of
- Scheme when (Scheme =:= http) orelse (Scheme =:= https) ->
- {Scheme, Rest};
- Scheme ->
- {error, {not_supported_scheme, Scheme}}
+ {SchemeStr, Rest} ->
+ Scheme = list_to_atom(http_util:to_lower(SchemeStr)),
+ SchemeDefaults = which_scheme_defaults(Opts),
+ case lists:keysearch(Scheme, 1, SchemeDefaults) of
+ {value, {Scheme, DefaultPort}} ->
+ {Scheme, DefaultPort, Rest};
+ false ->
+ {Scheme, no_default_port, Rest}
end
end.
-parse_uri_rest(Scheme, "//" ++ URIPart, Opts) ->
+parse_uri_rest(Scheme, DefaultPort, "//" ++ URIPart, Opts) ->
{Authority, PathQuery} =
case split_uri(URIPart, "/", URIPart, 1, 0) of
Split = {_, _} ->
@@ -93,26 +160,25 @@ parse_uri_rest(Scheme, "//" ++ URIPart, Opts) ->
{URIPart,""}
end
end,
-
{UserInfo, HostPort} = split_uri(Authority, "@", {"", Authority}, 1, 1),
- {Host, Port} = parse_host_port(Scheme, HostPort, Opts),
+ {Host, Port} = parse_host_port(Scheme, DefaultPort, HostPort, Opts),
{Path, Query} = parse_path_query(PathQuery),
- {UserInfo, Host, Port, Path, Query}.
+ {ok, {UserInfo, Host, Port, Path, Query}}.
parse_path_query(PathQuery) ->
{Path, Query} = split_uri(PathQuery, "\\?", {PathQuery, ""}, 1, 0),
{path(Path), Query}.
-parse_host_port(Scheme,"[" ++ HostPort, Opts) -> %ipv6
- DefaultPort = default_port(Scheme),
+%% In this version of the function, we no longer need
+%% the Scheme argument, but just in case...
+parse_host_port(_Scheme, DefaultPort, "[" ++ HostPort, Opts) -> %ipv6
{Host, ColonPort} = split_uri(HostPort, "\\]", {HostPort, ""}, 1, 1),
Host2 = maybe_ipv6_host_with_brackets(Host, Opts),
{_, Port} = split_uri(ColonPort, ":", {"", DefaultPort}, 0, 1),
{Host2, int_port(Port)};
-parse_host_port(Scheme, HostPort, _Opts) ->
- DefaultPort = default_port(Scheme),
+parse_host_port(_Scheme, DefaultPort, HostPort, _Opts) ->
{Host, Port} = split_uri(HostPort, ":", {HostPort, DefaultPort}, 1, 1),
{Host, int_port(Port)}.
@@ -133,15 +199,14 @@ maybe_ipv6_host_with_brackets(Host, Opts) ->
Host
end.
-default_port(http) ->
- 80;
-default_port(https) ->
- 443.
int_port(Port) when is_integer(Port) ->
Port;
int_port(Port) when is_list(Port) ->
- list_to_integer(Port).
+ list_to_integer(Port);
+%% This is the case where no port was found and there was no default port
+int_port(no_default_port) ->
+ throw({error, no_default_port}).
path("") ->
"/";
diff --git a/lib/inets/src/http_server/Makefile b/lib/inets/src/http_server/Makefile
index 55cc68dede..67555d5f1c 100644
--- a/lib/inets/src/http_server/Makefile
+++ b/lib/inets/src/http_server/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2005-2010. All Rights Reserved.
+# Copyright Ericsson AB 2005-2012. 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
@@ -88,6 +88,8 @@ ERL_FILES = $(MODULES:%=%.erl)
TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"'
+
# ----------------------------------------------------
# FLAGS
@@ -121,11 +123,11 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/http_server
- $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/http_server
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/http_server"
+ $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/src/http_server"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/inets/src/http_server/httpd_conf.erl b/lib/inets/src/http_server/httpd_conf.erl
index 7646300409..b575d7331b 100644
--- a/lib/inets/src/http_server/httpd_conf.erl
+++ b/lib/inets/src/http_server/httpd_conf.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2012. 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
@@ -210,12 +210,32 @@ load("MaxBodySize " ++ MaxBodySize, []) ->
{ok, Integer} ->
{ok, [], {max_body_size,Integer}};
{error, _} ->
- {error, ?NICE(clean(MaxBodySize)++
+ {error, ?NICE(clean(MaxBodySize) ++
" is an invalid number of MaxBodySize")}
end;
load("ServerName " ++ ServerName, []) ->
- {ok,[],{server_name,clean(ServerName)}};
+ {ok,[], {server_name, clean(ServerName)}};
+
+load("ServerTokens " ++ ServerTokens, []) ->
+ %% These are the valid *plain* server tokens:
+ %% sprod, major, minor, minimum, os, full
+ %% It can also be a "private" server token: private:<any string>
+ case string:tokens(ServerTokens, [$:]) of
+ ["private", Private] ->
+ {ok,[], {server_tokens, clean(Private)}};
+ [TokStr] ->
+ Tok = list_to_atom(clean(TokStr)),
+ case lists:member(Tok, [prod, major, minor, minimum, os, full]) of
+ true ->
+ {ok,[], {server_tokens, Tok}};
+ false ->
+ {error, ?NICE(clean(ServerTokens) ++
+ " is an invalid ServerTokens")}
+ end;
+ _ ->
+ {error, ?NICE(clean(ServerTokens) ++ " is an invalid ServerTokens")}
+ end;
load("SocketType " ++ SocketType, []) ->
%% ssl is the same as HTTP_DEFAULT_SSL_KIND
@@ -475,7 +495,7 @@ validate_properties(Properties) ->
validate_properties2(Properties) ->
case proplists:get_value(bind_address, Properties) of
undefined ->
- case proplists:get_value(sock_type, Properties, ip_comm) of
+ case proplists:get_value(sock_type, Properties, ip_comm) of
ip_comm ->
case proplists:get_value(ipfamily, Properties) of
undefined ->
@@ -537,6 +557,20 @@ validate_config_params([{server_name, Value} | Rest])
validate_config_params([{server_name, Value} | _]) ->
throw({server_name, Value});
+validate_config_params([{server_tokens, Value} | Rest])
+ when is_atom(Value) ->
+ case lists:member(Value, plain_server_tokens()) of
+ true ->
+ validate_config_params(Rest);
+ false ->
+ throw({server_tokens, Value})
+ end;
+validate_config_params([{server_tokens, {private, Value}} | Rest])
+ when is_list(Value) ->
+ validate_config_params(Rest);
+validate_config_params([{server_tokens, Value} | _]) ->
+ throw({server_tokens, Value});
+
validate_config_params([{socket_type, Value} | Rest])
when (Value =:= ip_comm) orelse
(Value =:= ssl) orelse
@@ -737,9 +771,73 @@ store({log_format, LogFormat}, _ConfigList)
store({log_format, LogFormat}, _ConfigList)
when (LogFormat =:= compact) orelse (LogFormat =:= pretty) ->
{ok, {log_format, LogFormat}};
+store({server_tokens, ServerTokens} = Entry, _ConfigList) ->
+ Server = server(ServerTokens),
+ {ok, [Entry, {server, Server}]};
store(ConfigListEntry, _ConfigList) ->
{ok, ConfigListEntry}.
+
+%% The SERVER_SOFTWARE macro has the following structure:
+%% <product>/<version>
+%% Example: "inets/1.2.3"
+%% So, with this example (on a linux machine, with OTP R15B),
+%% this will result in:
+%% prod: "inets"
+%% major: "inets/1"
+%% minor: "inets/1.2"
+%% minimal: "inets/1.2.3"
+%% os: "inets/1.2.3 (unix)
+%% full: "inets/1.2.3 (unix/linux) OTP/R15B"
+%% Note that the format of SERVER_SOFTWARE is that of 'minimal'.
+%% Also, there will always be atleast two digits in a version:
+%% Not just 1 but 1.0
+%%
+%% We have already checked that the value is valid,
+%% so there is no need to check enything here.
+%%
+server(prod = _ServerTokens) ->
+ [Prod|_Version] = string:tokens(?SERVER_SOFTWARE, [$/]),
+ Prod;
+server(major = _ServerTokens) ->
+ [Prod|Version] = string:tokens(?SERVER_SOFTWARE, [$/]),
+ [Major|_] = string:tokens(Version, [$.]),
+ Prod ++ "/" ++ Major;
+server(minor = _ServerTokens) ->
+ [Prod|Version] = string:tokens(?SERVER_SOFTWARE, [$/]),
+ [Major,Minor|_] = string:tokens(Version, [$.]),
+ Prod ++ "/" ++ Major ++ "." ++ Minor;
+server(minimal = _ServerTokens) ->
+ %% This is the default
+ ?SERVER_SOFTWARE;
+server(os = _ServerTokens) ->
+ OS = os_info(partial),
+ lists:flatten(io_lib:format("~s ~s", [?SERVER_SOFTWARE, OS]));
+server(full = _ServerTokens) ->
+ OTPRelease = otp_release(),
+ OS = os_info(full),
+ lists:flatten(
+ io_lib:format("~s ~s OTP/~s", [?SERVER_SOFTWARE, OS, OTPRelease]));
+server({private, Server} = _ServerTokens) when is_list(Server) ->
+ %% The user provide its own
+ Server;
+server(_) ->
+ ?SERVER_SOFTWARE.
+
+os_info(Info) ->
+ case os:type() of
+ {OsFamily, _OsName} when Info =:= partial ->
+ lists:flatten(io_lib:format("(~w)", [OsFamily]));
+ {OsFamily, OsName} ->
+ lists:flatten(io_lib:format("(~w/~w)", [OsFamily, OsName]));
+ OsFamily ->
+ lists:flatten(io_lib:format("(~w)", [OsFamily]))
+ end.
+
+otp_release() ->
+ erlang:system_info(otp_release).
+
+
%% Phase 3: Remove
remove_all(ConfigDB) ->
Modules = httpd_util:lookup(ConfigDB,modules,[]),
@@ -1159,6 +1257,10 @@ ssl_ca_certificate_file(ConfigDB) ->
[{cacertfile, File}]
end.
+plain_server_tokens() ->
+ [prod, major, minor, minimum, os, full].
+
error_report(Where,M,F,Error) ->
error_logger:error_report([{?MODULE, Where},
{apply, {M, F, []}}, Error]).
+
diff --git a/lib/inets/src/http_server/httpd_response.erl b/lib/inets/src/http_server/httpd_response.erl
index dd7223876e..2dedb088e4 100644
--- a/lib/inets/src/http_server/httpd_response.erl
+++ b/lib/inets/src/http_server/httpd_response.erl
@@ -144,10 +144,14 @@ send_response(ModData, Header, Body) ->
end
end.
-send_header(#mod{socket_type = Type, socket = Sock,
- http_version = Ver, connection = Conn} = _ModData,
+send_header(#mod{socket_type = Type,
+ socket = Sock,
+ http_version = Ver,
+ connection = Conn,
+ config_db = ConfigDb} = _ModData,
StatusCode, KeyValueTupleHeaders) ->
- Headers = create_header(lists:map(fun transform/1, KeyValueTupleHeaders)),
+ Headers = create_header(ConfigDb,
+ lists:map(fun transform/1, KeyValueTupleHeaders)),
NewVer = case {Ver, StatusCode} of
{[], _} ->
%% May be implicit!
@@ -275,13 +279,20 @@ cache_headers(#mod{config_db = Db}) ->
[]
end.
-create_header(KeyValueTupleHeaders) ->
- NewHeaders = add_default_headers([{"date", httpd_util:rfc1123_date()},
- {"content-type", "text/html"},
- {"server", ?SERVER_SOFTWARE}],
- KeyValueTupleHeaders),
+create_header(ConfigDb, KeyValueTupleHeaders) ->
+ Date = httpd_util:rfc1123_date(),
+ ContentType = "text/html",
+ Server = server(ConfigDb),
+ NewHeaders = add_default_headers([{"date", Date},
+ {"content-type", ContentType},
+ {"server", Server}],
+ KeyValueTupleHeaders),
lists:map(fun fix_header/1, NewHeaders).
+
+server(ConfigDb) ->
+ httpd_util:lookup(ConfigDb, server, ?SERVER_SOFTWARE).
+
fix_header({Key0, Value}) ->
%% make sure first letter is capital
Words1 = string:tokens(Key0, "-"),
diff --git a/lib/inets/src/http_server/httpd_script_env.erl b/lib/inets/src/http_server/httpd_script_env.erl
index d3115150b0..ac79a8cc63 100644
--- a/lib/inets/src/http_server/httpd_script_env.erl
+++ b/lib/inets/src/http_server/httpd_script_env.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2012. 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
@@ -50,29 +50,44 @@ create_env(ScriptType, ModData, ScriptElements) ->
%%%========================================================================
%%% Internal functions
%%%========================================================================
+
+which_server(#mod{config_db = ConfigDb}) ->
+ httpd_util:lookup(ConfigDb, server, ?SERVER_SOFTWARE).
+
+which_port(#mod{config_db = ConfigDb}) ->
+ httpd_util:lookup(ConfigDb, port, 80).
+
+which_peername(#mod{init_data = #init_data{peername = {_, RemoteAddr}}}) ->
+ RemoteAddr.
+
+which_resolve(#mod{init_data = #init_data{resolve = Resolve}}) ->
+ Resolve.
+
+which_method(#mod{method = Method}) ->
+ Method.
+
+which_request_uri(#mod{request_uri = RUri}) ->
+ RUri.
+
create_basic_elements(esi, ModData) ->
- {_, RemoteAddr} = (ModData#mod.init_data)#init_data.peername,
- [{server_software, ?SERVER_SOFTWARE},
- {server_name, (ModData#mod.init_data)#init_data.resolve},
- {gateway_interface,?GATEWAY_INTERFACE},
- {server_protocol, ?SERVER_PROTOCOL},
- {server_port, httpd_util:lookup(ModData#mod.config_db,port,80)},
- {request_method, ModData#mod.method},
- {remote_addr, RemoteAddr},
- {script_name, ModData#mod.request_uri}];
+ [{server_software, which_server(ModData)},
+ {server_name, which_resolve(ModData)},
+ {gateway_interface, ?GATEWAY_INTERFACE},
+ {server_protocol, ?SERVER_PROTOCOL},
+ {server_port, which_port(ModData)},
+ {request_method, which_method(ModData)},
+ {remote_addr, which_peername(ModData)},
+ {script_name, which_request_uri(ModData)}];
create_basic_elements(cgi, ModData) ->
- {_, RemoteAddr} = (ModData#mod.init_data)#init_data.peername,
- [{"SERVER_SOFTWARE",?SERVER_SOFTWARE},
- {"SERVER_NAME", (ModData#mod.init_data)#init_data.resolve},
- {"GATEWAY_INTERFACE",?GATEWAY_INTERFACE},
- {"SERVER_PROTOCOL",?SERVER_PROTOCOL},
- {"SERVER_PORT",
- integer_to_list(httpd_util:lookup(
- ModData#mod.config_db, port, 80))},
- {"REQUEST_METHOD", ModData#mod.method},
- {"REMOTE_ADDR", RemoteAddr},
- {"SCRIPT_NAME", ModData#mod.request_uri}].
+ [{"SERVER_SOFTWARE", which_server(ModData)},
+ {"SERVER_NAME", which_resolve(ModData)},
+ {"GATEWAY_INTERFACE", ?GATEWAY_INTERFACE},
+ {"SERVER_PROTOCOL", ?SERVER_PROTOCOL},
+ {"SERVER_PORT", integer_to_list(which_port(ModData))},
+ {"REQUEST_METHOD", which_method(ModData)},
+ {"REMOTE_ADDR", which_peername(ModData)},
+ {"SCRIPT_NAME", which_request_uri(ModData)}].
create_http_header_elements(ScriptType, Headers) ->
create_http_header_elements(ScriptType, Headers, []).
@@ -80,7 +95,7 @@ create_http_header_elements(ScriptType, Headers) ->
create_http_header_elements(_, [], Acc) ->
Acc;
create_http_header_elements(ScriptType, [{Name, [Value | _] = Values } |
- Headers], Acc)
+ Headers], Acc)
when is_list(Value) ->
NewName = lists:map(fun(X) -> if X == $- -> $_; true -> X end end, Name),
Element = http_env_element(ScriptType, NewName, multi_value(Values)),
diff --git a/lib/inets/src/http_server/httpd_sup.erl b/lib/inets/src/http_server/httpd_sup.erl
index 264dc9f006..8f3e8f9500 100644
--- a/lib/inets/src/http_server/httpd_sup.erl
+++ b/lib/inets/src/http_server/httpd_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2012. 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
@@ -162,17 +162,30 @@ httpd_config([Value| _] = Config) when is_tuple(Value) ->
httpd_child_spec([Value| _] = Config, AcceptTimeout, Debug)
when is_tuple(Value) ->
+ ?hdrt("httpd_child_spec - entry", [{accept_timeout, AcceptTimeout},
+ {debug, Debug}]),
Address = proplists:get_value(bind_address, Config, any),
Port = proplists:get_value(port, Config, 80),
httpd_child_spec(Config, AcceptTimeout, Debug, Address, Port);
-httpd_child_spec(ConfigFile, AcceptTimeout, Debug) ->
+%% In this case the AcceptTimeout and Debug will only have default values...
+httpd_child_spec(ConfigFile, AcceptTimeoutDef, DebugDef) ->
+ ?hdrt("httpd_child_spec - entry", [{config_file, ConfigFile},
+ {accept_timeout_def, AcceptTimeoutDef},
+ {debug_def, DebugDef}]),
case httpd_conf:load(ConfigFile) of
{ok, ConfigList} ->
+ ?hdrt("httpd_child_spec - loaded", [{config_list, ConfigList}]),
case (catch httpd_conf:validate_properties(ConfigList)) of
{ok, Config} ->
+ ?hdrt("httpd_child_spec - validated", [{config, Config}]),
Address = proplists:get_value(bind_address, Config, any),
Port = proplists:get_value(port, Config, 80),
+ AcceptTimeout =
+ proplists:get_value(accept_timeout, Config,
+ AcceptTimeoutDef),
+ Debug =
+ proplists:get_value(debug, Config, DebugDef),
httpd_child_spec([{file, ConfigFile} | Config],
AcceptTimeout, Debug, Address, Port);
Error ->
@@ -183,7 +196,7 @@ httpd_child_spec(ConfigFile, AcceptTimeout, Debug) ->
end.
httpd_child_spec(Config, AcceptTimeout, Debug, Addr, Port) ->
- case Port == 0 orelse proplists:is_defined(fd, Config) of
+ case (Port =:= 0) orelse proplists:is_defined(fd, Config) of
true ->
httpd_child_spec_listen(Config, AcceptTimeout, Debug, Addr, Port);
false ->
diff --git a/lib/inets/src/http_server/mod_get.erl b/lib/inets/src/http_server/mod_get.erl
index 5cb30e3d97..758985f330 100644
--- a/lib/inets/src/http_server/mod_get.erl
+++ b/lib/inets/src/http_server/mod_get.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2012. 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
@@ -18,9 +18,16 @@
%%
%%
-module(mod_get).
+
-export([do/1]).
+
-include("httpd.hrl").
-include("httpd_internal.hrl").
+-include("inets_internal.hrl").
+
+-define(VMODULE,"GET").
+
+
%% do
do(Info) ->
@@ -84,15 +91,16 @@ send_response(_Socket, _SocketType, Path, Info)->
file:close(FileDescriptor),
{proceed,[{response,{already_sent,200,
FileInfo#file_info.size}},
- {mime_type,MimeType}|Info#mod.data]};
+ {mime_type,MimeType} | Info#mod.data]};
{error, Reason} ->
+ ?hdrt("send_response -> failed open file",
+ [{path, Path}, {reason, Reason}]),
Status = httpd_file:handle_error(Reason, "open", Info, Path),
- {proceed,
- [{status, Status}| Info#mod.data]}
+ {proceed, [{status, Status} | Info#mod.data]}
end.
%% send
-
+
send(#mod{socket = Socket, socket_type = SocketType} = Info,
StatusCode, Headers, FileDescriptor) ->
?DEBUG("send -> send header",[]),
diff --git a/lib/inets/src/inets_app/Makefile b/lib/inets/src/inets_app/Makefile
index d99e33b4ea..b8d923edd8 100644
--- a/lib/inets/src/inets_app/Makefile
+++ b/lib/inets/src/inets_app/Makefile
@@ -46,7 +46,8 @@ MODULES = \
inets_service \
inets_app \
inets_sup \
- inets_regexp
+ inets_regexp \
+ inets_trace
INTERNAL_HRL_FILES = inets_internal.hrl
EXTERNAL_HRL_FILES = ../../include/httpd.hrl \
@@ -110,13 +111,13 @@ $(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/inets_app
- $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/inets_app
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(EXTERNAL_HRL_FILES) $(RELSYSDIR)/include
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/inets_app"
+ $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/src/inets_app"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(EXTERNAL_HRL_FILES) "$(RELSYSDIR)/include"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/inets/src/inets_app/inets.app.src b/lib/inets/src/inets_app/inets.app.src
index 1db7ed2c30..4aea2ef3d7 100644
--- a/lib/inets/src/inets_app/inets.app.src
+++ b/lib/inets/src/inets_app/inets.app.src
@@ -18,14 +18,15 @@
%%
{application,inets,
- [{description,"INETS CXC 138 49"},
- {vsn,"%VSN%"},
+ [{description, "INETS CXC 138 49"},
+ {vsn, "%VSN%"},
{modules,[
inets,
inets_sup,
inets_app,
inets_service,
inets_regexp,
+ inets_trace,
%% FTP
ftp,
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index e80cb2a23b..2adb2a0fc8 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -18,62 +18,92 @@
{"%VSN%",
[
- {"5.8",
+ {"5.9",
[
- {load_module, ftp, soft_purge, soft_purge, []},
- {update, httpc_handler, {advanced, upgrade_from_pre_5_8_1},
- soft_purge, soft_purge, []},
- {update, httpc_manager, {advanced, upgrade_from_pre_5_8_1},
- soft_purge, soft_purge, [httpc_handler]}
+ {load_module, tftp, soft_purge, soft_purge, [inets_service]},
+ {load_module, inets_service, soft_purge, soft_purge, []},
+ {load_module, httpc, soft_purge, soft_purge, [httpc_manager]},
+ {update, httpc_handler, soft, soft_purge, soft_purge, [httpc_manager]},
+ {update, httpc_manager, soft, soft_purge, soft_purge, []}
]
},
- {"5.7.2",
+ {"5.8.1",
[
- {restart_application, inets}
- ]
- },
- {"5.7.1",
- [
- {restart_application, inets}
+ {load_module, tftp, soft_purge, soft_purge, [inets_service]},
+ {load_module, inets_service, soft_purge, soft_purge, []},
+
+ {load_module, http_uri, soft_purge, soft_purge, []},
+ {load_module, httpc_response, soft_purge, soft_purge, [http_uri]},
+
+ {load_module, httpc, soft_purge, soft_purge,
+ [http_uri, httpc_manager]},
+
+ {load_module, inets_app, soft_purge, soft_purge, [inets_sup]},
+ {update, inets_sup, soft, soft_purge, soft_purge, []},
+
+ {load_module, httpd_conf, soft_purge, soft_purge, []},
+ {load_module, httpd_response, soft_purge, soft_purge, []},
+ {load_module, httpd_script_env, soft_purge, soft_purge, []},
+
+ {load_module, inets, soft_purge, soft_purge, [inets_trace]},
+ {update, httpc_manager, soft, soft_purge, soft_purge, [http_uri]},
+ {update, httpc_handler, soft, soft_purge, soft_purge, [httpc_manager]},
+ {update, httpd_sup, soft, soft_purge, soft_purge, []},
+ {add_module, inets_trace}
]
},
- {"5.7",
+ {"5.8",
[
{restart_application, inets}
]
},
- {"5.6",
+ {"5.7.2",
[
{restart_application, inets}
]
- }
+ }
],
[
- {"5.8",
+ {"5.9",
[
- {load_module, ftp, soft_purge, soft_purge, []},
- {update, httpc_handler, {advanced, upgrade_from_pre_5_8_1},
- soft_purge, soft_purge, []},
- {update, httpc_manager, {advanced, upgrade_from_pre_5_8_1},
- soft_purge, soft_purge, [httpc_handler]}
+ {load_module, tftp, soft_purge, soft_purge, [inets_service]},
+ {load_module, inets_service, soft_purge, soft_purge, []},
+ {load_module, httpc, soft_purge, soft_purge, [httpc_manager]},
+ {update, httpc_handler, soft, soft_purge, soft_purge, [httpc_manager]},
+ {update, httpc_manager, soft, soft_purge, soft_purge, []}
]
},
- {"5.7.2",
+ {"5.8.1",
[
- {restart_application, inets}
- ]
- },
- {"5.7.1",
- [
- {restart_application, inets}
+ {load_module, tftp, soft_purge, soft_purge, [inets_service]},
+ {load_module, inets_service, soft_purge, soft_purge, []},
+
+ {load_module, http_uri, soft_purge, soft_purge, []},
+ {load_module, httpc_response, soft_purge, soft_purge, [http_uri]},
+
+ {load_module, httpc, soft_purge, soft_purge,
+ [http_uri, httpc_manager]},
+
+ {load_module, inets_app, soft_purge, soft_purge, [inets_sup]},
+ {update, inets_sup, soft, soft_purge, soft_purge, []},
+
+ {load_module, httpd_conf, soft_purge, soft_purge, []},
+ {load_module, httpd_response, soft_purge, soft_purge, []},
+ {load_module, httpd_script_env, soft_purge, soft_purge, []},
+
+ {load_module, inets, soft_purge, soft_purge, []},
+ {update, httpc_manager, soft, soft_purge, soft_purge, [http_uri]},
+ {update, httpc_handler, soft, soft_purge, soft_purge, [httpc_manager]},
+ {update, httpd_sup, soft, soft_purge, soft_purge, []},
+ {remove, {inets_trace, soft_purge, brutal_purge}}
]
},
- {"5.7",
+ {"5.8",
[
{restart_application, inets}
]
},
- {"5.6",
+ {"5.7.2",
[
{restart_application, inets}
]
diff --git a/lib/inets/src/inets_app/inets.erl b/lib/inets/src/inets_app/inets.erl
index 054468e445..f33e0abe27 100644
--- a/lib/inets/src/inets_app/inets.erl
+++ b/lib/inets/src/inets_app/inets.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2012. 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
@@ -28,7 +28,7 @@
stop/0, stop/2,
services/0, services_info/0,
service_names/0]).
--export([enable_trace/2, enable_trace/3, disable_trace/0, set_trace/1,
+-export([enable_trace/2, enable_trace/3, disable_trace/0, set_trace/1,
report_event/4]).
-export([versions/0,
print_version_info/0, print_version_info/1]).
@@ -409,47 +409,8 @@ service_names() ->
%% Severity withing Limit) will be written to stdout using io:format.
%%
%%-----------------------------------------------------------------
-enable_trace(Level, Dest) ->
- enable_trace(Level, Dest, all).
-
-enable_trace(Level, Dest, Service) ->
- case valid_trace_service(Service) of
- true ->
- enable_trace2(Level, Dest, Service);
- false ->
- {error, {invalid_service, Service}}
- end.
-
-enable_trace2(Level, File, Service)
- when is_list(File) ->
- case file:open(File, [write]) of
- {ok, Fd} ->
- HandleSpec = {fun handle_trace/2, {Service, Fd}},
- do_enable_trace(Level, process, HandleSpec);
- Err ->
- Err
- end;
-enable_trace2(Level, Port, _) when is_integer(Port) ->
- do_enable_trace(Level, port, dbg:trace_port(ip, Port));
-enable_trace2(Level, io, Service) ->
- HandleSpec = {fun handle_trace/2, {Service, standard_io}},
- do_enable_trace(Level, process, HandleSpec);
-enable_trace2(Level, {Fun, _Data} = HandleSpec, _) when is_function(Fun) ->
- do_enable_trace(Level, process, HandleSpec).
-
-do_enable_trace(Level, Type, HandleSpec) ->
- case dbg:tracer(Type, HandleSpec) of
- {ok, _} ->
- set_trace(Level),
- ok;
- Error ->
- Error
- end.
-
-valid_trace_service(all) ->
- true;
-valid_trace_service(Service) ->
- lists:member(Service, [httpc, httpd, ftpc, tftp]).
+enable_trace(Level, Dest) -> inets_trace:enable(Level, Dest).
+enable_trace(Level, Dest, Service) -> inets_trace:enable(Level, Dest, Service).
%%-----------------------------------------------------------------
@@ -458,12 +419,7 @@ valid_trace_service(Service) ->
%% Description:
%% This function is used to stop tracing.
%%-----------------------------------------------------------------
-disable_trace() ->
- %% This is to make handle_trace/2 close the output file (if the
- %% event gets there before dbg closes)
- inets:report_event(100, "stop trace", stop_trace, [stop_trace]),
- dbg:stop().
-
+disable_trace() -> inets_trace:disable().
%%-----------------------------------------------------------------
@@ -476,60 +432,7 @@ disable_trace() ->
%% This function is used to change the trace level when tracing has
%% already been started.
%%-----------------------------------------------------------------
-set_trace(Level) ->
- set_trace(Level, all).
-
-set_trace(Level, Service) ->
- Pat = make_pattern(?MODULE, Service, Level),
- change_pattern(Pat).
-
-make_pattern(Mod, Service, Level)
- when is_atom(Mod) andalso is_atom(Service) ->
- case Level of
- min ->
- {Mod, Service, []};
- max ->
- Head = ['$1', '_', '_', '_'],
- Body = [],
- Cond = [],
- {Mod, Service, [{Head, Cond, Body}]};
- DetailLevel when is_integer(DetailLevel) ->
- Head = ['$1', '_', '_', '_'],
- Body = [],
- Cond = [{ '=<', '$1', DetailLevel}],
- {Mod, Service, [{Head, Cond, Body}]};
- _ ->
- exit({bad_level, Level})
- end.
-
-change_pattern({Mod, Service, Pattern})
- when is_atom(Mod) andalso is_atom(Service) ->
- MFA = {Mod, report_event, 4},
- case Pattern of
- [] ->
- try
- error_to_exit(ctp, dbg:ctp(MFA)),
- error_to_exit(p, dbg:p(all, clear))
- catch
- exit:{Where, Reason} ->
- {error, {Where, Reason}}
- end;
- List when is_list(List) ->
- try
- error_to_exit(ctp, dbg:ctp(MFA)),
- error_to_exit(tp, dbg:tp(MFA, Pattern)),
- error_to_exit(p, dbg:p(all, [call, timestamp]))
- catch
- exit:{Where, Reason} ->
- {error, {Where, Reason}}
- end
- end,
- ok.
-
-error_to_exit(_Where, {ok, _} = OK) ->
- OK;
-error_to_exit(Where, {error, Reason}) ->
- exit({Where, Reason}).
+set_trace(Level) -> inets_trace:set_level(Level).
%%-----------------------------------------------------------------
@@ -546,164 +449,8 @@ error_to_exit(Where, {error, Reason}) ->
%% put trace on this function.
%%-----------------------------------------------------------------
-report_event(Severity, Label, Service, Content)
- when (is_integer(Severity) andalso
- (Severity >= 0) andalso (100 >= Severity)) andalso
- is_list(Label) andalso
- is_atom(Service) andalso
- is_list(Content) ->
- hopefully_traced.
-
-
-%% ----------------------------------------------------------------------
-%% handle_trace(Event, Fd) -> Verbosity
-%%
-%% Parameters:
-%% Event -> The trace event (only megaco 'trace_ts' events are printed)
-%% Fd -> standard_io | file_descriptor() | trace_port()
-%%
-%% Description:
-%% This function is used to "receive" and print the trace events.
-%% Events are printed if:
-%% - Verbosity is max
-%% - Severity is =< Verbosity (e.g. Severity = 30, and Verbosity = 40)
-%% Events are not printed if:
-%% - Verbosity is min
-%% - Severity is > Verbosity
-%%-----------------------------------------------------------------
-
-handle_trace(_, closed_file = Fd) ->
- Fd;
-handle_trace({trace_ts, _Who, call,
- {?MODULE, report_event,
- [_Sev, "stop trace", stop_trace, [stop_trace]]},
- Timestamp},
- {_, standard_io} = Fd) ->
- (catch io:format(standard_io, "stop trace at ~s~n", [format_timestamp(Timestamp)])),
- Fd;
-handle_trace({trace_ts, _Who, call,
- {?MODULE, report_event,
- [_Sev, "stop trace", stop_trace, [stop_trace]]},
- Timestamp},
- standard_io = Fd) ->
- (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])),
- Fd;
-handle_trace({trace_ts, _Who, call,
- {?MODULE, report_event,
- [_Sev, "stop trace", stop_trace, [stop_trace]]},
- Timestamp},
- {_Service, Fd}) ->
- (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])),
- (catch file:close(Fd)),
- closed_file;
-handle_trace({trace_ts, _Who, call,
- {?MODULE, report_event,
- [_Sev, "stop trace", stop_trace, [stop_trace]]},
- Timestamp},
- Fd) ->
- (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])),
- (catch file:close(Fd)),
- closed_file;
-handle_trace({trace_ts, Who, call,
- {?MODULE, report_event,
- [Sev, Label, Service, Content]}, Timestamp},
- Fd) ->
- (catch print_inets_trace(Fd, Sev, Timestamp, Who,
- Label, Service, Content)),
- Fd;
-handle_trace(Event, Fd) ->
- (catch print_trace(Fd, Event)),
- Fd.
-
-
-print_inets_trace({Service, Fd},
- Sev, Timestamp, Who, Label, Service, Content) ->
- do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content);
-print_inets_trace({ServiceA, Fd},
- Sev, Timestamp, Who, Label, ServiceB, Content)
- when (ServiceA =:= all) ->
- do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, ServiceB, Content);
-print_inets_trace({ServiceA, _Fd},
- _Sev, _Timestamp, _Who, _Label, ServiceB, _Content)
- when ServiceA =/= ServiceB ->
- ok;
-print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content) ->
- do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content).
-
-do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content) ->
- Ts = format_timestamp(Timestamp),
- io:format(Fd, "[inets ~w trace ~w ~w ~s] ~s "
- "~n Content: ~p"
- "~n",
- [Service, Sev, Who, Ts, Label, Content]).
-
-print_trace({_, Fd}, Event) ->
- do_print_trace(Fd, Event);
-print_trace(Fd, Event) ->
- do_print_trace(Fd, Event).
-
-do_print_trace(Fd, {trace, Who, What, Where}) ->
- io:format(Fd, "[trace]"
- "~n Who: ~p"
- "~n What: ~p"
- "~n Where: ~p"
- "~n", [Who, What, Where]);
-
-do_print_trace(Fd, {trace, Who, What, Where, Extra}) ->
- io:format(Fd, "[trace]"
- "~n Who: ~p"
- "~n What: ~p"
- "~n Where: ~p"
- "~n Extra: ~p"
- "~n", [Who, What, Where, Extra]);
-
-do_print_trace(Fd, {trace_ts, Who, What, Where, When}) ->
- Ts = format_timestamp(When),
- io:format(Fd, "[trace ~s]"
- "~n Who: ~p"
- "~n What: ~p"
- "~n Where: ~p"
- "~n", [Ts, Who, What, Where]);
-
-do_print_trace(Fd, {trace_ts, Who, What, Where, Extra, When}) ->
- Ts = format_timestamp(When),
- io:format(Fd, "[trace ~s]"
- "~n Who: ~p"
- "~n What: ~p"
- "~n Where: ~p"
- "~n Extra: ~p"
- "~n", [Ts, Who, What, Where, Extra]);
-
-do_print_trace(Fd, {seq_trace, What, Where}) ->
- io:format(Fd, "[seq trace]"
- "~n What: ~p"
- "~n Where: ~p"
- "~n", [What, Where]);
-
-do_print_trace(Fd, {seq_trace, What, Where, When}) ->
- Ts = format_timestamp(When),
- io:format(Fd, "[seq trace ~s]"
- "~n What: ~p"
- "~n Where: ~p"
- "~n", [Ts, What, Where]);
-
-do_print_trace(Fd, {drop, Num}) ->
- io:format(Fd, "[drop trace] ~p~n", [Num]);
-
-do_print_trace(Fd, Trace) ->
- io:format(Fd, "[trace] "
- "~n ~p"
- "~n", [Trace]).
-
-
-format_timestamp({_N1, _N2, N3} = Now) ->
- {Date, Time} = calendar:now_to_datetime(Now),
- {YYYY,MM,DD} = Date,
- {Hour,Min,Sec} = Time,
- FormatDate =
- io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
- [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
- lists:flatten(FormatDate).
+report_event(Severity, Label, Service, Content) ->
+ inets_trace:report_event(Severity, Label, Service, Content).
%%--------------------------------------------------------------------
diff --git a/lib/inets/src/inets_app/inets.mk b/lib/inets/src/inets_app/inets.mk
index 194b4ca2b1..adef32dc19 100644
--- a/lib/inets/src/inets_app/inets.mk
+++ b/lib/inets/src/inets_app/inets.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2011. All Rights Reserved.
+# Copyright Ericsson AB 2010-2012. 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
@@ -33,16 +33,10 @@ ifeq ($(WARN_UNUSED_WARS), true)
ERL_COMPILE_FLAGS += +warn_unused_vars
endif
-ifeq ($(shell erl -noshell -eval 'io:format("~4s", [erlang:system_info(otp_release)])' -s init stop), R14B)
-INETS_ERL_COMPILE_FLAGS += -D'OTP-R14B-COMPILER'
-endif
-
INETS_APP_VSN_COMPILE_FLAGS = \
+'{parse_transform,sys_pre_attributes}' \
+'{attribute,insert,app_vsn,$(APP_VSN)}'
-INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"'
-
INETS_ERL_COMPILE_FLAGS += \
-pa $(ERL_TOP)/lib/inets/ebin \
$(INETS_APP_VSN_COMPILE_FLAGS)
diff --git a/lib/inets/src/inets_app/inets_app.erl b/lib/inets/src/inets_app/inets_app.erl
index cae79a6767..ee3359c4c3 100644
--- a/lib/inets/src/inets_app/inets_app.erl
+++ b/lib/inets/src/inets_app/inets_app.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2012. 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
@@ -24,7 +24,7 @@
-export([start/2, stop/1]).
start(_Type, _State) ->
- supervisor:start_link({local, inets_sup}, inets_sup, []).
+ inets_sup:start_link().
stop(_State) ->
ok.
diff --git a/lib/inets/src/inets_app/inets_internal.hrl b/lib/inets/src/inets_app/inets_internal.hrl
index 55c3669e4a..e56af3b59d 100644
--- a/lib/inets/src/inets_app/inets_internal.hrl
+++ b/lib/inets/src/inets_app/inets_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -24,8 +24,8 @@
%% Various trace macros
-define(report(Severity, Label, Service, Content),
- inets:report_event(Severity, Label, Service,
- [{module, ?MODULE}, {line, ?LINE} | Content])).
+ inets_trace:report_event(Severity, Label, Service,
+ [{module, ?MODULE}, {line, ?LINE} | Content])).
-define(report_important(Label, Service, Content),
?report(20, Label, Service, Content)).
-define(report_verbose(Label, Service, Content),
diff --git a/lib/inets/src/inets_app/inets_service.erl b/lib/inets/src/inets_app/inets_service.erl
index a057a51e2c..d17fdfe13e 100644
--- a/lib/inets/src/inets_app/inets_service.erl
+++ b/lib/inets/src/inets_app/inets_service.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2012. 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
@@ -20,20 +20,6 @@
-module(inets_service).
--ifdef('OTP-R14B-COMPILER').
-
--export([behaviour_info/1]).
-
-behaviour_info(callbacks) ->
- [{start_standalone, 1},
- {start_service, 1},
- {stop_service, 1},
- {services, 0},
- {service_info, 1}];
-behaviour_info(_) ->
- undefined.
-
--else.
%% Starts service stand-alone
%% start_standalone(Config) -> % {ok, Pid} | {error, Reason}
@@ -83,4 +69,3 @@ behaviour_info(_) ->
-callback service_info(Service :: term()) ->
{ok, [{Property :: term(), Value :: term()}]} | {error, Reason :: term()}.
--endif.
diff --git a/lib/inets/src/inets_app/inets_sup.erl b/lib/inets/src/inets_app/inets_sup.erl
index 20d5ef343e..66a0cdf785 100644
--- a/lib/inets/src/inets_app/inets_sup.erl
+++ b/lib/inets/src/inets_app/inets_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2012. 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
@@ -25,9 +25,19 @@
-behaviour(supervisor).
+%% External API
+-export([start_link/0]).
+
+%% Supervisor callbacks
-export([init/1]).
%%%=========================================================================
+%%% External functions
+%%%=========================================================================
+start_link() ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
init([]) ->
diff --git a/lib/inets/src/inets_app/inets_trace.erl b/lib/inets/src/inets_app/inets_trace.erl
new file mode 100644
index 0000000000..8911f65897
--- /dev/null
+++ b/lib/inets/src/inets_app/inets_trace.erl
@@ -0,0 +1,357 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Module for debug trace functions of the inets application
+%%----------------------------------------------------------------------
+
+-module(inets_trace).
+
+%% API
+-export([enable/2, enable/3,
+ disable/0,
+ set_level/1, set_level/2,
+ report_event/4]).
+
+
+%%====================================================================
+%% API
+%%====================================================================
+
+%%-----------------------------------------------------------------
+%% enable(Level, Destination) -> void()
+%% enable(Level, Destination, Service) -> void()
+%%
+%% Parameters:
+%% Level -> max | min | integer()
+%% Destination -> File | Port | io | HandlerSpec
+%% Service -> httpc | httpd | ftpc | tftp | all
+%% File -> string()
+%% Port -> integer()
+%% Verbosity -> true | false
+%% HandlerSpec = {function(), Data}
+%% Data = term()
+%%
+%% Description:
+%% This function is used to start tracing at level Level and send
+%% the result either to the file File, the port Port or to a
+%% trace handler.
+%% Note that it starts a tracer server.
+%% When Destination is the atom io (or the tuple {io, Verbosity}),
+%% all (printable) inets trace events (trace_ts events which has
+%% Severity withing Limit) will be written to stdout using io:format.
+%%
+%%-----------------------------------------------------------------
+enable(Level, Dest) ->
+ enable(Level, Dest, all).
+
+enable(Level, Dest, Service) ->
+ case valid_trace_service(Service) of
+ true ->
+ enable2(Level, Dest, Service);
+ false ->
+ {error, {invalid_service, Service}}
+ end.
+
+enable2(Level, File, Service)
+ when is_list(File) ->
+ case file:open(File, [write]) of
+ {ok, Fd} ->
+ HandleSpec = {fun handle_trace/2, {Service, Fd}},
+ do_enable(Level, process, HandleSpec);
+ Err ->
+ Err
+ end;
+enable2(Level, Port, _) when is_integer(Port) ->
+ do_enable(Level, port, dbg:trace_port(ip, Port));
+enable2(Level, io, Service) ->
+ HandleSpec = {fun handle_trace/2, {Service, standard_io}},
+ do_enable(Level, process, HandleSpec);
+enable2(Level, {Fun, _Data} = HandleSpec, _) when is_function(Fun) ->
+ do_enable(Level, process, HandleSpec).
+
+do_enable(Level, Type, HandleSpec) ->
+ case dbg:tracer(Type, HandleSpec) of
+ {ok, _} ->
+ set_level(Level),
+ ok;
+ Error ->
+ Error
+ end.
+
+valid_trace_service(all) ->
+ true;
+valid_trace_service(Service) ->
+ lists:member(Service, [httpc, httpd, ftpc, tftp]).
+
+
+%%-----------------------------------------------------------------
+%% disable() -> void()
+%%
+%% Description:
+%% This function is used to stop tracing.
+%%-----------------------------------------------------------------
+
+disable() ->
+ %% This is to make handle_trace/2 close the output file (if the
+ %% event gets there before dbg closes)
+ inets_trace:report_event(100, "stop trace", stop_trace, [stop_trace]),
+ dbg:stop().
+
+
+
+%%-----------------------------------------------------------------
+%% set_level(Level) -> void()
+%%
+%% Parameters:
+%% Level -> max | min | integer()
+%%
+%% Description:
+%% This function is used to change the trace level when tracing has
+%% already been started.
+%%-----------------------------------------------------------------
+set_level(Level) ->
+ set_level(Level, all).
+
+set_level(Level, Service) ->
+ Pat = make_pattern(?MODULE, Service, Level),
+ change_pattern(Pat).
+
+make_pattern(Mod, Service, Level)
+ when is_atom(Mod) andalso is_atom(Service) ->
+ case Level of
+ min ->
+ {Mod, Service, []};
+ max ->
+ Head = ['$1', '_', '_', '_'],
+ Body = [],
+ Cond = [],
+ {Mod, Service, [{Head, Cond, Body}]};
+ DetailLevel when is_integer(DetailLevel) ->
+ Head = ['$1', '_', '_', '_'],
+ Body = [],
+ Cond = [{ '=<', '$1', DetailLevel}],
+ {Mod, Service, [{Head, Cond, Body}]};
+ _ ->
+ exit({bad_level, Level})
+ end.
+
+change_pattern({Mod, Service, Pattern})
+ when is_atom(Mod) andalso is_atom(Service) ->
+ MFA = {Mod, report_event, 4},
+ case Pattern of
+ [] ->
+ try
+ error_to_exit(ctp, dbg:ctp(MFA)),
+ error_to_exit(p, dbg:p(all, clear))
+ catch
+ exit:{Where, Reason} ->
+ {error, {Where, Reason}}
+ end;
+ List when is_list(List) ->
+ try
+ error_to_exit(ctp, dbg:ctp(MFA)),
+ error_to_exit(tp, dbg:tp(MFA, Pattern)),
+ error_to_exit(p, dbg:p(all, [call, timestamp]))
+ catch
+ exit:{Where, Reason} ->
+ {error, {Where, Reason}}
+ end
+ end.
+
+error_to_exit(_Where, {ok, _} = OK) ->
+ OK;
+error_to_exit(Where, {error, Reason}) ->
+ exit({Where, Reason}).
+
+
+%%-----------------------------------------------------------------
+%% report_event(Severity, Label, Service, Content)
+%%
+%% Parameters:
+%% Severity -> 0 =< integer() =< 100
+%% Label -> string()
+%% Service -> httpd | httpc | ftp | tftp
+%% Content -> [{tag, term()}]
+%%
+%% Description:
+%% This function is used to generate trace events, that is,
+%% put trace on this function.
+%%-----------------------------------------------------------------
+
+report_event(Severity, Label, Service, Content)
+ when (is_integer(Severity) andalso
+ (Severity >= 0) andalso (100 >= Severity)) andalso
+ is_list(Label) andalso
+ is_atom(Service) andalso
+ is_list(Content) ->
+ hopefully_traced.
+
+
+%% ----------------------------------------------------------------------
+%% handle_trace(Event, Fd) -> Verbosity
+%%
+%% Parameters:
+%% Event -> The trace event
+%% Fd -> standard_io | file_descriptor() | trace_port()
+%%
+%% Description:
+%% This function is used to "receive" and pretty print the trace events.
+%% Events are printed if:
+%% - Verbosity is max
+%% - Severity is =< Verbosity (e.g. Severity = 30, and Verbosity = 40)
+%% Events are not printed if:
+%% - Verbosity is min
+%% - Severity is > Verbosity
+%%-----------------------------------------------------------------
+
+handle_trace(_, closed_file = Fd) ->
+ Fd;
+handle_trace({trace_ts, _Who, call,
+ {?MODULE, report_event,
+ [_Sev, "stop trace", stop_trace, [stop_trace]]},
+ Timestamp},
+ {_, standard_io} = Fd) ->
+ (catch io:format(standard_io, "stop trace at ~s~n", [format_timestamp(Timestamp)])),
+ Fd;
+handle_trace({trace_ts, _Who, call,
+ {?MODULE, report_event,
+ [_Sev, "stop trace", stop_trace, [stop_trace]]},
+ Timestamp},
+ standard_io = Fd) ->
+ (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])),
+ Fd;
+handle_trace({trace_ts, _Who, call,
+ {?MODULE, report_event,
+ [_Sev, "stop trace", stop_trace, [stop_trace]]},
+ Timestamp},
+ {_Service, Fd}) ->
+ (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])),
+ (catch file:close(Fd)),
+ closed_file;
+handle_trace({trace_ts, _Who, call,
+ {?MODULE, report_event,
+ [_Sev, "stop trace", stop_trace, [stop_trace]]},
+ Timestamp},
+ Fd) ->
+ (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])),
+ (catch file:close(Fd)),
+ closed_file;
+handle_trace({trace_ts, Who, call,
+ {?MODULE, report_event,
+ [Sev, Label, Service, Content]}, Timestamp},
+ Fd) ->
+ (catch print_inets_trace(Fd, Sev, Timestamp, Who,
+ Label, Service, Content)),
+ Fd;
+handle_trace(Event, Fd) ->
+ (catch print_trace(Fd, Event)),
+ Fd.
+
+
+print_inets_trace({Service, Fd},
+ Sev, Timestamp, Who, Label, Service, Content) ->
+ do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content);
+print_inets_trace({ServiceA, Fd},
+ Sev, Timestamp, Who, Label, ServiceB, Content)
+ when (ServiceA =:= all) ->
+ do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, ServiceB, Content);
+print_inets_trace({ServiceA, _Fd},
+ _Sev, _Timestamp, _Who, _Label, ServiceB, _Content)
+ when ServiceA =/= ServiceB ->
+ ok;
+print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content) ->
+ do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content).
+
+do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content) ->
+ Ts = format_timestamp(Timestamp),
+ io:format(Fd, "[inets ~w trace ~w ~w ~s] ~s "
+ "~n Content: ~p"
+ "~n",
+ [Service, Sev, Who, Ts, Label, Content]).
+
+print_trace({_, Fd}, Event) ->
+ do_print_trace(Fd, Event);
+print_trace(Fd, Event) ->
+ do_print_trace(Fd, Event).
+
+do_print_trace(Fd, {trace, Who, What, Where}) ->
+ io:format(Fd, "[trace]"
+ "~n Who: ~p"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n", [Who, What, Where]);
+
+do_print_trace(Fd, {trace, Who, What, Where, Extra}) ->
+ io:format(Fd, "[trace]"
+ "~n Who: ~p"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n Extra: ~p"
+ "~n", [Who, What, Where, Extra]);
+
+do_print_trace(Fd, {trace_ts, Who, What, Where, When}) ->
+ Ts = format_timestamp(When),
+ io:format(Fd, "[trace ~s]"
+ "~n Who: ~p"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n", [Ts, Who, What, Where]);
+
+do_print_trace(Fd, {trace_ts, Who, What, Where, Extra, When}) ->
+ Ts = format_timestamp(When),
+ io:format(Fd, "[trace ~s]"
+ "~n Who: ~p"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n Extra: ~p"
+ "~n", [Ts, Who, What, Where, Extra]);
+
+do_print_trace(Fd, {seq_trace, What, Where}) ->
+ io:format(Fd, "[seq trace]"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n", [What, Where]);
+
+do_print_trace(Fd, {seq_trace, What, Where, When}) ->
+ Ts = format_timestamp(When),
+ io:format(Fd, "[seq trace ~s]"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n", [Ts, What, Where]);
+
+do_print_trace(Fd, {drop, Num}) ->
+ io:format(Fd, "[drop trace] ~p~n", [Num]);
+
+do_print_trace(Fd, Trace) ->
+ io:format(Fd, "[trace] "
+ "~n ~p"
+ "~n", [Trace]).
+
+
+format_timestamp({_N1, _N2, N3} = Now) ->
+ {Date, Time} = calendar:now_to_datetime(Now),
+ {YYYY,MM,DD} = Date,
+ {Hour,Min,Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+ [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
+ lists:flatten(FormatDate).
+
+
diff --git a/lib/inets/src/tftp/Makefile b/lib/inets/src/tftp/Makefile
index 759b70c8e4..a9df8d0319 100644
--- a/lib/inets/src/tftp/Makefile
+++ b/lib/inets/src/tftp/Makefile
@@ -39,8 +39,10 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
# ----------------------------------------------------
# Target Specs
# ----------------------------------------------------
+BEHAVIOUR_MODULES= \
+ tftp
+
MODULES = \
- tftp \
tftp_binary \
tftp_engine \
tftp_file \
@@ -50,10 +52,13 @@ MODULES = \
HRL_FILES = tftp.hrl
-ERL_FILES = $(MODULES:%=%.erl)
+ERL_FILES= \
+ $(MODULES:%=%.erl) \
+ $(BEHAVIOUR_MODULES:%=%.erl)
TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+BEHAVIOUR_TARGET_FILES= $(BEHAVIOUR_MODULES:%=$(EBIN)/%.$(EMULATOR))
# ----------------------------------------------------
# FLAGS
@@ -72,10 +77,12 @@ ERL_COMPILE_FLAGS += \
# Targets
# ----------------------------------------------------
+$(TARGET_FILES): $(BEHAVIOUR_TARGET_FILES)
+
debug opt: $(TARGET_FILES)
clean:
- rm -f $(TARGET_FILES)
+ rm -f $(TARGET_FILES) $(BEHAVIOUR_TARGET_FILES)
rm -f core
docs:
@@ -86,11 +93,11 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/tftp
- $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/tftp
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/tftp"
+ $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/src/tftp"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) $(BEHAVIOUR_TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/inets/src/tftp/tftp.erl b/lib/inets/src/tftp/tftp.erl
index 0d7ae1a89e..1621add246 100644
--- a/lib/inets/src/tftp/tftp.erl
+++ b/lib/inets/src/tftp/tftp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2012. 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
@@ -224,20 +224,6 @@
service_info/1
]).
--ifdef('OTP-R14B-COMPILER').
-
--export([behaviour_info/1]).
-
-behaviour_info(callbacks) ->
- [{prepare, 6},
- {open, 6},
- {read, 1},
- {write, 2},
- {abort, 3}];
-behaviour_info(_) ->
- undefined.
-
--else.
-type peer() :: {PeerType :: inet | inet6,
PeerHost :: inet:ip_address(),
@@ -280,8 +266,6 @@ behaviour_info(_) ->
-callback abort(Code :: error_code(), string(), State :: term()) -> 'ok'.
--endif.
-
-include("tftp.hrl").