aboutsummaryrefslogtreecommitdiffstats
path: root/lib/inets/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/inets/src')
-rw-r--r--lib/inets/src/ftp/Makefile12
-rw-r--r--lib/inets/src/ftp/ftp.erl2
-rw-r--r--lib/inets/src/http_client/Makefile12
-rw-r--r--lib/inets/src/http_client/httpc.erl122
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl1015
-rw-r--r--lib/inets/src/http_client/httpc_internal.hrl2
-rw-r--r--lib/inets/src/http_client/httpc_manager.erl256
-rw-r--r--lib/inets/src/http_client/httpc_response.erl18
-rw-r--r--lib/inets/src/http_lib/Makefile12
-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.erl108
-rw-r--r--lib/inets/src/http_server/httpd_log.erl12
-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/Makefile19
-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.erl278
-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/Makefile25
-rw-r--r--lib/inets/src/tftp/tftp.erl18
29 files changed, 1711 insertions, 965 deletions
diff --git a/lib/inets/src/ftp/Makefile b/lib/inets/src/ftp/Makefile
index 19b93870df..2c3d2b6d13 100644
--- a/lib/inets/src/ftp/Makefile
+++ b/lib/inets/src/ftp/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,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..f0d4ce139e 100644
--- a/lib/inets/src/http_client/Makefile
+++ b/lib/inets/src/http_client/Makefile
@@ -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
@@ -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..ede649a5a9 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()).
@@ -841,6 +917,10 @@ validate_options([{proxy, Proxy} = Opt| Tail], Acc) ->
validate_proxy(Proxy),
validate_options(Tail, [Opt | Acc]);
+validate_options([{https_proxy, Proxy} = Opt| Tail], Acc) ->
+ validate_https_proxy(Proxy),
+ validate_options(Tail, [Opt | Acc]);
+
validate_options([{max_sessions, Value} = Opt| Tail], Acc) ->
validate_max_sessions(Value),
validate_options(Tail, [Opt | Acc]);
@@ -903,6 +983,14 @@ validate_proxy({{ProxyHost, ProxyPort}, NoProxy} = Proxy)
validate_proxy(BadProxy) ->
bad_option(proxy, BadProxy).
+validate_https_proxy({{ProxyHost, ProxyPort}, NoProxy} = Proxy)
+ when is_list(ProxyHost) andalso
+ is_integer(ProxyPort) andalso
+ is_list(NoProxy) ->
+ Proxy;
+validate_https_proxy(BadProxy) ->
+ bad_option(https_proxy, BadProxy).
+
validate_max_sessions(Value) when is_integer(Value) andalso (Value >= 0) ->
Value;
validate_max_sessions(BadValue) ->
@@ -1144,6 +1232,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..784a9c0019 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
@@ -29,44 +29,44 @@
%%--------------------------------------------------------------------
%% Internal Application API
-export([
- start_link/4,
- %% connect_and_send/2,
- send/2,
- cancel/3,
- stream/3,
- stream_next/1,
- info/1
- ]).
+ start_link/4,
+ %% connect_and_send/2,
+ send/2,
+ cancel/3,
+ stream/3,
+ stream_next/1,
+ info/1
+ ]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
- terminate/2, code_change/3]).
+ terminate/2, code_change/3]).
-record(timers,
- {
- request_timers = [], % [ref()]
- queue_timer % ref()
- }).
+ {
+ request_timers = [], % [ref()]
+ queue_timer % ref()
+ }).
-record(state,
- {
- request, % #request{}
- session, % #session{}
- status_line, % {Version, StatusCode, ReasonPharse}
- headers, % #http_response_h{}
- body, % binary()
- mfa, % {Moduel, Function, Args}
- pipeline = queue:new(), % queue()
- keep_alive = queue:new(), % queue()
- status, % undefined | new | pipeline | keep_alive | close | ssl_tunnel
- canceled = [], % [RequestId]
- max_header_size = nolimit, % nolimit | integer()
- max_body_size = nolimit, % nolimit | integer()
- options, % #options{}
- timers = #timers{}, % #timers{}
- profile_name, % atom() - id of httpc_manager process.
- once % send | undefined
- }).
+ {
+ request, % #request{}
+ session, % #session{}
+ status_line, % {Version, StatusCode, ReasonPharse}
+ headers, % #http_response_h{}
+ body, % binary()
+ mfa, % {Module, Function, Args}
+ pipeline = queue:new(), % queue()
+ keep_alive = queue:new(), % queue()
+ status, % undefined | new | pipeline | keep_alive | close | {ssl_tunnel, Request}
+ canceled = [], % [RequestId]
+ max_header_size = nolimit, % nolimit | integer()
+ max_body_size = nolimit, % nolimit | integer()
+ options, % #options{}
+ timers = #timers{}, % #timers{}
+ profile_name, % atom() - id of httpc_manager process.
+ once % send | undefined
+ }).
%%====================================================================
@@ -75,8 +75,8 @@
%%--------------------------------------------------------------------
%% Function: start_link(Request, Options, ProfileName) -> {ok, Pid}
%%
-%% Request = #request{}
-%% Options = #options{}
+%% Request = #request{}
+%% Options = #options{}
%% ProfileName = atom() - id of httpc manager process
%%
%% Description: Starts a http-request handler process. Intended to be
@@ -96,11 +96,11 @@
start_link(Parent, Request, Options, ProfileName) ->
{ok, proc_lib:start_link(?MODULE, init, [[Parent, Request, Options,
- ProfileName]])}.
+ ProfileName]])}.
%%--------------------------------------------------------------------
%% Function: send(Request, Pid) -> ok
-%% Request = #request{}
+%% Request = #request{}
%% Pid = pid() - the pid of the http-request handler process.
%%
%% Description: Uses this handlers session to send a request. Intended
@@ -112,7 +112,7 @@ send(Request, Pid) ->
%%--------------------------------------------------------------------
%% Function: cancel(RequestId, Pid) -> ok
-%% RequestId = ref()
+%% RequestId = ref()
%% Pid = pid() - the pid of the http-request handler process.
%%
%% Description: Cancels a request. Intended to be called by the httpc
@@ -142,12 +142,16 @@ stream_next(Pid) ->
%% Used for debugging and testing
%%--------------------------------------------------------------------
info(Pid) ->
- call(info, Pid).
-
+ try
+ call(info, Pid)
+ catch
+ _:_ ->
+ []
+ end.
%%--------------------------------------------------------------------
%% Function: stream(BodyPart, Request, Code) -> _
-%% BodyPart = binary()
+%% BodyPart = binary()
%% Request = #request{}
%% Code = integer()
%%
@@ -167,7 +171,7 @@ stream(BodyPart, #request{stream = Self} = Request, Code)
((Self =:= self) orelse (Self =:= {self, once})) ->
?hcrt("stream - self", [{stream, Self}, {code, Code}]),
httpc_response:send(Request#request.from,
- {Request#request.id, stream, BodyPart}),
+ {Request#request.id, stream, BodyPart}),
{<<>>, Request};
%% Stream to file
@@ -177,11 +181,11 @@ stream(BodyPart, #request{stream = Filename} = Request, Code)
when ((Code =:= 200) orelse (Code =:= 206)) andalso is_list(Filename) ->
?hcrt("stream - filename", [{stream, Filename}, {code, Code}]),
case file:open(Filename, [write, raw, append, delayed_write]) of
- {ok, Fd} ->
- ?hcrt("stream - file open ok", [{fd, Fd}]),
- stream(BodyPart, Request#request{stream = Fd}, 200);
- {error, Reason} ->
- exit({stream_to_file_failed, Reason})
+ {ok, Fd} ->
+ ?hcrt("stream - file open ok", [{fd, Fd}]),
+ stream(BodyPart, Request#request{stream = Fd}, 200);
+ {error, Reason} ->
+ exit({stream_to_file_failed, Reason})
end;
%% Stream to file
@@ -189,10 +193,10 @@ stream(BodyPart, #request{stream = Fd} = Request, Code)
when ((Code =:= 200) orelse (Code =:= 206)) ->
?hcrt("stream to file", [{stream, Fd}, {code, Code}]),
case file:write(Fd, BodyPart) of
- ok ->
- {<<>>, Request};
- {error, Reason} ->
- exit({stream_to_file_failed, Reason})
+ ok ->
+ {<<>>, Request};
+ {error, Reason} ->
+ exit({stream_to_file_failed, Reason})
end;
stream(BodyPart, Request,_) -> % only 200 and 206 responses can be streamed
@@ -208,7 +212,7 @@ stream(BodyPart, Request,_) -> % only 200 and 206 responses can be streamed
%% Function: init([Options, ProfileName]) -> {ok, State} |
%% {ok, State, Timeout} | ignore | {stop, Reason}
%%
-%% Options = #options{}
+%% Options = #options{}
%% ProfileName = atom() - id of httpc manager process
%%
%% Description: Initiates the httpc_handler process
@@ -224,20 +228,19 @@ init([Parent, Request, Options, ProfileName]) ->
%% Do not let initial tcp-connection block the manager-process
proc_lib:init_ack(Parent, self()),
handle_verbose(Options#options.verbose),
- Address = handle_proxy(Request#request.address, Options#options.proxy),
+ ProxyOptions = handle_proxy_options(Request#request.scheme, Options),
+ Address = handle_proxy(Request#request.address, ProxyOptions),
{ok, State} =
- case {Address /= Request#request.address, Request#request.scheme} of
- {true, https} ->
- Error = https_through_proxy_is_not_currently_supported,
- self() ! {init_error,
- Error, httpc_response:error(Request, Error)},
- {ok, #state{request = Request, options = Options,
- status = ssl_tunnel}};
- {_, _} ->
- connect_and_send_first_request(Address, Request,
- #state{options = Options,
- profile_name = ProfileName})
- end,
+ case {Address /= Request#request.address, Request#request.scheme} of
+ {true, https} ->
+ connect_and_send_upgrade_request(Address, Request,
+ #state{options = Options,
+ profile_name = ProfileName});
+ {_, _} ->
+ connect_and_send_first_request(Address, Request,
+ #state{options = Options,
+ profile_name = ProfileName})
+ end,
gen_server:enter_loop(?MODULE, [], State).
%%--------------------------------------------------------------------
@@ -250,139 +253,139 @@ init([Parent, Request, Options, ProfileName]) ->
%% Description: Handling call messages
%%--------------------------------------------------------------------
handle_call(#request{address = Addr} = Request, _,
- #state{status = Status,
- session = #session{type = pipeline} = Session,
- timers = Timers,
- options = #options{proxy = Proxy} = _Options,
- profile_name = ProfileName} = State)
+ #state{status = Status,
+ session = #session{type = pipeline} = Session,
+ timers = Timers,
+ options = #options{proxy = Proxy} = _Options,
+ profile_name = ProfileName} = State)
when Status =/= undefined ->
?hcrv("new request on a pipeline session",
- [{request, Request},
- {profile, ProfileName},
- {status, Status},
- {timers, Timers}]),
+ [{request, Request},
+ {profile, ProfileName},
+ {status, Status},
+ {timers, Timers}]),
Address = handle_proxy(Addr, Proxy),
case httpc_request:send(Address, Session, Request) of
ok ->
- ?hcrd("request sent", []),
+ ?hcrd("request sent", []),
- %% Activate the request time out for the new request
- NewState =
- activate_request_timeout(State#state{request = Request}),
+ %% Activate the request time out for the new request
+ NewState =
+ activate_request_timeout(State#state{request = Request}),
- ClientClose =
- httpc_request:is_client_closing(Request#request.headers),
+ ClientClose =
+ httpc_request:is_client_closing(Request#request.headers),
case State#state.request of
#request{} -> %% Old request not yet finished
- ?hcrd("old request still not finished", []),
- %% Make sure to use the new value of timers in state
- NewTimers = NewState#state.timers,
+ ?hcrd("old request still not finished", []),
+ %% Make sure to use the new value of timers in state
+ NewTimers = NewState#state.timers,
NewPipeline = queue:in(Request, State#state.pipeline),
- NewSession =
- Session#session{queue_length =
- %% Queue + current
- queue:len(NewPipeline) + 1,
- client_close = ClientClose},
- insert_session(NewSession, ProfileName),
- ?hcrd("session updated", []),
+ NewSession =
+ Session#session{queue_length =
+ %% Queue + current
+ queue:len(NewPipeline) + 1,
+ client_close = ClientClose},
+ insert_session(NewSession, ProfileName),
+ ?hcrd("session updated", []),
{reply, ok, State#state{pipeline = NewPipeline,
- session = NewSession,
- timers = NewTimers}};
- undefined ->
- %% Note: tcp-message receiving has already been
- %% activated by handle_pipeline/2.
- ?hcrd("no current request", []),
- cancel_timer(Timers#timers.queue_timer,
- timeout_queue),
- NewSession =
- Session#session{queue_length = 1,
- client_close = ClientClose},
- httpc_manager:insert_session(NewSession, ProfileName),
- Relaxed =
- (Request#request.settings)#http_options.relaxed,
- MFA = {httpc_response, parse,
- [State#state.max_header_size, Relaxed]},
- NewTimers = Timers#timers{queue_timer = undefined},
- ?hcrd("session created", []),
- {reply, ok, NewState#state{request = Request,
- session = NewSession,
- mfa = MFA,
- timers = NewTimers}}
- end;
- {error, Reason} ->
- ?hcri("failed sending request", [{reason, Reason}]),
- {reply, {pipeline_failed, Reason}, State}
+ session = NewSession,
+ timers = NewTimers}};
+ undefined ->
+ %% Note: tcp-message receiving has already been
+ %% activated by handle_pipeline/2.
+ ?hcrd("no current request", []),
+ cancel_timer(Timers#timers.queue_timer,
+ timeout_queue),
+ NewSession =
+ Session#session{queue_length = 1,
+ client_close = ClientClose},
+ httpc_manager:insert_session(NewSession, ProfileName),
+ Relaxed =
+ (Request#request.settings)#http_options.relaxed,
+ MFA = {httpc_response, parse,
+ [State#state.max_header_size, Relaxed]},
+ NewTimers = Timers#timers{queue_timer = undefined},
+ ?hcrd("session created", []),
+ {reply, ok, NewState#state{request = Request,
+ session = NewSession,
+ mfa = MFA,
+ timers = NewTimers}}
+ end;
+ {error, Reason} ->
+ ?hcri("failed sending request", [{reason, Reason}]),
+ {reply, {pipeline_failed, Reason}, State}
end;
handle_call(#request{address = Addr} = Request, _,
- #state{status = Status,
- session = #session{type = keep_alive} = Session,
- timers = Timers,
- options = #options{proxy = Proxy} = _Options,
- profile_name = ProfileName} = State)
+ #state{status = Status,
+ session = #session{type = keep_alive} = Session,
+ timers = Timers,
+ options = #options{proxy = Proxy} = _Options,
+ profile_name = ProfileName} = State)
when Status =/= undefined ->
?hcrv("new request on a keep-alive session",
- [{request, Request},
- {profile, ProfileName},
- {status, Status}]),
+ [{request, Request},
+ {profile, ProfileName},
+ {status, Status}]),
Address = handle_proxy(Addr, Proxy),
case httpc_request:send(Address, Session, Request) of
- ok ->
+ ok ->
- ?hcrd("request sent", []),
+ ?hcrd("request sent", []),
- %% Activate the request time out for the new request
- NewState =
- activate_request_timeout(State#state{request = Request}),
+ %% Activate the request time out for the new request
+ NewState =
+ activate_request_timeout(State#state{request = Request}),
- ClientClose =
- httpc_request:is_client_closing(Request#request.headers),
+ ClientClose =
+ httpc_request:is_client_closing(Request#request.headers),
- case State#state.request of
- #request{} -> %% Old request not yet finished
- %% Make sure to use the new value of timers in state
- ?hcrd("old request still not finished", []),
- NewTimers = NewState#state.timers,
+ case State#state.request of
+ #request{} -> %% Old request not yet finished
+ %% Make sure to use the new value of timers in state
+ ?hcrd("old request still not finished", []),
+ NewTimers = NewState#state.timers,
NewKeepAlive = queue:in(Request, State#state.keep_alive),
- NewSession =
- Session#session{queue_length =
- %% Queue + current
- queue:len(NewKeepAlive) + 1,
- client_close = ClientClose},
- insert_session(NewSession, ProfileName),
- ?hcrd("session updated", []),
+ NewSession =
+ Session#session{queue_length =
+ %% Queue + current
+ queue:len(NewKeepAlive) + 1,
+ client_close = ClientClose},
+ insert_session(NewSession, ProfileName),
+ ?hcrd("session updated", []),
{reply, ok, State#state{keep_alive = NewKeepAlive,
- session = NewSession,
- timers = NewTimers}};
- undefined ->
- %% Note: tcp-message reciving has already been
- %% activated by handle_pipeline/2.
- ?hcrd("no current request", []),
- cancel_timer(Timers#timers.queue_timer,
- timeout_queue),
- NewSession =
- Session#session{queue_length = 1,
- client_close = ClientClose},
- insert_session(NewSession, ProfileName),
- Relaxed =
- (Request#request.settings)#http_options.relaxed,
- MFA = {httpc_response, parse,
- [State#state.max_header_size, Relaxed]},
- {reply, ok, NewState#state{request = Request,
- session = NewSession,
- mfa = MFA}}
- end;
+ session = NewSession,
+ timers = NewTimers}};
+ undefined ->
+ %% Note: tcp-message reciving has already been
+ %% activated by handle_pipeline/2.
+ ?hcrd("no current request", []),
+ cancel_timer(Timers#timers.queue_timer,
+ timeout_queue),
+ NewSession =
+ Session#session{queue_length = 1,
+ client_close = ClientClose},
+ insert_session(NewSession, ProfileName),
+ Relaxed =
+ (Request#request.settings)#http_options.relaxed,
+ MFA = {httpc_response, parse,
+ [State#state.max_header_size, Relaxed]},
+ {reply, ok, NewState#state{request = Request,
+ session = NewSession,
+ mfa = MFA}}
+ end;
- {error, Reason} ->
- ?hcri("failed sending request", [{reason, Reason}]),
- {reply, {request_failed, Reason}, State}
+ {error, Reason} ->
+ ?hcri("failed sending request", [{reason, Reason}]),
+ {reply, {request_failed, Reason}, State}
end;
@@ -411,25 +414,25 @@ handle_call(info, _, State) ->
%% request as if it was never issued as in this case the request will
%% not have been sent.
handle_cast({cancel, RequestId, From},
- #state{request = #request{id = RequestId} = Request,
- profile_name = ProfileName,
- canceled = Canceled} = State) ->
+ #state{request = #request{id = RequestId} = Request,
+ profile_name = ProfileName,
+ canceled = Canceled} = State) ->
?hcrv("cancel current request", [{request_id, RequestId},
- {profile, ProfileName},
- {canceled, Canceled}]),
+ {profile, ProfileName},
+ {canceled, Canceled}]),
httpc_manager:request_canceled(RequestId, ProfileName, From),
?hcrv("canceled", []),
{stop, normal,
State#state{canceled = [RequestId | Canceled],
- request = Request#request{from = answer_sent}}};
+ request = Request#request{from = answer_sent}}};
handle_cast({cancel, RequestId, From},
- #state{profile_name = ProfileName,
- request = #request{id = CurrId},
- canceled = Canceled} = State) ->
+ #state{profile_name = ProfileName,
+ request = #request{id = CurrId},
+ canceled = Canceled} = State) ->
?hcrv("cancel", [{request_id, RequestId},
- {curr_req_id, CurrId},
- {profile, ProfileName},
- {canceled, Canceled}]),
+ {curr_req_id, CurrId},
+ {profile, ProfileName},
+ {canceled, Canceled}]),
httpc_manager:request_canceled(RequestId, ProfileName, From),
?hcrv("canceled", []),
{noreply, State#state{canceled = [RequestId | Canceled]}};
@@ -446,94 +449,94 @@ handle_cast(stream_next, #state{session = Session} = State) ->
%% Description: Handling all non call/cast messages
%%--------------------------------------------------------------------
handle_info({Proto, _Socket, Data},
- #state{mfa = {Module, Function, Args},
- request = #request{method = Method,
- stream = Stream} = Request,
- session = Session,
- status_line = StatusLine} = State)
+ #state{mfa = {Module, Function, Args},
+ request = #request{method = Method,
+ stream = Stream} = Request,
+ session = Session,
+ status_line = StatusLine} = State)
when (Proto =:= tcp) orelse
(Proto =:= ssl) orelse
(Proto =:= httpc_handler) ->
?hcri("received data", [{proto, Proto},
- {module, Module},
- {function, Function},
- {method, Method},
- {stream, Stream},
- {session, Session},
- {status_line, StatusLine}]),
+ {module, Module},
+ {function, Function},
+ {method, Method},
+ {stream, Stream},
+ {session, Session},
+ {status_line, StatusLine}]),
FinalResult =
- try Module:Function([Data | Args]) of
- {ok, Result} ->
- ?hcrd("data processed - ok", []),
- handle_http_msg(Result, State);
- {_, whole_body, _} when Method =:= head ->
- ?hcrd("data processed - whole body", []),
- handle_response(State#state{body = <<>>});
- {Module, whole_body, [Body, Length]} ->
- ?hcrd("data processed - whole body", [{length, Length}]),
- {_, Code, _} = StatusLine,
- {NewBody, NewRequest} = stream(Body, Request, Code),
- %% When we stream we will not keep the already
- %% streamed data, that would be a waste of memory.
- NewLength =
- case Stream of
- none ->
- Length;
- _ ->
- Length - size(Body)
- end,
-
- NewState = next_body_chunk(State),
- NewMFA = {Module, whole_body, [NewBody, NewLength]},
- {noreply, NewState#state{mfa = NewMFA,
- request = NewRequest}};
- NewMFA ->
- ?hcrd("data processed - new mfa", []),
- activate_once(Session),
- {noreply, State#state{mfa = NewMFA}}
- catch
- exit:_Exit ->
- ?hcrd("data processing exit", [{exit, _Exit}]),
- ClientReason = {could_not_parse_as_http, Data},
- ClientErrMsg = httpc_response:error(Request, ClientReason),
- NewState = answer_request(Request, ClientErrMsg, State),
- {stop, normal, NewState};
- error:_Error ->
- ?hcrd("data processing error", [{error, _Error}]),
- ClientReason = {could_not_parse_as_http, Data},
- ClientErrMsg = httpc_response:error(Request, ClientReason),
- NewState = answer_request(Request, ClientErrMsg, State),
- {stop, normal, NewState}
-
- end,
+ try Module:Function([Data | Args]) of
+ {ok, Result} ->
+ ?hcrd("data processed - ok", []),
+ handle_http_msg(Result, State);
+ {_, whole_body, _} when Method =:= head ->
+ ?hcrd("data processed - whole body", []),
+ handle_response(State#state{body = <<>>});
+ {Module, whole_body, [Body, Length]} ->
+ ?hcrd("data processed - whole body", [{length, Length}]),
+ {_, Code, _} = StatusLine,
+ {NewBody, NewRequest} = stream(Body, Request, Code),
+ %% When we stream we will not keep the already
+ %% streamed data, that would be a waste of memory.
+ NewLength =
+ case Stream of
+ none ->
+ Length;
+ _ ->
+ Length - size(Body)
+ end,
+
+ NewState = next_body_chunk(State),
+ NewMFA = {Module, whole_body, [NewBody, NewLength]},
+ {noreply, NewState#state{mfa = NewMFA,
+ request = NewRequest}};
+ NewMFA ->
+ ?hcrd("data processed - new mfa", []),
+ activate_once(Session),
+ {noreply, State#state{mfa = NewMFA}}
+ catch
+ exit:_Exit ->
+ ?hcrd("data processing exit", [{exit, _Exit}]),
+ ClientReason = {could_not_parse_as_http, Data},
+ ClientErrMsg = httpc_response:error(Request, ClientReason),
+ NewState = answer_request(Request, ClientErrMsg, State),
+ {stop, normal, NewState};
+ error:_Error ->
+ ?hcrd("data processing error", [{error, _Error}]),
+ ClientReason = {could_not_parse_as_http, Data},
+ ClientErrMsg = httpc_response:error(Request, ClientReason),
+ NewState = answer_request(Request, ClientErrMsg, State),
+ {stop, normal, NewState}
+
+ end,
?hcri("data processed", [{final_result, FinalResult}]),
FinalResult;
handle_info({Proto, Socket, Data},
- #state{mfa = MFA,
- request = Request,
- session = Session,
- status = Status,
- status_line = StatusLine,
- profile_name = Profile} = State)
+ #state{mfa = MFA,
+ request = Request,
+ session = Session,
+ status = Status,
+ status_line = StatusLine,
+ profile_name = Profile} = State)
when (Proto =:= tcp) orelse
(Proto =:= ssl) orelse
(Proto =:= httpc_handler) ->
error_logger:warning_msg("Received unexpected ~p data on ~p"
- "~n Data: ~p"
- "~n MFA: ~p"
- "~n Request: ~p"
- "~n Session: ~p"
- "~n Status: ~p"
- "~n StatusLine: ~p"
- "~n Profile: ~p"
- "~n",
- [Proto, Socket, Data, MFA,
- Request, Session, Status, StatusLine, Profile]),
+ "~n Data: ~p"
+ "~n MFA: ~p"
+ "~n Request: ~p"
+ "~n Session: ~p"
+ "~n Status: ~p"
+ "~n StatusLine: ~p"
+ "~n Profile: ~p"
+ "~n",
+ [Proto, Socket, Data, MFA,
+ Request, Session, Status, StatusLine, Profile]),
{noreply, State};
@@ -572,45 +575,45 @@ handle_info({ssl_error, _, _} = Reason, State) ->
%% Internally, to a request handling process, a request timeout is
%% seen as a canceled request.
handle_info({timeout, RequestId},
- #state{request = #request{id = RequestId} = Request,
- canceled = Canceled,
- profile_name = ProfileName} = State) ->
+ #state{request = #request{id = RequestId} = Request,
+ canceled = Canceled,
+ profile_name = ProfileName} = State) ->
?hcri("timeout of current request", [{id, RequestId}]),
httpc_response:send(Request#request.from,
- httpc_response:error(Request, timeout)),
+ httpc_response:error(Request, timeout)),
httpc_manager:request_done(RequestId, ProfileName),
?hcrv("response (timeout) sent - now terminate", []),
{stop, normal,
State#state{request = Request#request{from = answer_sent},
- canceled = [RequestId | Canceled]}};
+ canceled = [RequestId | Canceled]}};
handle_info({timeout, RequestId},
- #state{canceled = Canceled,
- profile_name = ProfileName} = State) ->
+ #state{canceled = Canceled,
+ profile_name = ProfileName} = State) ->
?hcri("timeout", [{id, RequestId}]),
Filter =
- fun(#request{id = Id, from = From} = Request) when Id =:= RequestId ->
- ?hcrv("found request", [{id, Id}, {from, From}]),
- %% Notify the owner
- httpc_response:send(From,
- httpc_response:error(Request, timeout)),
- httpc_manager:request_done(RequestId, ProfileName),
- ?hcrv("response (timeout) sent", []),
- [Request#request{from = answer_sent}];
- (_) ->
- true
- end,
+ fun(#request{id = Id, from = From} = Request) when Id =:= RequestId ->
+ ?hcrv("found request", [{id, Id}, {from, From}]),
+ %% Notify the owner
+ httpc_response:send(From,
+ httpc_response:error(Request, timeout)),
+ httpc_manager:request_done(RequestId, ProfileName),
+ ?hcrv("response (timeout) sent", []),
+ [Request#request{from = answer_sent}];
+ (_) ->
+ true
+ end,
case State#state.status of
- pipeline ->
- ?hcrd("pipeline", []),
- Pipeline = queue:filter(Filter, State#state.pipeline),
- {noreply, State#state{canceled = [RequestId | Canceled],
- pipeline = Pipeline}};
- keep_alive ->
- ?hcrd("keep_alive", []),
- KeepAlive = queue:filter(Filter, State#state.keep_alive),
- {noreply, State#state{canceled = [RequestId | Canceled],
- keep_alive = KeepAlive}}
+ pipeline ->
+ ?hcrd("pipeline", []),
+ Pipeline = queue:filter(Filter, State#state.pipeline),
+ {noreply, State#state{canceled = [RequestId | Canceled],
+ pipeline = Pipeline}};
+ keep_alive ->
+ ?hcrd("keep_alive", []),
+ KeepAlive = queue:filter(Filter, State#state.keep_alive),
+ {noreply, State#state{canceled = [RequestId | Canceled],
+ keep_alive = KeepAlive}}
end;
handle_info(timeout_queue, State = #state{request = undefined}) ->
@@ -619,11 +622,11 @@ handle_info(timeout_queue, State = #state{request = undefined}) ->
%% Timing was such as the pipeline_timout was not canceled!
handle_info(timeout_queue, #state{timers = Timers} = State) ->
{noreply, State#state{timers =
- Timers#timers{queue_timer = undefined}}};
+ Timers#timers{queue_timer = undefined}}};
%% Setting up the connection to the server somehow failed.
handle_info({init_error, Tag, ClientErrMsg},
- State = #state{request = Request}) ->
+ State = #state{request = Request}) ->
?hcrv("init error", [{tag, Tag}, {client_error, ClientErrMsg}]),
NewState = answer_request(Request, ClientErrMsg, State),
{stop, normal, NewState};
@@ -647,21 +650,21 @@ handle_info({'EXIT', _, _}, State) ->
%% Init error there is no socket to be closed.
terminate(normal,
- #state{request = Request,
- session = {send_failed, AReason} = Reason} = State) ->
+ #state{request = Request,
+ session = {send_failed, AReason} = Reason} = State) ->
?hcrd("terminate", [{send_reason, AReason}, {request, Request}]),
maybe_send_answer(Request,
- httpc_response:error(Request, Reason),
- State),
+ httpc_response:error(Request, Reason),
+ State),
ok;
terminate(normal,
- #state{request = Request,
- session = {connect_failed, AReason} = Reason} = State) ->
+ #state{request = Request,
+ session = {connect_failed, AReason} = Reason} = State) ->
?hcrd("terminate", [{connect_reason, AReason}, {request, Request}]),
maybe_send_answer(Request,
- httpc_response:error(Request, Reason),
- State),
+ httpc_response:error(Request, Reason),
+ State),
ok;
terminate(normal, #state{session = undefined}) ->
@@ -670,21 +673,21 @@ terminate(normal, #state{session = undefined}) ->
%% Init error sending, no session information has been setup but
%% there is a socket that needs closing.
terminate(normal,
- #state{session = #session{id = undefined} = Session}) ->
+ #state{session = #session{id = undefined} = Session}) ->
close_socket(Session);
%% Socket closed remotely
terminate(normal,
- #state{session = #session{socket = {remote_close, Socket},
- socket_type = SocketType,
- id = Id},
- profile_name = ProfileName,
- request = Request,
- timers = Timers,
- pipeline = Pipeline,
- keep_alive = KeepAlive} = State) ->
+ #state{session = #session{socket = {remote_close, Socket},
+ socket_type = SocketType,
+ id = Id},
+ profile_name = ProfileName,
+ request = Request,
+ timers = Timers,
+ pipeline = Pipeline,
+ keep_alive = KeepAlive} = State) ->
?hcrt("terminate(normal) - remote close",
- [{id, Id}, {profile, ProfileName}]),
+ [{id, Id}, {profile, ProfileName}]),
%% Clobber session
(catch httpc_manager:delete_session(Id, ProfileName)),
@@ -702,15 +705,15 @@ terminate(normal,
http_transport:close(SocketType, Socket);
terminate(Reason, #state{session = #session{id = Id,
- socket = Socket,
- socket_type = SocketType},
- request = undefined,
- profile_name = ProfileName,
- timers = Timers,
- pipeline = Pipeline,
- keep_alive = KeepAlive} = State) ->
+ socket = Socket,
+ socket_type = SocketType},
+ request = undefined,
+ profile_name = ProfileName,
+ timers = Timers,
+ pipeline = Pipeline,
+ keep_alive = KeepAlive} = State) ->
?hcrt("terminate",
- [{id, Id}, {profile, ProfileName}, {reason, Reason}]),
+ [{id, Id}, {profile, ProfileName}, {reason, Reason}]),
%% Clobber session
(catch httpc_manager:delete_session(Id, ProfileName)),
@@ -728,16 +731,16 @@ terminate(Reason, #state{request = undefined}) ->
terminate(Reason, #state{request = Request} = State) ->
?hcrd("terminate", [{reason, Reason}, {request, Request}]),
NewState = maybe_send_answer(Request,
- httpc_response:error(Request, Reason),
- State),
+ httpc_response:error(Request, Reason),
+ State),
terminate(Reason, NewState#state{request = undefined}).
maybe_retry_queue(Q, State) ->
case queue:is_empty(Q) of
- false ->
- retry_pipeline(queue:to_list(Q), State);
- true ->
- ok
+ false ->
+ retry_pipeline(queue:to_list(Q), State);
+ true ->
+ ok
end.
maybe_send_answer(#request{from = answer_sent}, _Reason, State) ->
@@ -761,44 +764,44 @@ deliver_answer(Request) ->
%%--------------------------------------------------------------------
code_change(_,
- #state{session = OldSession,
- profile_name = ProfileName} = State,
- upgrade_from_pre_5_8_1) ->
+ #state{session = OldSession,
+ profile_name = ProfileName} = State,
+ upgrade_from_pre_5_8_1) ->
case OldSession of
- {session,
- Id, ClientClose, Scheme, Socket, SocketType, QueueLen, Type} ->
- NewSession = #session{id = Id,
- client_close = ClientClose,
- scheme = Scheme,
- socket = Socket,
- socket_type = SocketType,
- queue_length = QueueLen,
- type = Type},
- insert_session(NewSession, ProfileName),
- {ok, State#state{session = NewSession}};
- _ ->
- {ok, State}
+ {session,
+ Id, ClientClose, Scheme, Socket, SocketType, QueueLen, Type} ->
+ NewSession = #session{id = Id,
+ client_close = ClientClose,
+ scheme = Scheme,
+ socket = Socket,
+ socket_type = SocketType,
+ queue_length = QueueLen,
+ type = Type},
+ insert_session(NewSession, ProfileName),
+ {ok, State#state{session = NewSession}};
+ _ ->
+ {ok, State}
end;
code_change(_,
- #state{session = OldSession,
- profile_name = ProfileName} = State,
- downgrade_to_pre_5_8_1) ->
+ #state{session = OldSession,
+ profile_name = ProfileName} = State,
+ downgrade_to_pre_5_8_1) ->
case OldSession of
- #session{id = Id,
- client_close = ClientClose,
- scheme = Scheme,
- socket = Socket,
- socket_type = SocketType,
- queue_length = QueueLen,
- type = Type} ->
- NewSession = {session,
- Id, ClientClose, Scheme, Socket, SocketType,
- QueueLen, Type},
- insert_session(NewSession, ProfileName),
- {ok, State#state{session = NewSession}};
- _ ->
- {ok, State}
+ #session{id = Id,
+ client_close = ClientClose,
+ scheme = Scheme,
+ socket = Socket,
+ socket_type = SocketType,
+ queue_length = QueueLen,
+ type = Type} ->
+ NewSession = {session,
+ Id, ClientClose, Scheme, Socket, SocketType,
+ QueueLen, Type},
+ insert_session(NewSession, ProfileName),
+ {ok, State#state{session = NewSession}};
+ _ ->
+ {ok, State}
end;
code_change(_, State, _) ->
@@ -806,22 +809,22 @@ code_change(_, State, _) ->
%% new_http_options({http_options, TimeOut, AutoRedirect, SslOpts,
-%% Auth, Relaxed}) ->
+%% Auth, Relaxed}) ->
%% {http_options, "HTTP/1.1", TimeOut, AutoRedirect, SslOpts,
%% Auth, Relaxed}.
%% old_http_options({http_options, _, TimeOut, AutoRedirect,
-%% SslOpts, Auth, Relaxed}) ->
+%% SslOpts, Auth, Relaxed}) ->
%% {http_options, TimeOut, AutoRedirect, SslOpts, Auth, Relaxed}.
%% new_queue(Queue, Fun) ->
%% List = queue:to_list(Queue),
%% NewList =
-%% lists:map(fun(Request) ->
-%% Settings =
-%% Fun(Request#request.settings),
-%% Request#request{settings = Settings}
-%% end, List),
+%% lists:map(fun(Request) ->
+%% Settings =
+%% Fun(Request#request.settings),
+%% Request#request{settings = Settings}
+%% end, List),
%% queue:from_list(NewList).
@@ -830,88 +833,121 @@ code_change(_, State, _) ->
%%%--------------------------------------------------------------------
connect(SocketType, ToAddress,
- #options{ipfamily = IpFamily,
- ip = FromAddress,
- port = FromPort,
- socket_opts = Opts0}, Timeout) ->
+ #options{ipfamily = IpFamily,
+ ip = FromAddress,
+ port = FromPort,
+ socket_opts = Opts0}, Timeout) ->
Opts1 =
- case FromPort of
- default ->
- Opts0;
- _ ->
- [{port, FromPort} | Opts0]
- end,
+ case FromPort of
+ default ->
+ Opts0;
+ _ ->
+ [{port, FromPort} | Opts0]
+ end,
Opts2 =
- case FromAddress of
- default ->
- Opts1;
- _ ->
- [{ip, FromAddress} | Opts1]
- end,
+ case FromAddress of
+ default ->
+ Opts1;
+ _ ->
+ [{ip, FromAddress} | Opts1]
+ end,
case IpFamily of
- inet6fb4 ->
- Opts3 = [inet6 | Opts2],
- case http_transport:connect(SocketType, ToAddress, Opts3, Timeout) of
- {error, _Reason} = Error ->
- Opts4 = [inet | Opts2],
- case http_transport:connect(SocketType,
- ToAddress, Opts4, Timeout) of
- {error, _} ->
- %% Reply with the "original" error
- Error;
- OK ->
- OK
- end;
- OK ->
- OK
- end;
- _ ->
- Opts3 = [IpFamily | Opts2],
- http_transport:connect(SocketType, ToAddress, Opts3, Timeout)
+ inet6fb4 ->
+ Opts3 = [inet6 | Opts2],
+ case http_transport:connect(SocketType,
+ ToAddress, Opts3, Timeout) of
+ {error, Reason6} ->
+ Opts4 = [inet | Opts2],
+ case http_transport:connect(SocketType,
+ ToAddress, Opts4, Timeout) of
+ {error, Reason4} ->
+ {error, {failed_connect,
+ [{to_address, ToAddress},
+ {inet6, Opts3, Reason6},
+ {inet, Opts4, Reason4}]}};
+ OK ->
+ OK
+ end;
+ OK ->
+ OK
+ end;
+ _ ->
+ Opts3 = [IpFamily | Opts2],
+ 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) ->
SocketType = socket_type(Request),
ConnTimeout = (Request#request.settings)#http_options.connect_timeout,
?hcri("connect",
- [{address, Address}, {request, Request}, {options, Options}]),
+ [{address, Address}, {request, Request}, {options, Options}]),
+ case connect(SocketType, Address, Options, ConnTimeout) of
+ {ok, Socket} ->
+ ClientClose =
+ httpc_request:is_client_closing(
+ Request#request.headers),
+ SessionType = httpc_manager:session_type(Options),
+ SocketType = socket_type(Request),
+ Session = #session{id = {Request#request.address, self()},
+ scheme = Request#request.scheme,
+ socket = Socket,
+ socket_type = SocketType,
+ client_close = ClientClose,
+ type = SessionType},
+ ?hcri("connected - now send first request", [{socket, Socket}]),
+
+ case httpc_request:send(Address, Session, Request) of
+ ok ->
+ ?hcri("first request sent", []),
+ TmpState = State#state{request = Request,
+ session = Session,
+ mfa = init_mfa(Request, State),
+ status_line =
+ init_status_line(Request),
+ headers = undefined,
+ body = undefined,
+ status = new},
+ http_transport:setopts(SocketType,
+ Socket, [{active, once}]),
+ NewState = activate_request_timeout(TmpState),
+ {ok, NewState};
+ {error, Reason} ->
+ self() ! {init_error, error_sending,
+ httpc_response:error(Request, Reason)},
+ {ok, State#state{request = Request,
+ session =
+ #session{socket = Socket}}}
+ end;
+ {error, Reason} ->
+ self() ! {init_error, error_connecting,
+ httpc_response:error(Request, Reason)},
+ {ok, State#state{request = Request}}
+ end.
+
+connect_and_send_upgrade_request(Address, Request, #state{options = Options} = State) ->
+ ConnTimeout = (Request#request.settings)#http_options.connect_timeout,
+ SocketType = ip_comm,
case connect(SocketType, Address, Options, ConnTimeout) of
- {ok, Socket} ->
- ClientClose =
- httpc_request:is_client_closing(
- Request#request.headers),
+ {ok, Socket} ->
SessionType = httpc_manager:session_type(Options),
- SocketType = socket_type(Request),
- Session = #session{id = {Request#request.address, self()},
- scheme = Request#request.scheme,
- socket = Socket,
+ Session = #session{socket = Socket,
socket_type = SocketType,
- client_close = ClientClose,
+ id = {Request#request.address, self()},
+ scheme = http,
+ client_close = false,
type = SessionType},
- ?hcri("connected - now send first request", [{socket, Socket}]),
-
- case httpc_request:send(Address, Session, Request) of
- ok ->
- ?hcri("first request sent", []),
- TmpState = State#state{request = Request,
- session = Session,
- mfa = init_mfa(Request, State),
- status_line =
- init_status_line(Request),
- headers = undefined,
- body = undefined,
- status = new},
- http_transport:setopts(SocketType,
- Socket, [{active, once}]),
- NewState = activate_request_timeout(TmpState),
- {ok, NewState};
- {error, Reason} ->
- self() ! {init_error, error_sending,
- httpc_response:error(Request, Reason)},
- {ok, State#state{request = Request,
- session =
- #session{socket = Socket}}}
- end;
+ ErrorHandler =
+ fun(ERequest, EState, EReason) ->
+ self() ! {init_error, error_sending,
+ httpc_response:error(ERequest, EReason)},
+ {ok, EState#state{request = ERequest}} end,
+ tls_tunnel(Address, Request, State#state{session = Session}, ErrorHandler);
{error, Reason} ->
self() ! {init_error, error_connecting,
httpc_response:error(Request, Reason)},
@@ -1015,15 +1051,25 @@ handle_http_msg(Body, #state{status_line = {_,Code, _}} = State) ->
{NewBody, NewRequest} = stream(Body, State#state.request, Code),
handle_response(State#state{body = NewBody, request = NewRequest}).
-handle_http_body(<<>>, State = #state{status_line = {_,304, _}}) ->
+handle_http_body(_, #state{status = {ssl_tunnel, _},
+ status_line = {_,200, _}} = State) ->
+ tls_upgrade(State);
+
+handle_http_body(_, #state{status = {ssl_tunnel, Request},
+ status_line = StatusLine} = State) ->
+ ClientErrMsg = httpc_response:error(Request,{could_no_establish_ssh_tunnel, StatusLine}),
+ NewState = answer_request(Request, ClientErrMsg, State),
+ {stop, normal, NewState};
+
+handle_http_body(<<>>, #state{status_line = {_,304, _}} = State) ->
?hcrt("handle_http_body - 304", []),
handle_response(State#state{body = <<>>});
-handle_http_body(<<>>, State = #state{status_line = {_,204, _}}) ->
+handle_http_body(<<>>, #state{status_line = {_,204, _}} = State) ->
?hcrt("handle_http_body - 204", []),
handle_response(State#state{body = <<>>});
-handle_http_body(<<>>, State = #state{request = #request{method = head}}) ->
+handle_http_body(<<>>, #state{request = #request{method = head}} = State) ->
?hcrt("handle_http_body - head", []),
handle_response(State#state{body = <<>>});
@@ -1110,7 +1156,7 @@ handle_response(#state{request = Request,
{session, Session},
{status_line, StatusLine}]),
- handle_cookies(Headers, Request, Options, ProfileName),
+ handle_cookies(Headers, Request, Options, httpc_manager), %% FOO profile_name
case httpc_response:result({StatusLine, Headers, Body}, Request) of
%% 100-continue
continue ->
@@ -1494,6 +1540,12 @@ retry_pipeline([Request | PipeLine],
end,
retry_pipeline(PipeLine, NewState).
+handle_proxy_options(https, #options{https_proxy = {HttpsProxy, _} = HttpsProxyOpt}) when
+ HttpsProxy =/= undefined ->
+ HttpsProxyOpt;
+handle_proxy_options(_, #options{proxy = Proxy}) ->
+ Proxy.
+
%%% Check to see if the given {Host,Port} tuple is in the NoProxyList
%%% Returns an eventually updated {Host,Port} tuple, with the proxy address
handle_proxy(HostPort = {Host, _Port}, {Proxy, NoProxy}) ->
@@ -1687,6 +1739,96 @@ send_raw(SocketType, Socket, ProcessBody, Acc) ->
end
end.
+tls_tunnel(Address, Request, #state{session = #session{socket = Socket,
+ socket_type = SocketType} = Session} = State,
+ ErrorHandler) ->
+ UpgradeRequest = tls_tunnel_request(Request),
+ case httpc_request:send(Address, Session, UpgradeRequest) of
+ ok ->
+ TmpState = State#state{request = UpgradeRequest,
+ %% session = Session,
+ mfa = init_mfa(UpgradeRequest, State),
+ status_line =
+ init_status_line(UpgradeRequest),
+ headers = undefined,
+ body = undefined},
+ http_transport:setopts(SocketType,
+ Socket, [{active, once}]),
+ NewState = activate_request_timeout(TmpState),
+ {ok, NewState#state{status = {ssl_tunnel, Request}}};
+ {error, Reason} ->
+ ErrorHandler(Request, State, Reason)
+ end.
+
+tls_tunnel_request(#request{headers = Headers,
+ settings = Options,
+ address = {Host, Port}= Adress,
+ ipv6_host_with_brackets = IPV6}) ->
+
+ URI = Host ++":" ++ integer_to_list(Port),
+
+ #request{
+ id = make_ref(),
+ from = self(),
+ scheme = http, %% Use tcp-first and then upgrade!
+ address = Adress,
+ path = URI,
+ pquery = "",
+ method = connect,
+ headers = #http_request_h{host = host_header(Headers, URI),
+ te = "",
+ pragma = "no-cache",
+ other = [{"Proxy-Connection", " Keep-Alive"}]},
+ settings = Options,
+ abs_uri = URI,
+ stream = false,
+ userinfo = "",
+ headers_as_is = [],
+ started = http_util:timestamp(),
+ ipv6_host_with_brackets = IPV6
+ }.
+
+host_header(#http_request_h{host = Host}, _) ->
+ Host;
+
+%% Handles header_as_is
+host_header(_, URI) ->
+ {ok, {_, _, Host, _, _, _}} = http_uri:parse(URI),
+ Host.
+
+tls_upgrade(#state{status =
+ {ssl_tunnel,
+ #request{settings =
+ #http_options{ssl = {_, TLSOptions} = SocketType}} = Request},
+ session = #session{socket = TCPSocket} = Session0,
+ options = Options} = State) ->
+
+ case ssl:connect(TCPSocket, TLSOptions) of
+ {ok, TLSSocket} ->
+ Address = Request#request.address,
+ ClientClose = httpc_request:is_client_closing(Request#request.headers),
+ SessionType = httpc_manager:session_type(Options),
+ Session = Session0#session{
+ scheme = https,
+ socket = TLSSocket,
+ socket_type = SocketType,
+ type = SessionType,
+ client_close = ClientClose},
+ httpc_request:send(Address, Session, Request),
+ http_transport:setopts(SocketType, TLSSocket, [{active, once}]),
+ NewState = State#state{session = Session,
+ request = Request,
+ mfa = init_mfa(Request, State),
+ status_line =
+ init_status_line(Request),
+ headers = undefined,
+ body = undefined,
+ status = new
+ },
+ {noreply, activate_request_timeout(NewState)};
+ {error, _Reason} ->
+ {stop, normal, State#state{request = Request}}
+ end.
%% ---------------------------------------------------------------------
%% Session wrappers
@@ -1704,7 +1846,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_internal.hrl b/lib/inets/src/http_client/httpc_internal.hrl
index 8af752546c..30e2742e9d 100644
--- a/lib/inets/src/http_client/httpc_internal.hrl
+++ b/lib/inets/src/http_client/httpc_internal.hrl
@@ -37,6 +37,7 @@
-define(HTTP_MAX_REDIRECTS, 4).
-define(HTTP_KEEP_ALIVE_TIMEOUT, 120000).
-define(HTTP_KEEP_ALIVE_LENGTH, 5).
+-define(TLS_UPGRADE_TOKEN, "TLS/1.0").
%%% HTTP Client per request settings
-record(http_options,
@@ -72,6 +73,7 @@
-record(options,
{
proxy = {undefined, []}, % {{ProxyHost, ProxyPort}, [NoProxy]},
+ https_proxy = {undefined, []}, % {{ProxyHost, ProxyPort}, [NoProxy]}
%% 0 means persistent connections are used without pipelining
pipeline_timeout = ?HTTP_PIPELINE_TIMEOUT,
max_pipeline_length = ?HTTP_PIPELINE_LENGTH,
diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl
index 453081da21..c45dcab802 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),
@@ -494,6 +577,7 @@ handle_cast({set_options, Options}, State = #state{options = OldOptions}) ->
?hcrv("set options", [{options, Options}, {old_options, OldOptions}]),
NewOptions =
#options{proxy = get_proxy(Options, OldOptions),
+ https_proxy = get_https_proxy(Options, OldOptions),
pipeline_timeout = get_pipeline_timeout(Options, OldOptions),
max_pipeline_length = get_max_pipeline_length(Options, OldOptions),
max_keep_alive_length = get_max_keep_alive_length(Options, OldOptions),
@@ -623,7 +707,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,39 +735,42 @@ 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', _} ->
- %% Why would this crash?
- %% Only if the process has died, but we don't
- %% know about it?
- [];
- Else ->
- Else
- end} ||
- {Pid, State} <- Handlers2],
- Handlers3.
+ Pattern = {'$2', '$1', '_'},
+ Handlers1 = [{Pid, Id} || [Pid, Id] <- ets:match(Tab, Pattern)],
+ Handlers2 = sort_handlers(Handlers1),
+ [{Pid, Reqs, httpc_handler:info(Pid)} || {Pid, Reqs} <- Handlers2].
handle_request(#request{settings =
#http_options{version = "HTTP/0.9"}} = Request,
@@ -736,19 +823,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 +894,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 +963,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,9 +987,39 @@ cast(ProfileName, Msg) ->
gen_server:cast(ProfileName, Msg).
+get_option(proxy, #options{proxy = Proxy}) ->
+ Proxy;
+get_option(https_proxy, #options{https_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).
+get_https_proxy(Opts, #options{https_proxy = Default}) ->
+ proplists:get_value(https_proxy, Opts, Default).
+
get_pipeline_timeout(Opts, #options{pipeline_timeout = Default}) ->
proplists:get_value(pipeline_timeout, 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..51167b34fa 100644
--- a/lib/inets/src/http_lib/Makefile
+++ b/lib/inets/src/http_lib/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
@@ -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..747118431e 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,71 @@ 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]))
+ end.
+
+otp_release() ->
+ erlang:system_info(otp_release).
+
+
%% Phase 3: Remove
remove_all(ConfigDB) ->
Modules = httpd_util:lookup(ConfigDB,modules,[]),
@@ -1159,6 +1255,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_log.erl b/lib/inets/src/http_server/httpd_log.erl
index 60ab326a20..a34435e0e8 100644
--- a/lib/inets/src/http_server/httpd_log.erl
+++ b/lib/inets/src/http_server/httpd_log.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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
@@ -36,8 +36,8 @@
AuthUser :: string(),
Date :: string(),
StatusCode :: pos_integer(),
- Size :: pos_integer() | string()) ->
- {Log :: atom() | pid(), Entry :: string()}.
+ Size :: 0 | pos_integer() | string()) ->
+ {Log :: atom() | pid(), Entry :: string()} | term() .
access_entry(Log, NoLog, Info, RFC931, AuthUser, Date, StatusCode, SizeStr)
when is_list(SizeStr) ->
@@ -69,7 +69,7 @@ access_entry(Log, NoLog,
Info :: #mod{},
Date :: string(),
Reason :: term()) ->
- {Log :: atom() | pid(), Entry :: string()}.
+ {Log :: atom() | pid(), Entry :: string()} | term().
error_entry(Log, NoLog,
#mod{config_db = ConfigDB,
@@ -87,7 +87,7 @@ error_entry(Log, NoLog,
ConfigDB :: term(),
Date :: string(),
ErrroStr :: string()) ->
- {Log :: atom() | pid(), Entry :: string()}.
+ {Log :: atom() | pid(), Entry :: string()} | term().
error_report_entry(Log, NoLog, ConfigDb, Date, ErrorStr) ->
MakeEntry = fun() -> io_lib:format("[~s], ~s~n", [Date, ErrorStr]) end,
@@ -99,7 +99,7 @@ error_report_entry(Log, NoLog, ConfigDb, Date, ErrorStr) ->
ConfigDB :: term(),
Date :: string(),
Reason :: term()) ->
- {Log :: atom() | pid(), Entry :: string()}.
+ {Log :: atom() | pid(), Entry :: string()} | term().
security_entry(Log, NoLog, #mod{config_db = ConfigDB}, Date, Reason) ->
MakeEntry = fun() -> io_lib:format("[~s] ~s~n", [Date, Reason]) end,
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..7d68145287 100644
--- a/lib/inets/src/inets_app/Makefile
+++ b/lib/inets/src/inets_app/Makefile
@@ -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
@@ -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..ed8082534f 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]).
@@ -274,13 +274,8 @@ sys_info() ->
os_info() ->
V = os:version(),
- case os:type() of
- {OsFam, OsName} ->
- [{fam, OsFam}, {name, OsName}, {ver, V}];
- OsFam ->
- [{fam, OsFam}, {ver, V}]
- end.
-
+ {OsFam, OsName} = os:type(),
+ [{fam, OsFam}, {name, OsName}, {ver, V}].
print_mods_info(Versions) ->
case key1search(mod_info, Versions) of
@@ -409,47 +404,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 +414,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 +427,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 +444,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..b368b12462 100644
--- a/lib/inets/src/tftp/Makefile
+++ b/lib/inets/src/tftp/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
@@ -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").