aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/doc/src/erlc.xml10
-rw-r--r--erts/emulator/beam/erl_bif_re.c13
-rw-r--r--erts/etc/common/erlc.c13
-rw-r--r--erts/test/erlc_SUITE.erl17
-rw-r--r--lib/compiler/doc/src/compile.xml12
-rw-r--r--lib/compiler/src/compile.erl63
-rw-r--r--lib/compiler/test/error_SUITE.erl30
-rw-r--r--lib/inets/doc/src/httpc.xml60
-rw-r--r--lib/inets/doc/src/notes.xml10
-rw-r--r--lib/inets/src/http_client/httpc.erl115
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl271
-rw-r--r--lib/inets/src/http_client/httpc_internal.hrl34
-rw-r--r--lib/inets/src/http_client/httpc_manager.erl118
-rw-r--r--lib/inets/src/http_client/httpc_request.erl42
-rw-r--r--lib/inets/src/http_lib/http_transport.erl136
-rw-r--r--lib/inets/test/httpc_SUITE.erl134
-rw-r--r--lib/inets/vsn.mk3
-rw-r--r--lib/public_key/doc/src/Makefile13
-rw-r--r--lib/public_key/test/Makefile10
-rw-r--r--lib/public_key/test/public_key_SUITE.erl10
-rw-r--r--lib/ssl/doc/src/Makefile13
-rw-r--r--lib/ssl/test/ssl_packet_SUITE.erl12
-rw-r--r--lib/stdlib/src/edlin.erl36
-rw-r--r--lib/stdlib/src/edlin_expand.erl49
-rw-r--r--lib/stdlib/test/ExpandTestCaps.erl32
-rw-r--r--lib/stdlib/test/ExpandTestCaps1.erl44
-rw-r--r--lib/stdlib/test/Makefile5
-rw-r--r--lib/stdlib/test/edlin_expand_SUITE.erl156
-rw-r--r--lib/stdlib/test/expand_test.erl32
-rw-r--r--lib/stdlib/test/expand_test1.erl44
-rw-r--r--lib/wx/test/wx_class_SUITE.erl26
-rw-r--r--lib/wx/test/wx_xtra_SUITE.erl7
-rw-r--r--lib/wx/test/wxt.erl18
-rw-r--r--lib/xmerl/doc/src/Makefile12
34 files changed, 1261 insertions, 339 deletions
diff --git a/erts/doc/src/erlc.xml b/erts/doc/src/erlc.xml
index 3859ac8365..1e8960c22c 100644
--- a/erts/doc/src/erlc.xml
+++ b/erts/doc/src/erlc.xml
@@ -4,7 +4,7 @@
<comref>
<header>
<copyright>
- <year>1997</year><year>2009</year>
+ <year>1997</year><year>2010</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -13,12 +13,12 @@
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.
-
+
</legalnotice>
<title>erlc</title>
@@ -104,6 +104,10 @@
must be quoted. Terms which contain spaces
must be quoted on all platforms.</p>
</item>
+ <tag>-W<em>error</em></tag>
+ <item>
+ <p>Makes all warnings into errors.</p>
+ </item>
<tag>-W<em>number</em></tag>
<item>
<p>Sets warning level to <em>number</em>. Default is <c><![CDATA[1]]></c>.
diff --git a/erts/emulator/beam/erl_bif_re.c b/erts/emulator/beam/erl_bif_re.c
index 16abab65b0..6efc19597b 100644
--- a/erts/emulator/beam/erl_bif_re.c
+++ b/erts/emulator/beam/erl_bif_re.c
@@ -1,19 +1,19 @@
/*
* %CopyrightBegin%
- *
- * Copyright Ericsson AB 2008-2009. All Rights Reserved.
- *
+ *
+ * Copyright Ericsson AB 2008-2010. All Rights Reserved.
+ *
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
* compliance with the License. You should have received a copy of the
* Erlang Public License along with this software. If not, it can be
* retrieved online at http://www.erlang.org/.
- *
+ *
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
- *
+ *
* %CopyrightEnd%
*/
@@ -1020,6 +1020,9 @@ re_run_3(BIF_ALIST_3)
goto handle_iolist;
}
pb = (ProcBin *) bptr;
+ if (pb->flags) {
+ erts_emasculate_writable_binary(pb);
+ }
restart.subject = (char *) (pb->bytes+offset);
restart.flags |= RESTART_FLAG_SUBJECT_IN_BINARY;
} else {
diff --git a/erts/etc/common/erlc.c b/erts/etc/common/erlc.c
index c958fed741..09aca19e6c 100644
--- a/erts/etc/common/erlc.c
+++ b/erts/etc/common/erlc.c
@@ -1,19 +1,19 @@
/*
* %CopyrightBegin%
- *
- * Copyright Ericsson AB 1997-2009. All Rights Reserved.
- *
+ *
+ * Copyright Ericsson AB 1997-2010. All Rights Reserved.
+ *
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
* compliance with the License. You should have received a copy of the
* Erlang Public License along with this software. If not, it can be
* retrieved online at http://www.erlang.org/.
- *
+ *
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
- *
+ *
* %CopyrightEnd%
*/
/*
@@ -310,6 +310,8 @@ main(int argc, char** argv)
case 'W': /* Enable warnings. */
if (strcmp(argv[1]+2, "all") == 0) {
PUSH2("@warn", "999");
+ } else if (strcmp(argv[1]+2, "error") == 0) {
+ PUSH2("@option", "warnings_as_errors");
} else if (isdigit((int)argv[1][2])) {
PUSH2("@warn", argv[1]+2);
} else {
@@ -566,6 +568,7 @@ usage(void)
{"-pz path", "add path to the end of Erlang's code path"},
{"-smp", "compile using SMP emulator"},
{"-v", "verbose compiler output"},
+ {"-Werror", "make all warnings into errors"},
{"-W0", "disable warnings"},
{"-Wnumber", "set warning level to number"},
{"-Wall", "enable all warnings"},
diff --git a/erts/test/erlc_SUITE.erl b/erts/test/erlc_SUITE.erl
index 1d944811aa..6b4484b31e 100644
--- a/erts/test/erlc_SUITE.erl
+++ b/erts/test/erlc_SUITE.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(erlc_SUITE).
@@ -56,6 +56,13 @@ compile_erl(Config) when is_list(Config) ->
?line run(Config, Cmd, FileName, "-W0", ["_OK_"]),
+ %% Try treating warnings as errors.
+
+ ?line run(Config, Cmd, FileName, "-Werror",
+ ["compile: warnings being treated as errors\$",
+ "Warning: function foo/0 is unused\$",
+ "_ERROR_"]),
+
%% Check a bad file.
?line BadFile = filename:join(SrcDir, "erl_test_bad.erl"),
diff --git a/lib/compiler/doc/src/compile.xml b/lib/compiler/doc/src/compile.xml
index c39c9b25eb..daa686bc56 100644
--- a/lib/compiler/doc/src/compile.xml
+++ b/lib/compiler/doc/src/compile.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2009</year>
+ <year>1996</year><year>2010</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -13,12 +13,12 @@
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.
-
+
</legalnotice>
<title>compile</title>
@@ -212,6 +212,12 @@
success.</p>
</item>
+ <tag><c>warnings_as_errors</c></tag>
+ <item>
+ <p>Causes warnings to be treated as errors. This option is supported
+ since R13B04.</p>
+ </item>
+
<tag><c>return</c></tag>
<item>
<p>This is a short form for both <c>return_errors</c> and
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index e725083a9f..58e147d508 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%% Purpose: Run the Erlang compiler.
@@ -302,7 +302,7 @@ os_process_size() ->
list_to_integer(lib:nonl(Size));
_ ->
0
- end.
+ end.
run_tc({Name,Fun}, St) ->
Before0 = statistics(runtime),
@@ -318,17 +318,30 @@ run_tc({Name,Fun}, St) ->
Val.
comp_ret_ok(#compile{code=Code,warnings=Warn0,module=Mod,options=Opts}=St) ->
- Warn = messages_per_file(Warn0),
- report_warnings(St#compile{warnings = Warn}),
- Ret1 = case member(binary, Opts) andalso not member(no_code_generation, Opts) of
- true -> [Code];
- false -> []
- end,
- Ret2 = case member(return_warnings, Opts) of
- true -> Ret1 ++ [Warn];
- false -> Ret1
- end,
- list_to_tuple([ok,Mod|Ret2]).
+ case member(warnings_as_errors, Opts) andalso length(Warn0) > 0 of
+ true ->
+ case member(report_warnings, Opts) of
+ true ->
+ io:format("~p: warnings being treated as errors\n",
+ [?MODULE]);
+ false ->
+ ok
+ end,
+ comp_ret_err(St);
+ false ->
+ Warn = messages_per_file(Warn0),
+ report_warnings(St#compile{warnings = Warn}),
+ Ret1 = case member(binary, Opts) andalso
+ not member(no_code_generation, Opts) of
+ true -> [Code];
+ false -> []
+ end,
+ Ret2 = case member(return_warnings, Opts) of
+ true -> Ret1 ++ [Warn];
+ false -> Ret1
+ end,
+ list_to_tuple([ok,Mod|Ret2])
+ end.
comp_ret_err(#compile{warnings=Warn0,errors=Err0,options=Opts}=St) ->
Warn = messages_per_file(Warn0),
@@ -344,18 +357,18 @@ comp_ret_err(#compile{warnings=Warn0,errors=Err0,options=Opts}=St) ->
messages_per_file(Ms) ->
T = lists:sort([{File,M} || {File,Messages} <- Ms, M <- Messages]),
PrioMs = [erl_scan, epp, erl_parse],
- {Prio0, Rest} =
+ {Prio0, Rest} =
lists:mapfoldl(fun(M, A) ->
lists:partition(fun({_,{_,Mod,_}}) -> Mod =:= M;
(_) -> false
end, A)
end, T, PrioMs),
- Prio = lists:sort(fun({_,{L1,_,_}}, {_,{L2,_,_}}) -> L1 =< L2 end,
+ Prio = lists:sort(fun({_,{L1,_,_}}, {_,{L2,_,_}}) -> L1 =< L2 end,
lists:append(Prio0)),
flatmap(fun mpf/1, [Prio, Rest]).
mpf(Ms) ->
- [{File,[M || {F,M} <- Ms, F =:= File]} ||
+ [{File,[M || {F,M} <- Ms, F =:= File]} ||
File <- lists:usort([F || {F,_} <- Ms])].
%% passes(form|file, [Option]) -> [{Name,PassFun}]
@@ -495,14 +508,14 @@ select_passes([List|Ps], Opts) when is_list(List) ->
select_cond(Flag, ShouldBe, Pass, Ps, Opts) ->
ShouldNotBe = not ShouldBe,
- case member(Flag, Opts) of
+ case member(Flag, Opts) of
ShouldBe -> select_passes([Pass|Ps], Opts);
ShouldNotBe -> select_passes(Ps, Opts)
end.
%% select_list_passes([Pass], Opts) -> {done,[Pass]} | {not_done,[Pass]}
%% Evaluate all conditions having to do with listings in the list of
-%% passes.
+%% passes.
select_list_passes(Ps, Opts) ->
select_list_passes_1(Ps, Opts, []).
@@ -782,7 +795,7 @@ clean_parse_transforms_1([F|Fs], Acc) ->
clean_parse_transforms_1(Fs, [F|Acc]);
clean_parse_transforms_1([], Acc) -> reverse(Acc).
-transforms(Os) -> [ M || {parse_transform,M} <- Os ].
+transforms(Os) -> [ M || {parse_transform,M} <- Os ].
transform_module(#compile{options=Opt,code=Code0}=St0) ->
%% Extract compile options from code into options field.
@@ -815,7 +828,7 @@ foldl_transform(St, [T|Ts]) ->
end;
foldl_transform(St, []) -> {ok,St}.
-get_core_transforms(Opts) -> [M || {core_transform,M} <- Opts].
+get_core_transforms(Opts) -> [M || {core_transform,M} <- Opts].
core_transforms(St) ->
%% The options field holds the complete list of options at this
@@ -1264,7 +1277,7 @@ listing(Ext, St) ->
listing(LFun, Ext, St) ->
Lfile = outfile(St#compile.base, Ext, St#compile.options),
case file:open(Lfile, [write,delayed_write]) of
- {ok,Lf} ->
+ {ok,Lf} ->
Code = restore_expanded_types(Ext, St#compile.code),
LFun(Lf, Code),
ok = file:close(Lf),
diff --git a/lib/compiler/test/error_SUITE.erl b/lib/compiler/test/error_SUITE.erl
index 477730c3ac..cdd2434b25 100644
--- a/lib/compiler/test/error_SUITE.erl
+++ b/lib/compiler/test/error_SUITE.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1998-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(error_SUITE).
@@ -21,11 +21,11 @@
-include("test_server.hrl").
-export([all/1,
- head_mismatch_line/1,r11b_binaries/1]).
+ head_mismatch_line/1,r11b_binaries/1,warnings_as_errors/1]).
all(suite) ->
test_lib:recompile(?MODULE),
- [head_mismatch_line,r11b_binaries].
+ [head_mismatch_line,r11b_binaries,warnings_as_errors].
%% Tests that a head mismatch is reported on the correct line (OTP-2125).
head_mismatch_line(Config) when is_list(Config) ->
@@ -73,6 +73,20 @@ r11b_binaries(Config) when is_list(Config) ->
?line [] = run(Config, Ts),
ok.
+warnings_as_errors(Config) when is_list(Config) ->
+ Ts = [{warnings_as_errors,
+ <<"
+ t() ->
+ A = unused,
+ ok.
+ ">>,
+ [warnings_as_errors],
+ {error,
+ [],
+ [{3,erl_lint,{unused_var,'A'}}]} }],
+ ?line [] = run(Config, Ts),
+ ok.
+
run(Config, Tests) ->
F = fun({N,P,Ws,E}, BadL) ->
@@ -104,6 +118,8 @@ run_test(Conf, Test0, Warnings) ->
%% Test result of compilation.
?line Res = case compile:file(File, Opts) of
{error,[{_File,Es}],Ws} ->
+ {error,Es,Ws};
+ {error,Es,[{_File,Ws}]} ->
{error,Es,Ws}
end,
file:delete(File),
diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml
index 680473cc38..e143ba2c1a 100644
--- a/lib/inets/doc/src/httpc.xml
+++ b/lib/inets/doc/src/httpc.xml
@@ -21,7 +21,7 @@
</legalnotice>
- <title>http</title>
+ <title>httpc</title>
<prepared>Ingela Anderton Andin</prepared>
<responsible></responsible>
<docno></docno>
@@ -64,6 +64,8 @@ request_id() = ref()
profile() = atom()
path() = string() representing a file path or directory path
ip_address() = See inet(3)
+socket_opt() = See the Options used by gen_tcp(3) and
+ ssl(3) connect(s)
]]></code>
</section>
@@ -162,13 +164,13 @@ ssl_options() = {verify, code()} |
<v>Request = request()</v>
<v>HTTPOptions = http_options()</v>
<v>http_options() = [http_option()]</v>
- <v>http_option() = {timeout, timeout()} |
+ <v>http_option() = {timeout, timeout()} |
{connect_timeout, timeout()} |
- {ssl, ssl_options()} |
- {autoredirect, boolean()} |
+ {ssl, ssl_options()} |
+ {autoredirect, boolean()} |
{proxy_auth, {userstring(), passwordstring()}} |
- {version, http_version()} |
- {relaxed, boolean()}</v>
+ {version, http_version()} |
+ {relaxed, boolean()}</v>
<v>timeout() = integer() >= 0 | infinity</v>
<v>Options = options()</v>
<v>options() = [option()]</v>
@@ -177,8 +179,10 @@ ssl_options() = {verify, code()} |
{body_format, body_format()} |
{full_result, boolean()} |
{headers_as_is, boolean() |
+ {socket_opts, socket_opts()} |
{receiver, receiver()}}</v>
<v>stream_to() = none | self | {self, once} | filename() </v>
+ <v>socket_opts() = [socket_opt()]</v>
<v>receiver() = pid() | function()/1 | {Module, Function, Args} </v>
<v>Module = atom() </v>
<v>Function = atom() </v>
@@ -315,6 +319,24 @@ ssl_options() = {verify, code()} |
<p>Defaults to <c>false</c>. </p>
</item>
+ <tag><c><![CDATA[socket_opts]]></c></tag>
+ <item>
+ <p>Socket options to be used for this and subsequent
+ request(s). </p>
+ <p>Overrides any value set by the
+ <seealso marker="set_options">set_options</seealso>
+ function. </p>
+ <p>Note that the validity of the options are <em>not</em>
+ checked in any way. </p>
+ <p>Note that this may change the socket behaviour
+ (see <seealso marker="inet#setopts">inet:setopts/2</seealso>)
+ for an already existing, and therefor already connected
+ request handler. </p>
+ <p>By defaults the socket options set by the
+ <seealso marker="#set_options">set_options/1,2</seealso>
+ function is used when establishing connection. </p>
+ </item>
+
<tag><c><![CDATA[receiver]]></c></tag>
<item>
<p>Defines how the client will deliver the result for a
@@ -393,17 +415,30 @@ apply(Module, Function, [ReplyInfo | Args])
<fsummary>Sets options to be used for subsequent requests.</fsummary>
<type>
<v>Options = [Option]</v>
- <v>Option = {proxy, {Proxy, NoProxy}} | {max_sessions, MaxSessions} |
- {max_keep_alive_length, MaxKeepAlive} | {keep_alive_timeout, KeepAliveTimeout} |
- {max_pipeline_length, MaxPipeline} | {pipeline_timeout, PipelineTimeout} |
- {cookies | CookieMode} |
- {ipfamily, IpFamily} | {ip, IpAddress} | {port, Port} |
- {verbose, VerboseMode} </v>
+ <v>Option = {proxy, {Proxy, NoProxy}} |
+ {max_sessions, MaxSessions} |
+ {max_keep_alive_length, MaxKeepAlive} |
+ {keep_alive_timeout, KeepAliveTimeout} |
+ {max_pipeline_length, MaxPipeline} |
+ {pipeline_timeout, PipelineTimeout} |
+ {cookies, CookieMode} |
+ {ipfamily, IpFamily} |
+ {ip, IpAddress} |
+ {port, Port} |
+ {socket_opts, socket_opts()} |
+ {verbose, VerboseMode} </v>
<v>Proxy = {Hostname, Port}</v>
<v>Hostname = string() </v>
<d>ex: "localhost" or "foo.bar.se"</d>
<v>Port = integer()</v>
<d>ex: 8080 </d>
+ <v>socket_opts() = [socket_opt()]</v>
+ <d>The options are appended to the socket options used by the
+ client. </d>
+ <d>These are the default values when a new request handler
+ is started (for the initial connect). They are passed directly
+ to the underlying transport (gen_tcp or ssl) <em>without</em>
+ verification! </d>
<v>NoProxy = [NoProxyDesc]</v>
<v>NoProxyDesc = DomainDesc | HostName | IPDesc</v>
<v>DomainDesc = "*.Domain"</v>
@@ -573,6 +608,7 @@ apply(Module, Function, [ReplyInfo | Args])
<section>
<title>SEE ALSO</title>
<p>RFC 2616, <seealso marker="inets">inets(3)</seealso>,
+ <seealso marker="kernel:gen_tcp">gen_tcp(3)</seealso>,
<seealso marker="ssl:ssl">ssl(3)</seealso>
</p>
</section>
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index ed83708940..e95c8d6e97 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -41,6 +41,16 @@
<list>
<item>
+ <p>[httpc] - Allow users to pass socket options to the transport
+ module when making requests. </p>
+ <p>See the <c>socket_opts</c> option in the
+ <seealso marker="httpc#request2">request/4</seealso> or
+ <seealso marker="httpc#set_options">set_options/1,2</seealso>
+ for more info, </p>
+ <p>Own Id: OTP-8352</p>
+ </item>
+
+ <item>
<p>[httpc] Fix bug crafting Host header when port is not 80. </p>
<p>The host header should include the port number as well as the
host name when making a request to a server listening on a port
diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl
index c4ee4f1fda..5205605e0a 100644
--- a/lib/inets/src/http_client/httpc.erl
+++ b/lib/inets/src/http_client/httpc.erl
@@ -28,7 +28,8 @@
-behaviour(inets_service).
%% API
--export([request/1, request/2, request/4, request/5,
+-export([
+ request/1, request/2, request/4, request/5,
cancel_request/1, cancel_request/2,
set_option/2, set_option/3,
set_options/1, set_options/2,
@@ -38,7 +39,9 @@
reset_cookies/0, reset_cookies/1,
stream_next/1,
default_profile/0,
- profile_name/1, profile_name/2]).
+ profile_name/1, profile_name/2,
+ info/0, info/1
+ ]).
%% Behavior callbacks
-export([start_standalone/1, start_service/1,
@@ -314,6 +317,27 @@ which_cookies(Profile) ->
%%--------------------------------------------------------------------------
+%% info() -> list()
+%% info(Profile) -> list()
+%%
+%% Description: Debug function, retreive info about the profile
+%%-------------------------------------------------------------------------
+info() ->
+ info(default_profile()).
+
+info(Profile) ->
+ ?hcrt("info", [{profile, Profile}]),
+ try
+ begin
+ httpc_manager:info(profile_name(Profile))
+ end
+ catch
+ exit:{noproc, _} ->
+ {error, {not_started, Profile}}
+ end.
+
+
+%%--------------------------------------------------------------------------
%% reset_cookies() -> void()
%% reset_cookies(Profile) -> void()
%%
@@ -399,35 +423,34 @@ handle_request(Method, Url,
Headers, ContentType, Body,
HTTPOptions0, Options0, Profile) ->
- Started = http_util:timestamp(),
- NewHeaders = [{http_util:to_lower(Key), Val} || {Key, Val} <- Headers],
+ Started = http_util:timestamp(),
+ NewHeaders = [{http_util:to_lower(Key), Val} || {Key, Val} <- Headers],
try
begin
- HTTPOptions = http_options(HTTPOptions0),
- Options = request_options(Options0),
- Sync = proplists:get_value(sync, Options),
- Stream = proplists:get_value(stream, Options),
- HeadersRecord =
- header_record(NewHeaders,
- #http_request_h{},
- header_host(Host, Port),
- HTTPOptions#http_options.version),
- Receiver = proplists:get_value(receiver, Options),
- Request = #request{from = Receiver,
- scheme = Scheme,
- address = {Host,Port},
- path = Path,
- pquery = Query,
- method = Method,
- headers = HeadersRecord,
- content = {ContentType,Body},
- settings = HTTPOptions,
- abs_uri = Url,
- userinfo = UserInfo,
- stream = Stream,
+ HTTPOptions = http_options(HTTPOptions0),
+ Options = request_options(Options0),
+ Sync = proplists:get_value(sync, Options),
+ Stream = proplists:get_value(stream, Options),
+ Host2 = header_host(Host, Port),
+ HeadersRecord = header_record(NewHeaders, Host2, HTTPOptions),
+ Receiver = proplists:get_value(receiver, Options),
+ SocketOpts = proplists:get_value(socket_opts, Options),
+ Request = #request{from = Receiver,
+ scheme = Scheme,
+ address = {Host, Port},
+ path = Path,
+ pquery = Query,
+ method = Method,
+ headers = HeadersRecord,
+ content = {ContentType, Body},
+ settings = HTTPOptions,
+ abs_uri = Url,
+ userinfo = UserInfo,
+ stream = Stream,
headers_as_is = headers_as_is(Headers, Options),
- started = Started},
+ socket_opts = SocketOpts,
+ started = Started},
case httpc_manager:request(Request, profile_name(Profile)) of
{ok, RequestId} ->
handle_answer(RequestId, Sync, Options);
@@ -591,6 +614,7 @@ http_options_default() ->
{connect_timeout, {field, #http_options.timeout}, #http_options.connect_timeout, ConnTimeoutPost}
].
+
request_options_defaults() ->
VerifyBoolean =
fun(Value) when ((Value =:= true) orelse (Value =:= false)) ->
@@ -640,13 +664,23 @@ request_options_defaults() ->
error
end,
+ VerifySocketOpts =
+ fun([]) ->
+ {ok, undefined};
+ (Value) when is_list(Value) ->
+ ok;
+ (_) ->
+ error
+ end,
+
[
- {sync, true, VerifySync},
- {stream, none, VerifyStream},
- {body_format, string, VerifyBodyFormat},
- {full_result, true, VerifyFullResult},
- {headers_as_is, false, VerifyHeaderAsIs},
- {receiver, self(), VerifyReceiver}
+ {sync, true, VerifySync},
+ {stream, none, VerifyStream},
+ {body_format, string, VerifyBodyFormat},
+ {full_result, true, VerifyFullResult},
+ {headers_as_is, false, VerifyHeaderAsIs},
+ {receiver, self(), VerifyReceiver},
+ {socket_opts, undefined, VerifySocketOpts}
].
request_options(Options) ->
@@ -671,6 +705,9 @@ request_options([{Key, DefaultVal, Verify} | Defaults], Options, Acc) ->
ok ->
Options2 = lists:keydelete(Key, 1, Options),
request_options(Defaults, Options2, [{Key, Value} | Acc]);
+ {ok, Value2} ->
+ Options2 = lists:keydelete(Key, 1, Options),
+ request_options(Defaults, Options2, [{Key, Value2} | Acc]);
error ->
Report = io_lib:format("Invalid option ~p:~p ignored ~n",
[Key, Value]),
@@ -756,6 +793,10 @@ validate_options([{port, Value} = Opt| Tail], Acc) ->
validate_port(Value),
validate_options(Tail, [Opt | Acc]);
+validate_options([{socket_opts, Value} = Opt| Tail], Acc) ->
+ validate_socket_opts(Value),
+ validate_options(Tail, [Opt | Acc]);
+
validate_options([{verbose, Value} = Opt| Tail], Acc) ->
validate_verbose(Value),
validate_options(Tail, [Opt | Acc]);
@@ -836,6 +877,11 @@ validate_port(Value) when is_integer(Value) ->
validate_port(BadValue) ->
bad_option(port, BadValue).
+validate_socket_opts(Value) when is_list(Value) ->
+ Value;
+validate_socket_opts(BadValue) ->
+ bad_option(socket_opts, BadValue).
+
validate_verbose(Value)
when ((Value =:= false) orelse
(Value =:= verbose) orelse
@@ -855,6 +901,9 @@ header_host(Host, Port) ->
Host ++ ":" ++ integer_to_list(Port).
+header_record(NewHeaders, Host, #http_options{version = Version}) ->
+ header_record(NewHeaders, #http_request_h{}, Host, Version).
+
header_record([], RequestHeaders, Host, Version) ->
validate_headers(RequestHeaders, Host, Version);
header_record([{"cache-control", Val} | Rest], RequestHeaders, Host, Version) ->
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index 25f9b0777f..fec74932a2 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -28,8 +28,15 @@
%%--------------------------------------------------------------------
%% Internal Application API
--export([start_link/2, connect_and_send/2,
- send/2, cancel/2, stream/3, stream_next/1]).
+-export([
+ start_link/2,
+ connect_and_send/2,
+ send/2,
+ cancel/2,
+ stream/3,
+ stream_next/1,
+ info/1
+ ]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
@@ -131,6 +138,18 @@ stream_next(Pid) ->
%%--------------------------------------------------------------------
+%% Function: info(Pid) -> [{Key, Val}]
+%% Pid = pid() - the pid of the http-request handler process.
+%%
+%% Description:
+%% Returns various information related to this handler
+%% Used for debugging and testing
+%%--------------------------------------------------------------------
+info(Pid) ->
+ call(info, Pid).
+
+
+%%--------------------------------------------------------------------
%% Function: stream(BodyPart, Request, Code) -> _
%% BodyPart = binary()
%% Request = #request{}
@@ -143,21 +162,21 @@ stream_next(Pid) ->
%%--------------------------------------------------------------------
%% Request should not be streamed
stream(BodyPart, Request = #request{stream = none}, _) ->
- ?hcrt("stream - none", [{body_part, BodyPart}]),
+ ?hcrt("stream - none", []),
{BodyPart, Request};
%% Stream to caller
stream(BodyPart, Request = #request{stream = Self}, Code)
when ((Code =:= 200) orelse (Code =:= 206)) andalso
((Self =:= self) orelse (Self =:= {self, once})) ->
- ?hcrt("stream - self", [{stream, Self}, {code, Code}, {body_part, BodyPart}]),
+ ?hcrt("stream - self", [{stream, Self}, {code, Code}]),
httpc_response:send(Request#request.from,
{Request#request.id, stream, BodyPart}),
{<<>>, Request};
stream(BodyPart, Request = #request{stream = Self}, 404)
when (Self =:= self) orelse (Self =:= {self, once}) ->
- ?hcrt("stream - self with 404", [{stream, Self}, {body_part, BodyPart}]),
+ ?hcrt("stream - self with 404", [{stream, Self}]),
httpc_response:send(Request#request.from,
{Request#request.id, stream, BodyPart}),
{<<>>, Request};
@@ -167,7 +186,7 @@ stream(BodyPart, Request = #request{stream = Self}, 404)
%% We keep this for backward compatibillity...
stream(BodyPart, Request = #request{stream = Filename}, Code)
when ((Code =:= 200) orelse (Code =:= 206)) andalso is_list(Filename) ->
- ?hcrt("stream - filename", [{stream, Filename}, {code, Code}, {body_part, BodyPart}]),
+ ?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}]),
@@ -179,7 +198,7 @@ stream(BodyPart, Request = #request{stream = Filename}, Code)
%% Stream to file
stream(BodyPart, Request = #request{stream = Fd}, Code)
when ((Code =:= 200) orelse (Code =:= 206)) ->
- ?hcrt("stream to file", [{stream, Fd}, {code, Code}, {body_part, BodyPart}]),
+ ?hcrt("stream to file", [{stream, Fd}, {code, Code}]),
case file:write(Fd, BodyPart) of
ok ->
{<<>>, Request};
@@ -188,7 +207,7 @@ stream(BodyPart, Request = #request{stream = Fd}, Code)
end;
stream(BodyPart, Request,_) -> % only 200 and 206 responses can be streamed
- ?hcrt("stream - ignore", [{request, Request}, {body_part, BodyPart}]),
+ ?hcrt("stream - ignore", [{request, Request}]),
{BodyPart, Request}.
@@ -260,22 +279,22 @@ handle_call({connect_and_send, #request{address = Address0,
end
end;
-handle_call(Request, _,
+handle_call(#request{address = Addr} = Request, _,
#state{status = Status,
session = #tcp_session{socket = Socket,
type = pipeline} = Session,
timers = Timers,
- options = Options,
+ options = #options{proxy = Proxy} = _Options,
profile_name = ProfileName} = State)
when Status =/= undefined ->
- ?hcrv("new request", [{request, Request},
- {profile, ProfileName},
- {status, Status},
- {session_type, pipeline},
- {timers, Timers}]),
+ ?hcrv("new request on a pipeline session",
+ [{request, Request},
+ {profile, ProfileName},
+ {status, Status},
+ {timers, Timers}]),
- Address = handle_proxy(Request#request.address, Options#options.proxy),
+ Address = handle_proxy(Addr, Proxy),
case httpc_request:send(Address, Request, Socket) of
ok ->
@@ -331,21 +350,21 @@ handle_call(Request, _,
{reply, {pipeline_failed, Reason}, State}
end;
-handle_call(Request, _,
+handle_call(#request{address = Addr} = Request, _,
#state{status = Status,
session = #tcp_session{socket = Socket,
type = keep_alive} = Session,
timers = Timers,
- options = Options,
+ options = #options{proxy = Proxy} = _Options,
profile_name = ProfileName} = State)
when Status =/= undefined ->
- ?hcrv("new request", [{request, Request},
- {profile, ProfileName},
- {status, Status},
- {session_type, keep_alive}]),
+ ?hcrv("new request on a keep-alive session",
+ [{request, Request},
+ {profile, ProfileName},
+ {status, Status}]),
- Address = handle_proxy(Request#request.address, Options#options.proxy),
+ Address = handle_proxy(Addr, Proxy),
case httpc_request:send(Address, Request, Socket) of
ok ->
@@ -396,7 +415,12 @@ handle_call(Request, _,
{error, Reason} ->
?hcri("failed sending request", [{reason, Reason}]),
{reply, {request_failed, Reason}, State}
- end.
+ end;
+
+
+handle_call(info, _, State) ->
+ Info = handler_info(State),
+ {reply, Info, State}.
%%--------------------------------------------------------------------
@@ -441,8 +465,7 @@ handle_cast({cancel, RequestId},
{noreply, State#state{canceled = [RequestId | Canceled]}};
handle_cast(stream_next, #state{session = Session} = State) ->
- http_transport:setopts(socket_type(Session#tcp_session.scheme),
- Session#tcp_session.socket, [{active, once}]),
+ activate_once(Session),
{noreply, State#state{once = once}}.
@@ -453,7 +476,7 @@ 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} = MFA,
+ #state{mfa = {Module, Function, Args},
request = #request{method = Method,
stream = Stream} = Request,
session = Session,
@@ -463,8 +486,8 @@ handle_info({Proto, _Socket, Data},
(Proto =:= httpc_handler) ->
?hcri("received data", [{proto, Proto},
- {data, Data},
- {mfa, MFA},
+ {module, Module},
+ {function, Function},
{method, Method},
{stream, Stream},
{session, Session},
@@ -473,14 +496,13 @@ handle_info({Proto, _Socket, Data},
FinalResult =
try Module:Function([Data | Args]) of
{ok, Result} ->
- ?hcrd("data processed - ok", [{result, 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",
- [{module, Module}, {body, Body}, {length, 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
@@ -498,25 +520,25 @@ handle_info({Proto, _Socket, Data},
{noreply, NewState#state{mfa = NewMFA,
request = NewRequest}};
NewMFA ->
- ?hcrd("data processed", [{new_mfa, NewMFA}]),
- http_transport:setopts(socket_type(Session#tcp_session.scheme),
- Session#tcp_session.socket,
- [{active, once}]),
+ ?hcrd("data processed - new mfa", []),
+ activate_once(Session),
{noreply, State#state{mfa = NewMFA}}
catch
- exit:_ ->
+ 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:_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", [{result, FinalResult}]),
+ ?hcri("data processed", []),
FinalResult;
@@ -667,6 +689,9 @@ terminate(normal,
request = Request,
timers = Timers,
pipeline = Pipeline}) ->
+ ?hcrt("terminate(normal) - remote close",
+ [{id, Id}, {profile, ProfileName}]),
+
%% Clobber session
(catch httpc_manager:delete_session(Id, ProfileName)),
@@ -776,19 +801,22 @@ new_queue(Queue, Fun) ->
end, List),
queue:from_list(NewList).
-%%--------------------------------------------------------------------
+
+%%%--------------------------------------------------------------------
%%% Internal functions
-%%--------------------------------------------------------------------
+%%%--------------------------------------------------------------------
-connect(SocketType, ToAddress, #options{ipfamily = IpFamily,
- ip = FromAddress,
- port = FromPort}, Timeout) ->
+connect(SocketType, ToAddress,
+ #options{ipfamily = IpFamily,
+ ip = FromAddress,
+ port = FromPort,
+ socket_opts = Opts0}, Timeout) ->
Opts1 =
case FromPort of
default ->
- [];
+ Opts0;
_ ->
- [{port, FromPort}]
+ [{port, FromPort} | Opts0]
end,
Opts2 =
case FromAddress of
@@ -814,10 +842,10 @@ connect(SocketType, ToAddress, #options{ipfamily = IpFamily,
end.
connect_and_send_first_request(Address,
- #request{settings = Settings,
- headers = Headers,
- address = OrigAddress,
- scheme = Scheme} = Request,
+ #request{settings = Settings,
+ headers = Headers,
+ address = OrigAddress,
+ scheme = Scheme} = Request,
#state{options = Options} = State) ->
?hcrd("connect",
@@ -841,13 +869,13 @@ connect_and_send_first_request(Address,
client_close = ClientClose,
type = SessionType},
TmpState =
- State#state{request = Request,
- session = Session,
- mfa = init_mfa(Request, State),
+ State#state{request = Request,
+ session = Session,
+ mfa = init_mfa(Request, State),
status_line = init_status_line(Request),
- headers = undefined,
- body = undefined,
- status = new},
+ headers = undefined,
+ body = undefined,
+ status = new},
?hcrt("activate socket", []),
activate_once(Session),
NewState = activate_request_timeout(TmpState),
@@ -867,12 +895,87 @@ connect_and_send_first_request(Address,
{stop, Error, State#state{request = Request}}
end.
+
+handler_info(#state{request = Request,
+ session = Session,
+ status_line = _StatusLine,
+ pipeline = Pipeline,
+ keep_alive = KeepAlive,
+ status = Status,
+ canceled = _Canceled,
+ options = _Options,
+ timers = _Timers} = _State) ->
+
+ ?hcrt("handler info", [{request, Request},
+ {session, Session},
+ {pipeline, Pipeline},
+ {keep_alive, KeepAlive},
+ {status, Status}]),
+
+ %% Info about the current request
+ RequestInfo =
+ case Request of
+ undefined ->
+ [];
+ #request{id = Id,
+ started = ReqStarted} ->
+ [{id, Id}, {started, ReqStarted}]
+ end,
+
+ ?hcrt("handler info", [{request_info, RequestInfo}]),
+
+ %% Info about the current session/socket
+ SessionType = Session#tcp_session.type,
+ QueueLen = case Session#tcp_session.type of
+ pipeline ->
+ queue:len(Pipeline);
+ keep_alive ->
+ queue:len(KeepAlive)
+ end,
+ Socket = Session#tcp_session.socket,
+ Scheme = Session#tcp_session.scheme,
+ SocketType = socket_type(Scheme),
+
+ ?hcrt("handler info", [{session_type, SessionType},
+ {queue_length, QueueLen},
+ {scheme, Scheme},
+ {socket_type, SocketType},
+ {socket, Socket}]),
+
+ SocketOpts = http_transport:getopts(SocketType, Socket),
+ SocketStats = http_transport:getstat(SocketType, Socket),
+
+ Remote = http_transport:peername(SocketType, Socket),
+ Local = http_transport:sockname(SocketType, Socket),
+
+ ?hcrt("handler info", [{remote, Remote},
+ {local, Local},
+ {socket_opts, SocketOpts},
+ {socket_stats, SocketStats}]),
+
+ SocketInfo = [{remote, Remote},
+ {local, Local},
+ {socket_opts, SocketOpts},
+ {socket_stats, SocketStats}],
+
+ SessionInfo =
+ [{type, SessionType},
+ {queue_length, QueueLen},
+ {scheme, Scheme},
+ {socket_info, SocketInfo}],
+
+ [{status, Status},
+ {current_request, RequestInfo},
+ {session, SessionInfo}].
+
+
+
handle_http_msg({Version, StatusCode, ReasonPharse, Headers, Body},
State = #state{request = Request}) ->
- ?hcrt("handle_http_msg", [{body, Body}]),
+ ?hcrt("handle_http_msg", [{headers, Headers}]),
case Headers#http_response_h.'content-type' of
"multipart/byteranges" ++ _Param ->
- exit({not_yet_implemented, multypart_nyteranges});
+ exit({not_yet_implemented, multypart_byteranges});
_ ->
StatusLine = {Version, StatusCode, ReasonPharse},
{ok, NewRequest} = start_stream(StatusLine, Headers, Request),
@@ -883,11 +986,11 @@ handle_http_msg({Version, StatusCode, ReasonPharse, Headers, Body},
end;
handle_http_msg({ChunkedHeaders, Body}, #state{headers = Headers} = State) ->
?hcrt("handle_http_msg",
- [{chunked_headers, ChunkedHeaders}, {body, Body}]),
+ [{chunked_headers, ChunkedHeaders}, {headers, Headers}]),
NewHeaders = http_chunk:handle_headers(Headers, ChunkedHeaders),
handle_response(State#state{headers = NewHeaders, body = Body});
handle_http_msg(Body, #state{status_line = {_,Code, _}} = State) ->
- ?hcrt("handle_http_msg", [{body, Body}, {code, Code}]),
+ ?hcrt("handle_http_msg", [{code, Code}]),
{NewBody, NewRequest} = stream(Body, State#state.request, Code),
handle_response(State#state{body = NewBody, request = NewRequest}).
@@ -903,15 +1006,12 @@ handle_http_body(<<>>, State = #state{request = #request{method = head}}) ->
?hcrt("handle_http_body - head", []),
handle_response(State#state{body = <<>>});
-handle_http_body(Body, State = #state{headers = Headers,
- max_body_size = MaxBodySize,
- status_line = {_,Code, _},
- request = Request}) ->
+handle_http_body(Body, #state{headers = Headers,
+ max_body_size = MaxBodySize,
+ status_line = {_,Code, _},
+ request = Request} = State) ->
?hcrt("handle_http_body",
- [{headers, Headers},
- {body, Body},
- {max_body_size, MaxBodySize},
- {code, Code}]),
+ [{max_body_size, MaxBodySize}, {headers, Headers}, {code, Code}]),
TransferEnc = Headers#http_response_h.'transfer-encoding',
case case_insensitive_header(TransferEnc) of
"chunked" ->
@@ -1000,9 +1100,7 @@ handle_response(#state{request = Request,
Session#tcp_session.socket,
RequestBody),
%% Wait for next response
- http_transport:setopts(socket_type(Session#tcp_session.scheme),
- Session#tcp_session.socket,
- [{active, once}]),
+ activate_once(Session),
Relaxed = (Request#request.settings)#http_options.relaxed,
MFA = {httpc_response, parse,
[State#state.max_header_size, Relaxed]},
@@ -1038,7 +1136,7 @@ handle_response(#state{request = Request,
ok = httpc_manager:retry_request(TimeNewRequest, ProfileName),
handle_queue(State#state{request = undefined}, Data);
{ok, Msg, Data} ->
- ?hcrd("handle response - ok", [{msg, Msg}, {data, Data}]),
+ ?hcrd("handle response - ok", []),
end_stream(StatusLine, Request),
NewState = answer_request(Request, Msg, State),
handle_queue(NewState, Data);
@@ -1137,10 +1235,7 @@ handle_pipeline(#state{status = pipeline,
body = undefined},
case Data of
<<>> ->
- http_transport:setopts(
- socket_type(Session#tcp_session.scheme),
- Session#tcp_session.socket,
- [{active, once}]),
+ activate_once(Session),
{noreply, NewState};
_ ->
%% If we already received some bytes of
@@ -1164,14 +1259,12 @@ handle_keep_alive_queue(
case queue:out(State#state.keep_alive) of
{empty, _} ->
- ?hcrd("epmty keep_alive queue", []),
+ ?hcrd("empty keep_alive queue", []),
%% The server may choose too terminate an idle keep_alive session
%% in this case we want to receive the close message
%% at once and not when trying to send the next
%% request.
- http_transport:setopts(socket_type(Session#tcp_session.scheme),
- Session#tcp_session.socket,
- [{active, once}]),
+ activate_once(Session),
%% If a keep_alive session has been idle for some time is not
%% closed by the server, the client may want to close it.
NewState = activate_queue_timeout(TimeOut, State),
@@ -1276,9 +1369,8 @@ is_keep_alive_enabled_server("HTTP/1.0",
is_keep_alive_enabled_server(_,_) ->
false.
-is_keep_alive_connection(Headers, Session) ->
- (not ((Session#tcp_session.client_close) or
- httpc_response:is_server_closing(Headers))).
+is_keep_alive_connection(Headers, #tcp_session{client_close = ClientClose}) ->
+ (not ((ClientClose) orelse httpc_response:is_server_closing(Headers))).
try_to_enable_pipeline_or_keep_alive(
#state{session = Session,
@@ -1286,8 +1378,12 @@ try_to_enable_pipeline_or_keep_alive(
status_line = {Version, _, _},
headers = Headers,
profile_name = ProfileName} = State) ->
- case (is_keep_alive_enabled_server(Version, Headers) andalso
- is_keep_alive_connection(Headers, Session)) of
+ ?hcrd("try to enable pipeline or keep-alive",
+ [{version, Version},
+ {headers, Headers},
+ {session, Session}]),
+ case is_keep_alive_enabled_server(Version, Headers) andalso
+ is_keep_alive_connection(Headers, Session) of
true ->
case (is_pipeline_enabled_client(Session) andalso
httpc_request:is_idempotent(Method)) of
@@ -1307,7 +1403,7 @@ try_to_enable_pipeline_or_keep_alive(
end.
answer_request(Request, Msg, #state{timers = Timers} = State) ->
- ?hcrt("answer request", [{request, Request}, {msg, Msg}]),
+ ?hcrt("answer request", [{request, Request}]),
httpc_response:send(Request#request.from, Msg),
RequestTimers = Timers#timers.request_timers,
TimerRef =
@@ -1435,7 +1531,7 @@ socket_type(#request{scheme = https, settings = Settings}) ->
socket_type(http) ->
ip_comm;
socket_type(https) ->
- {ssl, []}. %% Dummy value ok for ex setops that does not use this value
+ {ssl, []}. %% Dummy value ok for ex setopts that does not use this value
start_stream({_Version, _Code, _ReasonPhrase}, _Headers,
#request{stream = none} = Request) ->
@@ -1529,6 +1625,7 @@ handle_verbose(trace) ->
handle_verbose(_) ->
ok.
+
%%% Normaly I do not comment out code, I throw it away. But this might
%%% actually be used one day if ssl is improved.
%% send_ssl_tunnel_request(Address, Request = #request{address = {Host, Port}},
diff --git a/lib/inets/src/http_client/httpc_internal.hrl b/lib/inets/src/http_client/httpc_internal.hrl
index 4c5e6ed5d8..4d76c4beb3 100644
--- a/lib/inets/src/http_client/httpc_internal.hrl
+++ b/lib/inets/src/http_client/httpc_internal.hrl
@@ -46,7 +46,7 @@
%% bool() - true if auto redirect on 30x response
autoredirect = true,
- %% Ssl socket options
+ %% ssl socket options
ssl = [],
%% {User, Password} = {string(), string()}
@@ -63,19 +63,20 @@
%%% HTTP Client per profile setting.
-record(options,
{
- proxy = {undefined, []}, % {{ProxyHost, ProxyPort}, [NoProxy]},
- %% 0 means persistent connections are used without pipelining
- pipeline_timeout = ?HTTP_PIPELINE_TIMEOUT,
- max_pipeline_length = ?HTTP_PIPELINE_LENGTH,
- max_keep_alive_length = ?HTTP_KEEP_ALIVE_LENGTH,
- keep_alive_timeout = ?HTTP_KEEP_ALIVE_TIMEOUT, % Used when pipeline_timeout = 0
- max_sessions = ?HTTP_MAX_TCP_SESSIONS,
- cookies = disabled, % enabled | disabled | verify
- verbose = false,
- ipfamily = inet, % inet | inet6 | inet6fb4
- ip = default, % specify local interface
- port = default % specify local port
- }
+ proxy = {undefined, []}, % {{ProxyHost, ProxyPort}, [NoProxy]},
+ %% 0 means persistent connections are used without pipelining
+ pipeline_timeout = ?HTTP_PIPELINE_TIMEOUT,
+ max_pipeline_length = ?HTTP_PIPELINE_LENGTH,
+ max_keep_alive_length = ?HTTP_KEEP_ALIVE_LENGTH,
+ keep_alive_timeout = ?HTTP_KEEP_ALIVE_TIMEOUT, % Used when pipeline_timeout = 0
+ max_sessions = ?HTTP_MAX_TCP_SESSIONS,
+ cookies = disabled, % enabled | disabled | verify
+ verbose = false,
+ ipfamily = inet, % inet | inet6 | inet6fb4
+ ip = default, % specify local interface
+ port = default, % specify local port
+ socket_opts = [] % other socket options
+ }
).
%%% All data associated to a specific HTTP request
@@ -98,7 +99,8 @@
headers_as_is, % Boolean() - workaround for servers that does
% not honor the http standard, can also be used for testing purposes.
started, % integer() > 0 - When we started processing the request
- timer % undefined | ref()
+ timer, % undefined | ref()
+ socket_opts % undefined | [socket_option()]
}
).
@@ -109,7 +111,7 @@
scheme, % http (HTTP/TCP) | https (HTTP/SSL/TCP)
socket, % Open socket, used by connection
queue_length = 1, % Current length of pipeline or keep alive queue
- type % pipeline | keep_alive (wait for response before sending new request)
+ type % pipeline | keep_alive (wait for response before sending new request)
}).
-record(http_cookie,
diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl
index 915f4c024d..f8fc6322ed 100644
--- a/lib/inets/src/http_client/httpc_manager.erl
+++ b/lib/inets/src/http_client/httpc_manager.erl
@@ -38,7 +38,8 @@
store_cookies/3,
which_cookies/1, which_cookies/2,
reset_cookies/1,
- session_type/1
+ session_type/1,
+ info/1
]).
%% gen_server callbacks
@@ -61,7 +62,7 @@
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 | operational
+ state % State of the handler: initiating | operational | canceled
}).
%% Entries in the handler / request cross-ref table
@@ -181,6 +182,7 @@ request_canceled(RequestId, ProfileName) ->
insert_session(Session, ProfileName) ->
SessionDbName = session_db_name(ProfileName),
+ ?hcrt("insert session", [{session, Session}, {profile, ProfileName}]),
ets:insert(SessionDbName, Session).
@@ -196,6 +198,7 @@ insert_session(Session, ProfileName) ->
delete_session(SessionId, ProfileName) ->
SessionDbName = session_db_name(ProfileName),
+ ?hcrt("delete session", [{session_is, SessionId}, {profile, ProfileName}]),
ets:delete(SessionDbName, SessionId).
@@ -263,6 +266,19 @@ which_cookies(Url, ProfileName) ->
%%--------------------------------------------------------------------
+%% Function: info(ProfileName) -> list()
+%%
+%% ProfileName = atom()
+%%
+%% Description: Retrieves various info about the manager and the
+%% handlers it manages
+%%--------------------------------------------------------------------
+
+info(ProfileName) ->
+ call(ProfileName, info).
+
+
+%%--------------------------------------------------------------------
%% Function: session_type(Options) -> ok
%%
%% Options = #options{}
@@ -342,10 +358,8 @@ handle_call({request, Request}, _From, State) ->
{reply, {ok, ReqId}, NewState};
Error ->
- %% This is way too severe
- %% To crash the manager simply because
- %% it failed to properly handle a request
- {stop, Error, httpc_response:error(Request, Error), State}
+ NewError = {error, {failed_process_request, Error}},
+ {reply, NewError, State}
end;
handle_call({cancel_request, RequestId}, From,
@@ -377,17 +391,17 @@ handle_call({cancel_request, RequestId}, From,
end;
-handle_call(reset_cookies, _, #state{cookie_db = CookieDb} = State) ->
+handle_call(reset_cookies, _, #state{cookie_db = CookieDb} = State) ->
?hcrv("reset cookies", []),
httpc_cookie:reset_db(CookieDb),
{reply, ok, State};
-handle_call(which_cookies, _, #state{cookie_db = CookieDb} = State) ->
+handle_call(which_cookies, _, #state{cookie_db = CookieDb} = State) ->
?hcrv("which cookies", []),
CookieHeaders = httpc_cookie:which_cookies(CookieDb),
{reply, CookieHeaders, State};
-handle_call({which_cookies, Url}, _, #state{cookie_db = CookieDb} = State) ->
+handle_call({which_cookies, Url}, _, #state{cookie_db = CookieDb} = State) ->
?hcrv("which cookies", [{url, Url}]),
case http_uri:parse(Url) of
{Scheme, _, Host, Port, Path, _} ->
@@ -398,6 +412,11 @@ handle_call({which_cookies, Url}, _, #state{cookie_db = CookieDb} = State) ->
{reply, Msg, State}
end;
+handle_call(info, _, State) ->
+ ?hcrv("info", []),
+ Info = get_manager_info(State),
+ {reply, Info, State};
+
handle_call(Req, From, #state{profile_name = ProfileName} = State) ->
error_report(ProfileName,
"received unkown request"
@@ -428,17 +447,29 @@ handle_cast({retry_or_redirect_request, {Time, Request}},
{noreply, State}
end;
-handle_cast({retry_or_redirect_request, Request}, State) ->
+handle_cast({retry_or_redirect_request, Request},
+ #state{profile_name = Profile,
+ handler_db = HandlerDb} = State) ->
?hcrv("retry or redirect request", [{request, Request}]),
case (catch handle_request(Request, State)) of
{ok, _, NewState} ->
{noreply, NewState};
Error ->
- %% This is *way* too severe.
- %% To crash the manager simply because
- %% it failed to properly handle *one* request
- {stop, Error, State}
+ ReqId = Request#request.id,
+ error_report(Profile,
+ "failed to retry or redirect request ~p"
+ "~n Error: ~p", [ReqId, Error]),
+ case ets:lookup(HandlerDb, ReqId) of
+ [#handler_info{from = From}] ->
+ Error2 = httpc_response:error(Request, Error),
+ httpc_response:send(From, Error2),
+ ok;
+
+ _ ->
+ ok
+ end,
+ {noreply, State}
end;
handle_cast({request_canceled, RequestId}, State) ->
@@ -468,7 +499,8 @@ handle_cast({set_options, Options}, State = #state{options = OldOptions}) ->
ipfamily = get_ipfamily(Options, OldOptions),
ip = get_ip(Options, OldOptions),
port = get_port(Options, OldOptions),
- verbose = get_verbose(Options, OldOptions)
+ verbose = get_verbose(Options, OldOptions),
+ socket_opts = get_socket_opts(Options, OldOptions)
},
case {OldOptions#options.verbose, NewOptions#options.verbose} of
{Same, Same} ->
@@ -572,6 +604,32 @@ code_change(_OldVsn, State, _Extra) ->
%% Internal functions
%%--------------------------------------------------------------------
+get_manager_info(#state{handler_db = HDB,
+ cookie_db = CDB} = _State) ->
+ HandlerInfo = get_handler_info(HDB),
+ CookieInfo = httpc_cookie:which_cookies(CDB),
+ [{handlers, HandlerInfo}, {cookies, CookieInfo}].
+
+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, httpc_handler:info(Pid)} ||
+ {Pid, State} <- Handlers2],
+ Handlers3.
+
%%
%% The request handler process is started asynchronously by a
@@ -606,7 +664,7 @@ handle_connect_and_send(_StarterPid, ReqId, HandlerPid, Result,
"send request ~p"
"~n Error: ~p", [HandlerPid, ReqId, Result]),
?hcri("received connect-and-send error", [{result, Result}]),
- Reason2 =
+ Reason2 =
case Result of
{error, Reason} ->
{failed_connecting, Reason};
@@ -747,7 +805,10 @@ select_session(Method, HostPort, Scheme, SessionType,
type = SessionType},
%% {'_', {HostPort, '$1'}, false, Scheme, '_', '$2', SessionTyp},
Candidates = ets:match(SessionDb, Pattern),
- ?hcrd("select session", [{candidates, Candidates}]),
+ ?hcrd("select session", [{host_port, HostPort},
+ {scheme, Scheme},
+ {type, SessionType},
+ {candidates, Candidates}]),
select_session(Candidates, MaxKeepAlive, MaxPipe, SessionType);
false ->
no_connection
@@ -776,20 +837,30 @@ pipeline_or_keep_alive(#request{id = Id} = Request, HandlerPid, State) ->
?hcrd("pipeline of keep-alive", [{id, Id}, {handler, HandlerPid}]),
case (catch httpc_handler:send(Request, HandlerPid)) of
ok ->
- ?hcrd("pipeline of keep-alive - successfully sent", []),
+ ?hcrd("pipeline or keep-alive - successfully sent", []),
Entry = #handler_info{id = Id,
handler = HandlerPid,
state = operational},
ets:insert(State#state.handler_db, Entry);
_ -> %% timeout pipelining failed
- ?hcrd("pipeline of keep-alive - failed sending -> "
+ ?hcrd("pipeline or keep-alive - failed sending -> "
"start a new handler", []),
create_handler_starter(Request, State)
end.
-create_handler_starter(#request{id = Id, from = From} = Request,
+create_handler_starter(#request{socket_opts = SocketOpts} = Request,
+ #state{options = Options} = State)
+ when is_list(SocketOpts) ->
+ %% The user provided us with (override) socket options
+ ?hcrt("create handler starter", [{socket_opts, SocketOpts}, {options, Options}]),
+ Options2 = Options#options{socket_opts = SocketOpts},
+ create_handler_starter(Request#request{socket_opts = undefined},
+ State#state{options = Options2});
+
+create_handler_starter(#request{id = Id,
+ from = From} = Request,
#state{profile_name = ProfileName,
options = Options,
handler_db = HandlerDb} = _State) ->
@@ -858,8 +929,8 @@ generate_request_id(Request) ->
RequestId = make_ref(),
Request#request{id = RequestId};
_ ->
- %% This is an automatic redirect or a retryed pipelined
- %% request keep the old id.
+ %% This is an automatic redirect or a retryed pipelined request
+ %% => keep the old id.
Request
end.
@@ -960,6 +1031,9 @@ get_port(Opts, #options{port = Default}) ->
get_verbose(Opts, #options{verbose = Default}) ->
proplists:get_value(verbose, Opts, Default).
+get_socket_opts(Opts, #options{socket_opts = Default}) ->
+ proplists:get_value(socket_opts, Opts, Default).
+
handle_verbose(debug) ->
dbg:p(self(), [call]),
diff --git a/lib/inets/src/http_client/httpc_request.erl b/lib/inets/src/http_client/httpc_request.erl
index f15c5d4381..55e0af4b42 100644
--- a/lib/inets/src/http_client/httpc_request.erl
+++ b/lib/inets/src/http_client/httpc_request.erl
@@ -39,24 +39,37 @@
%%
%% Description: Composes and sends a HTTP-request.
%%-------------------------------------------------------------------------
-send(SendAddr, #request{method = Method,
- scheme = Scheme,
- path = Path,
- pquery = Query,
- headers = Headers,
- content = Content,
- address = Address,
- abs_uri = AbsUri,
- headers_as_is = HeadersAsIs,
- settings = HttpOptions,
- userinfo = UserInfo},
- Socket) ->
+send(SendAddr, #request{scheme = Scheme, socket_opts = SocketOpts} = Request,
+ Socket)
+ when is_list(SocketOpts) ->
+ SocketType = socket_type(Scheme),
+ case http_transport:setopts(SocketType, Socket, SocketOpts) of
+ ok ->
+ send(SendAddr, Socket, SocketType,
+ Request#request{socket_opts = undefined});
+ {error, Reason} ->
+ {error, {setopts_failed, Reason}}
+ end;
+send(SendAddr, #request{scheme = Scheme} = Request, Socket) ->
+ SocketType = socket_type(Scheme),
+ send(SendAddr, Socket, SocketType, Request).
+
+send(SendAddr, Socket, SocketType,
+ #request{method = Method,
+ path = Path,
+ pquery = Query,
+ headers = Headers,
+ content = Content,
+ address = Address,
+ abs_uri = AbsUri,
+ headers_as_is = HeadersAsIs,
+ settings = HttpOptions,
+ userinfo = UserInfo}) ->
?hcrt("send",
[{send_addr, SendAddr},
{socket, Socket},
{method, Method},
- {scheme, Scheme},
{path, Path},
{pquery, Query},
{headers, Headers},
@@ -95,7 +108,8 @@ send(SendAddr, #request{method = Method,
?hcrd("send", [{message, Message}]),
- http_transport:send(socket_type(Scheme), Socket, lists:append(Message)).
+ http_transport:send(SocketType, Socket, lists:append(Message)).
+
%%-------------------------------------------------------------------------
diff --git a/lib/inets/src/http_lib/http_transport.erl b/lib/inets/src/http_lib/http_transport.erl
index 27a950174f..7c2ac626e6 100644
--- a/lib/inets/src/http_lib/http_transport.erl
+++ b/lib/inets/src/http_lib/http_transport.erl
@@ -16,17 +16,33 @@
%%
%% %CopyrightEnd%
%%
-%
+
-module(http_transport).
% Internal application API
--export([start/1, connect/3, connect/4, listen/2, listen/3,
- accept/2, accept/3, close/2,
- send/3, controlling_process/3, setopts/3,
- peername/2, resolve/0]).
+-export([
+ start/1,
+ connect/3, connect/4,
+ listen/2, listen/3,
+ accept/2, accept/3,
+ close/2,
+ send/3,
+ controlling_process/3,
+ setopts/3, getopts/2, getopts/3,
+ getstat/2,
+ peername/2, sockname/2,
+ resolve/0
+ ]).
-export([negotiate/3]).
+-include("inets_internal.hrl").
+-define(SERVICE, httpl).
+-define(hlri(Label, Content), ?report_important(Label, ?SERVICE, Content)).
+-define(hlrv(Label, Content), ?report_verbose(Label, ?SERVICE, Content)).
+-define(hlrd(Label, Content), ?report_debug(Label, ?SERVICE, Content)).
+-define(hlrt(Label, Content), ?report_trace(Label, ?SERVICE, Content)).
+
%%%=========================================================================
%%% Internal application API
@@ -77,14 +93,22 @@ connect(SocketType, Address, Opts) ->
connect(ip_comm = _SocketType, {Host, Port}, Opts0, Timeout)
when is_list(Opts0) ->
Opts = [binary, {packet, 0}, {active, false}, {reuseaddr, true} | Opts0],
+ ?hlrt("connect using gen_tcp",
+ [{host, Host}, {port, Port}, {opts, Opts}, {timeout, Timeout}]),
gen_tcp:connect(Host, Port, Opts, Timeout);
connect({ssl, SslConfig}, {Host, Port}, _, Timeout) ->
Opts = [binary, {active, false}] ++ SslConfig,
+ ?hlrt("connect using ssl",
+ [{host, Host}, {port, Port}, {ssl_config, SslConfig},
+ {timeout, Timeout}]),
ssl:connect(Host, Port, Opts, Timeout);
connect({erl_ssl, SslConfig}, {Host, Port}, _, Timeout) ->
Opts = [binary, {active, false}, {ssl_imp, new}] ++ SslConfig,
+ ?hlrt("connect using erl_ssl",
+ [{host, Host}, {port, Port}, {ssl_config, SslConfig},
+ {timeout, Timeout}]),
ssl:connect(Host, Port, Opts, Timeout).
@@ -209,6 +233,7 @@ accept(ip_comm, ListenSocket, Timeout) ->
accept({ssl,_SSLConfig}, ListenSocket, Timeout) ->
ssl:transport_accept(ListenSocket, Timeout).
+
%%-------------------------------------------------------------------------
%% controlling_process(SocketType, Socket, NewOwner) -> ok | {error, Reason}
%% SocketType = ip_comm | {ssl, _}
@@ -222,6 +247,7 @@ controlling_process(ip_comm, Socket, NewOwner) ->
controlling_process({ssl, _}, Socket, NewOwner) ->
ssl:controlling_process(Socket, NewOwner).
+
%%-------------------------------------------------------------------------
%% setopts(SocketType, Socket, Options) -> ok | {error, Reason}
%% SocketType = ip_comm | {ssl, _}
@@ -231,10 +257,62 @@ controlling_process({ssl, _}, Socket, NewOwner) ->
%% gen_tcp or ssl.
%%-------------------------------------------------------------------------
setopts(ip_comm, Socket, Options) ->
- inet:setopts(Socket,Options);
+ ?hlrt("ip_comm setopts", [{socket, Socket}, {options, Options}]),
+ inet:setopts(Socket, Options);
setopts({ssl, _}, Socket, Options) ->
+ ?hlrt("ssl setopts", [{socket, Socket}, {options, Options}]),
ssl:setopts(Socket, Options).
+
+%%-------------------------------------------------------------------------
+%% getopts(SocketType, Socket [, Opts]) -> ok | {error, Reason}
+%% SocketType = ip_comm | {ssl, _}
+%% Socket = socket()
+%% Opts = socket_options()
+%% Description: Gets the values for some options.
+%%-------------------------------------------------------------------------
+getopts(SocketType, Socket) ->
+ Opts = [packet, packet_size, recbuf, sndbuf, priority, tos, send_timeout],
+ getopts(SocketType, Socket, Opts).
+
+getopts(ip_comm, Socket, Options) ->
+ ?hlrt("ip_comm getopts", [{socket, Socket}, {options, Options}]),
+ case inet:getopts(Socket, Options) of
+ {ok, SocketOpts} ->
+ SocketOpts;
+ {error, _} ->
+ []
+ end;
+getopts({ssl, _}, Socket, Options) ->
+ ?hlrt("ssl getopts", [{socket, Socket}, {options, Options}]),
+ case ssl:getopts(Socket, Options) of
+ {ok, SocketOpts} ->
+ SocketOpts;
+ {error, _} ->
+ []
+ end.
+
+
+%%-------------------------------------------------------------------------
+%% getstat(SocketType, Socket) -> socket_stats()
+%% SocketType = ip_comm | {ssl, _}
+%% Socket = socket()
+%% socket_stats() = list()
+%% Description: Gets the socket stats values for the socket
+%%-------------------------------------------------------------------------
+getstat(ip_comm = _SocketType, Socket) ->
+ ?hlrt("ip_comm getstat", [{socket, Socket}]),
+ case inet:getstat(Socket) of
+ {ok, Stats} ->
+ Stats;
+ {error, _} ->
+ []
+ end;
+getstat({ssl, _} = _SocketType, _Socket) ->
+ %% ?hlrt("ssl getstat", [{socket, Socket}]),
+ [].
+
+
%%-------------------------------------------------------------------------
%% send(RequestOrSocketType, Socket, Message) -> ok | {error, Reason}
%% SocketType = ip_comm | {ssl, _}
@@ -261,9 +339,11 @@ close({ssl, _}, Socket) ->
ssl:close(Socket).
%%-------------------------------------------------------------------------
-%% peername(SocketType, Socket) -> ok | {error, Reason}
+%% peername(SocketType, Socket) -> {Port, SockName}
%% SocketType = ip_comm | {ssl, _}
%% Socket = socket()
+%% Port = integer() (-1 if error occured)
+%% PeerName = string()
%%
%% Description: Returns the address and port for the other end of a
%% connection, usning either gen_tcp or ssl.
@@ -298,6 +378,48 @@ peername({ssl, _}, Socket) ->
{-1, "unknown"}
end.
+
+%%-------------------------------------------------------------------------
+%% sockname(SocketType, Socket) -> {Port, SockName}
+%% SocketType = ip_comm | {ssl, _}
+%% Socket = socket()
+%% Port = integer() (-1 if error occured)
+%% SockName = string()
+%%
+%% Description: Returns the address and port for the local (our) end
+%% other end of connection, using either gen_tcp or ssl.
+%%-------------------------------------------------------------------------
+sockname(ip_comm, Socket) ->
+ case inet:sockname(Socket) of
+ {ok,{{A, B, C, D}, Port}} ->
+ SockName = integer_to_list(A)++"."++integer_to_list(B)++"."++
+ integer_to_list(C)++"."++integer_to_list(D),
+ {Port, SockName};
+ {ok,{{A, B, C, D, E, F, G, H}, Port}} ->
+ SockName = http_util:integer_to_hexlist(A) ++ ":"++
+ http_util:integer_to_hexlist(B) ++ ":" ++
+ http_util:integer_to_hexlist(C) ++ ":" ++
+ http_util:integer_to_hexlist(D) ++ ":" ++
+ http_util:integer_to_hexlist(E) ++ ":" ++
+ http_util:integer_to_hexlist(F) ++ ":" ++
+ http_util:integer_to_hexlist(G) ++":"++
+ http_util:integer_to_hexlist(H),
+ {Port, SockName};
+ {error, _} ->
+ {-1, "unknown"}
+ end;
+
+sockname({ssl, _}, Socket) ->
+ case ssl:sockname(Socket) of
+ {ok,{{A, B, C, D}, Port}} ->
+ SockName = integer_to_list(A)++"."++integer_to_list(B)++"."++
+ integer_to_list(C)++"."++integer_to_list(D),
+ {Port, SockName};
+ {error, _} ->
+ {-1, "unknown"}
+ end.
+
+
%%-------------------------------------------------------------------------
%% resolve() -> HostName
%% HostName = string()
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index 4914a16264..96099c49fd 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -164,7 +164,7 @@ end_per_suite(Config) ->
%%--------------------------------------------------------------------
%% Function: init_per_testcase(Case, Config) -> Config
-% Case - atom()
+%% Case - atom()
%% Name of the test case that is about to be run.
%% Config - [tuple()]
%% A list of key/value pairs, holding the test case configuration.
@@ -234,6 +234,7 @@ init_per_testcase(Case, Timeout, Config) ->
http:set_options([{proxy, {{?PROXY, ?PROXY_PORT},
["localhost", ?IPV6_LOCAL_HOST]}}]),
inets:enable_trace(max, io, httpc),
+ %% inets:enable_trace(max, io, all),
%% snmp:set_trace([gen_tcp, inet_tcp, prim_inet]),
NewConfig.
@@ -282,6 +283,7 @@ tickets(suite) ->
otp_8154,
otp_8106,
otp_8056,
+ otp_8352,
otp_8371
].
@@ -977,6 +979,29 @@ http_redirect(Config) when is_list(Config) ->
"~n ~p", [URL302]),
{ok, {{_,200,_}, [_ | _], [_|_]}}
= http:request(get, {URL302, []}, [], []),
+ case http:request(get, {URL302, []}, [], []) of
+ {ok, Reply7} ->
+ case Reply7 of
+ {{_,200,_}, [_ | _], [_|_]} ->
+ tsp("http_redirect -> "
+ "expected reply for request 7"),
+ ok;
+ {StatusLine, Headers, Body} ->
+ tsp("http_redirect -> "
+ "unexpected reply for request 7: "
+ "~n StatusLine: ~p"
+ "~n Headers: ~p"
+ "~n Body: ~p",
+ [StatusLine, Headers, Body]),
+ tsf({unexpected_reply, Reply7})
+ end;
+ Error7 ->
+ tsp("http_redirect -> "
+ "unexpected result for request 7: "
+ "~n Error7: ~p",
+ [Error7]),
+ tsf({unexpected_result, Error7})
+ end,
tsp("http_redirect -> issue request 7: "
"~n ~p", [URL302]),
@@ -1019,6 +1044,7 @@ http_redirect(Config) when is_list(Config) ->
end.
+
%%-------------------------------------------------------------------------
http_redirect_loop(doc) ->
["Test redirect loop detection"];
@@ -1197,26 +1223,42 @@ proxy_emulate_lower_versions(suite) ->
proxy_emulate_lower_versions(Config) when is_list(Config) ->
case ?config(skip, Config) of
undefined ->
- {ok, Body0 = [_| _]} = http:request(get, {?PROXY_URL, []},
- [{version, "HTTP/0.9"}], []),
- inets_test_lib:check_body(Body0),
+ Result09 = pelv_get("HTTP/0.9"),
+ case Result09 of
+ {ok, [_| _] = Body0} ->
+ inets_test_lib:check_body(Body0),
+ ok;
+ _ ->
+ tsf({unexpected_result, "HTTP/0.9", Result09})
+ end,
%% We do not check the version here as many servers
%% do not behave according to the rfc and send
%% 1.1 in its response.
- {ok,{{_, 200, _}, [_ | _], Body1 = [_ | _]}} =
- http:request(get, {?PROXY_URL, []},
- [{version, "HTTP/1.0"}], []),
- inets_test_lib:check_body(Body1),
-
- {ok, {{"HTTP/1.1", 200, _}, [_ | _], Body2 = [_ | _]}} =
- http:request(get, {?PROXY_URL, []},
- [{version, "HTTP/1.1"}], []),
- inets_test_lib:check_body(Body2);
+ Result10 = pelv_get("HTTP/1.0"),
+ case Result10 of
+ {ok,{{_, 200, _}, [_ | _], Body1 = [_ | _]}} ->
+ inets_test_lib:check_body(Body1),
+ ok;
+ _ ->
+ tsf({unexpected_result, "HTTP/1.0", Result10})
+ end,
+
+ Result11 = pelv_get("HTTP/1.1"),
+ case Result11 of
+ {ok, {{"HTTP/1.1", 200, _}, [_ | _], Body2 = [_ | _]}} ->
+ inets_test_lib:check_body(Body2);
+ _ ->
+ tsf({unexpected_result, "HTTP/1.1", Result11})
+ end;
+
Reason ->
{skip, Reason}
end.
+pelv_get(Version) ->
+ http:request(get, {?PROXY_URL, []}, [{version, Version}], []).
+
%%-------------------------------------------------------------------------
proxy_trace(doc) ->
["Perform a TRACE request that goes through a proxy."];
@@ -2275,6 +2317,72 @@ otp_8056(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
+otp_8352(doc) ->
+ "OTP-8352";
+otp_8352(suite) ->
+ [];
+otp_8352(Config) when is_list(Config) ->
+ tsp("otp_8352 -> entry with"
+ "~n Config: ~p", [Config]),
+ case ?config(local_server, Config) of
+ ok ->
+ tsp("local-server running"),
+
+ tsp("initial profile info(1): ~p", [httpc:info()]),
+
+ MaxSessions = 5,
+ MaxKeepAlive = 10,
+ KeepAliveTimeout = timer:minutes(2),
+ ConnOptions = [{max_sessions, MaxSessions},
+ {max_keep_alive_length, MaxKeepAlive},
+ {keep_alive_timeout, KeepAliveTimeout}],
+ http:set_options(ConnOptions),
+
+ Method = get,
+ Port = ?config(local_port, Config),
+ URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html",
+ Request = {URL, []},
+ Timeout = timer:seconds(1),
+ ConnTimeout = Timeout + timer:seconds(1),
+ HttpOptions1 = [{timeout, Timeout}, {connect_timeout, ConnTimeout}],
+ Options1 = [{socket_opts, [{tos, 87},
+ {recbuf, 16#FFFF},
+ {sndbuf, 16#FFFF}]}],
+ case http:request(Method, Request, HttpOptions1, Options1) of
+ {ok, {{_,200,_}, [_ | _], ReplyBody1 = [_ | _]}} ->
+ %% equivaliant to http:request(get, {URL, []}, [], []),
+ inets_test_lib:check_body(ReplyBody1);
+ {ok, UnexpectedReply1} ->
+ tsf({unexpected_reply, UnexpectedReply1});
+ {error, _} = Error1 ->
+ tsf({bad_reply, Error1})
+ end,
+
+ tsp("profile info (2): ~p", [httpc:info()]),
+
+ HttpOptions2 = [],
+ Options2 = [{socket_opts, [{tos, 84},
+ {recbuf, 32#1FFFF},
+ {sndbuf, 32#1FFFF}]}],
+ case http:request(Method, Request, HttpOptions2, Options2) of
+ {ok, {{_,200,_}, [_ | _], ReplyBody2 = [_ | _]}} ->
+ %% equivaliant to http:request(get, {URL, []}, [], []),
+ inets_test_lib:check_body(ReplyBody2);
+ {ok, UnexpectedReply2} ->
+ tsf({unexpected_reply, UnexpectedReply2});
+ {error, _} = Error2 ->
+ tsf({bad_reply, Error2})
+ end,
+ tsp("profile info (3): ~p", [httpc:info()]),
+ ok;
+
+ _ ->
+ {skip, "Failed to start local http-server"}
+ end.
+
+
+%%-------------------------------------------------------------------------
+
otp_8371(doc) ->
["OTP-8371"];
otp_8371(suite) ->
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index 433724f190..746517eed5 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -19,7 +19,7 @@
APPLICATION = inets
INETS_VSN = 5.3
-PRE_VSN =-p12
+PRE_VSN =-p13
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
TICKETS = \
@@ -32,6 +32,7 @@ TICKETS = \
OTP-8327 \
OTP-8349 \
OTP-8351 \
+ OTP-8352 \
OTP-8359 \
OTP-8371
diff --git a/lib/public_key/doc/src/Makefile b/lib/public_key/doc/src/Makefile
index 08d1396cca..298c28a740 100644
--- a/lib/public_key/doc/src/Makefile
+++ b/lib/public_key/doc/src/Makefile
@@ -1,19 +1,19 @@
#
# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2008-2009. All Rights Reserved.
-#
+#
+# Copyright Ericsson AB 2008-2010. All Rights Reserved.
+#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
# compliance with the License. You should have received a copy of the
# Erlang Public License along with this software. If not, it can be
# retrieved online at http://www.erlang.org/.
-#
+#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
# the License for the specific language governing rights and limitations
# under the License.
-#
+#
# %CopyrightEnd%
#
@@ -56,6 +56,9 @@ XML_CHAPTER_FILES = \
BOOK_FILES = book.xml
+XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF3_FILES) \
+ $(XML_PART_FILES) $(XML_CHAPTER_FILES)
+
GIF_FILES = note.gif
# ----------------------------------------------------
diff --git a/lib/public_key/test/Makefile b/lib/public_key/test/Makefile
index 62d7ddd16e..c7215020c7 100644
--- a/lib/public_key/test/Makefile
+++ b/lib/public_key/test/Makefile
@@ -1,19 +1,19 @@
#
# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2008-2009. All Rights Reserved.
-#
+#
+# Copyright Ericsson AB 2008-2010. All Rights Reserved.
+#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
# compliance with the License. You should have received a copy of the
# Erlang Public License along with this software. If not, it can be
# retrieved online at http://www.erlang.org/.
-#
+#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
# the License for the specific language governing rights and limitations
# under the License.
-#
+#
# %CopyrightEnd%
#
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index 122ab1bd7d..8cc36e490d 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
diff --git a/lib/ssl/doc/src/Makefile b/lib/ssl/doc/src/Makefile
index 54d274ef83..fa263d28ab 100644
--- a/lib/ssl/doc/src/Makefile
+++ b/lib/ssl/doc/src/Makefile
@@ -1,19 +1,19 @@
#
# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2009. All Rights Reserved.
-#
+#
+# Copyright Ericsson AB 1999-2010. All Rights Reserved.
+#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
# compliance with the License. You should have received a copy of the
# Erlang Public License along with this software. If not, it can be
# retrieved online at http://www.erlang.org/.
-#
+#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
# the License for the specific language governing rights and limitations
# under the License.
-#
+#
# %CopyrightEnd%
#
@@ -52,6 +52,9 @@ XML_CHAPTER_FILES = \
BOOK_FILES = book.xml
+XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF3_FILES) $(XML_REF6_FILES) \
+ $(XML_PART_FILES) $(XML_CHAPTER_FILES)
+
GIF_FILES = warning.gif
PS_FILES =
diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl
index 929f69c6c6..c59a5c9256 100644
--- a/lib/ssl/test/ssl_packet_SUITE.erl
+++ b/lib/ssl/test/ssl_packet_SUITE.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
@@ -37,7 +37,7 @@
-define(uint24(X), << ?UINT24(X) >> ).
-define(uint32(X), << ?UINT32(X) >> ).
-define(uint64(X), << ?UINT64(X) >> ).
--define(TIMEOUT, 60000).
+-define(TIMEOUT, 120000).
-define(MANY, 1000).
-define(SOME, 50).
diff --git a/lib/stdlib/src/edlin.erl b/lib/stdlib/src/edlin.erl
index 31a653bda0..0e98bbaa06 100644
--- a/lib/stdlib/src/edlin.erl
+++ b/lib/stdlib/src/edlin.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(edlin).
@@ -281,12 +281,32 @@ do_op(_, Bef, Aft, Rs) ->
%% Step over word/non-word characters pushing the stepped over ones on
%% the stack.
-over_word([C|Cs], Stack, N) ->
+
+over_word(Cs, Stack, N) ->
+ L = length([1 || $\' <- Cs]),
+ case L rem 2 of
+ 0 ->
+ over_word1(Cs, Stack, N);
+ 1 ->
+ until_quote(Cs, Stack, N)
+ end.
+
+until_quote([$\'|Cs], Stack, N) ->
+ {Cs, [$\'|Stack], N+1};
+until_quote([C|Cs], Stack, N) ->
+ until_quote(Cs, [C|Stack], N+1).
+
+over_word1([$\'=C|Cs], Stack, N) ->
+ until_quote(Cs, [C|Stack], N+1);
+over_word1(Cs, Stack, N) ->
+ over_word2(Cs, Stack, N).
+
+over_word2([C|Cs], Stack, N) ->
case word_char(C) of
- true -> over_word(Cs, [C|Stack], N+1);
+ true -> over_word2(Cs, [C|Stack], N+1);
false -> {[C|Cs],Stack,N}
end;
-over_word([], Stack, N) when is_integer(N) ->
+over_word2([], Stack, N) when is_integer(N) ->
{[],Stack,N}.
over_non_word([C|Cs], Stack, N) ->
diff --git a/lib/stdlib/src/edlin_expand.erl b/lib/stdlib/src/edlin_expand.erl
index 7ed76a6b09..516c0aa30b 100644
--- a/lib/stdlib/src/edlin_expand.erl
+++ b/lib/stdlib/src/edlin_expand.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2005-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(edlin_expand).
@@ -46,23 +46,38 @@ expand_module_name(Prefix) ->
match(Prefix, code:all_loaded(), ":").
expand_function_name(ModStr, FuncPrefix) ->
- Mod = list_to_atom(ModStr),
- case erlang:module_loaded(Mod) of
- true ->
- L = Mod:module_info(),
- case lists:keyfind(exports, 1, L) of
- {_, Exports} ->
- match(FuncPrefix, Exports, "(");
- _ ->
- {no, [], []}
- end;
- false ->
+ case to_atom(ModStr) of
+ {ok, Mod} ->
+ case erlang:module_loaded(Mod) of
+ true ->
+ L = Mod:module_info(),
+ case lists:keyfind(exports, 1, L) of
+ {_, Exports} ->
+ match(FuncPrefix, Exports, "(");
+ _ ->
+ {no, [], []}
+ end;
+ false ->
+ {no, [], []}
+ end;
+ error ->
{no, [], []}
end.
+%% if it's a quoted atom, atom_to_list/1 will do the wrong thing.
+to_atom(Str) ->
+ case erl_scan:string(Str) of
+ {ok, [{atom,_,A}], _} ->
+ {ok, A};
+ _ ->
+ error
+ end.
+
match(Prefix, Alts, Extra) ->
Len = length(Prefix),
- Matches = [{S, A} || {H, A} <- Alts, prefix(Prefix, S=atom_to_list(H))],
+ Matches = lists:sort(
+ [{S, A} || {H, A} <- Alts,
+ prefix(Prefix, S=hd(io_lib:fwrite("~w",[H])))]),
case longest_common_head([N || {N, _} <- Matches]) of
{partial, []} ->
{no, [], Matches}; % format_matches(Matches)};
diff --git a/lib/stdlib/test/ExpandTestCaps.erl b/lib/stdlib/test/ExpandTestCaps.erl
new file mode 100644
index 0000000000..96c4115354
--- /dev/null
+++ b/lib/stdlib/test/ExpandTestCaps.erl
@@ -0,0 +1,32 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module('ExpandTestCaps').
+
+-export([a_fun_name/1,
+ a_less_fun_name/1,
+ b_comes_after_a/1]).
+
+a_fun_name(X) ->
+ X.
+
+a_less_fun_name(X) ->
+ X.
+
+b_comes_after_a(X) ->
+ X.
diff --git a/lib/stdlib/test/ExpandTestCaps1.erl b/lib/stdlib/test/ExpandTestCaps1.erl
new file mode 100644
index 0000000000..09ee9f81c4
--- /dev/null
+++ b/lib/stdlib/test/ExpandTestCaps1.erl
@@ -0,0 +1,44 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module('ExpandTestCaps1').
+
+-export([a_fun_name/1,
+ a_less_fun_name/1,
+ b_comes_after_a/1,
+ 'Quoted_fun_name'/0,
+ 'Quoted_fun_too'/0,
+ '#weird-fun-name'/0]).
+
+a_fun_name(X) ->
+ X.
+
+a_less_fun_name(X) ->
+ X.
+
+b_comes_after_a(X) ->
+ X.
+
+'Quoted_fun_name'() ->
+ whoopee.
+
+'Quoted_fun_too'() ->
+ too.
+
+'#weird-fun-name'() ->
+ weird.
diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile
index 7a87eef5f3..ac8cbba375 100644
--- a/lib/stdlib/test/Makefile
+++ b/lib/stdlib/test/Makefile
@@ -18,6 +18,7 @@ MODULES= \
digraph_utils_SUITE \
dummy1_h \
dummy_h \
+ edlin_expand_SUITE \
epp_SUITE \
erl_eval_helper \
erl_eval_SUITE \
@@ -29,6 +30,10 @@ MODULES= \
escript_SUITE \
ets_SUITE \
ets_tough_SUITE \
+ expand_test \
+ expand_test1 \
+ ExpandTestCaps \
+ ExpandTestCaps1 \
filelib_SUITE \
file_sorter_SUITE \
filename_SUITE \
diff --git a/lib/stdlib/test/edlin_expand_SUITE.erl b/lib/stdlib/test/edlin_expand_SUITE.erl
new file mode 100644
index 0000000000..613bfd000e
--- /dev/null
+++ b/lib/stdlib/test/edlin_expand_SUITE.erl
@@ -0,0 +1,156 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(edlin_expand_SUITE).
+-export([all/1]).
+
+-export([normal/1, quoted_fun/1, quoted_module/1, quoted_both/1]).
+
+-export([init_per_testcase/2, fin_per_testcase/2]).
+
+-include("test_server.hrl").
+
+% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:minutes(1)).
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog = ?t:timetrap(?default_timeout),
+ [{watchdog, Dog} | Config].
+fin_per_testcase(_Case, Config) ->
+ Dog = ?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+all(doc) ->
+ ["Test cases for edlin_expand."];
+all(suite) ->
+ [normal, quoted_fun, quoted_module, quoted_both].
+
+normal(doc) ->
+ [""];
+normal(suite) ->
+ [];
+normal(Config) when is_list(Config) ->
+ ?line {module,expand_test} = c:l(expand_test),
+ % These tests might fail if another module with the prefix "expand_" happens
+ % to also be loaded.
+ ?line {yes, "test:", []} = edlin_expand:expand(lists:reverse("expand_")),
+ ?line {no, [], []} = edlin_expand:expand(lists:reverse("expandXX_")),
+ ?line {no,[],
+ [{"a_fun_name",1},
+ {"a_less_fun_name",1},
+ {"b_comes_after_a",1},
+ {"module_info",0},
+ {"module_info",1}]} = edlin_expand:expand(lists:reverse("expand_test:")),
+ ?line {yes,[],[{"a_fun_name",1},
+ {"a_less_fun_name",1}]} = edlin_expand:expand(
+ lists:reverse("expand_test:a_")),
+ ok.
+
+quoted_fun(doc) ->
+ ["Normal module name, some function names using quoted atoms"];
+quoted_fun(suite) ->
+ [];
+quoted_fun(Config) when is_list(Config) ->
+ ?line {module,expand_test} = c:l(expand_test),
+ ?line {module,expand_test1} = c:l(expand_test1),
+ %% should be no colon after test this time
+ ?line {yes, "test", []} = edlin_expand:expand(lists:reverse("expand_")),
+ ?line {no, [], []} = edlin_expand:expand(lists:reverse("expandXX_")),
+ ?line {no,[],[{"'#weird-fun-name'",0},
+ {"'Quoted_fun_name'",0},
+ {"'Quoted_fun_too'",0},
+ {"a_fun_name",1},
+ {"a_less_fun_name",1},
+ {"b_comes_after_a",1},
+ {"module_info",0},
+ {"module_info",1}]} = edlin_expand:expand(
+ lists:reverse("expand_test1:")),
+ ?line {yes,"_",[]} = edlin_expand:expand(
+ lists:reverse("expand_test1:a")),
+ ?line {yes,[],[{"a_fun_name",1},
+ {"a_less_fun_name",1}]} = edlin_expand:expand(
+ lists:reverse("expand_test1:a_")),
+ ?line {yes,[],
+ [{"'#weird-fun-name'",0},
+ {"'Quoted_fun_name'",0},
+ {"'Quoted_fun_too'",0}]} = edlin_expand:expand(
+ lists:reverse("expand_test1:'")),
+ ?line {yes,"uoted_fun_",[]} = edlin_expand:expand(
+ lists:reverse("expand_test1:'Q")),
+ ?line {yes,[],
+ [{"'Quoted_fun_name'",0},
+ {"'Quoted_fun_too'",0}]} = edlin_expand:expand(
+ lists:reverse("expand_test1:'Quoted_fun_")),
+ ?line {yes,"weird-fun-name'(",[]} = edlin_expand:expand(
+ lists:reverse("expand_test1:'#")),
+ ok.
+
+quoted_module(doc) ->
+ [""];
+quoted_module(suite) ->
+ [];
+quoted_module(Config) when is_list(Config) ->
+ ?line {module,'ExpandTestCaps'} = c:l('ExpandTestCaps'),
+ ?line {yes, "Caps':", []} = edlin_expand:expand(lists:reverse("'ExpandTest")),
+ ?line {no,[],
+ [{"a_fun_name",1},
+ {"a_less_fun_name",1},
+ {"b_comes_after_a",1},
+ {"module_info",0},
+ {"module_info",1}]} = edlin_expand:expand(lists:reverse("'ExpandTestCaps':")),
+ ?line {yes,[],[{"a_fun_name",1},
+ {"a_less_fun_name",1}]} = edlin_expand:expand(
+ lists:reverse("'ExpandTestCaps':a_")),
+ ok.
+
+quoted_both(suite) ->
+ [];
+quoted_both(Config) when is_list(Config) ->
+ ?line {module,'ExpandTestCaps'} = c:l('ExpandTestCaps'),
+ ?line {module,'ExpandTestCaps1'} = c:l('ExpandTestCaps1'),
+ %% should be no colon (or quote) after test this time
+ ?line {yes, "Caps", []} = edlin_expand:expand(lists:reverse("'ExpandTest")),
+ ?line {no,[],[{"'#weird-fun-name'",0},
+ {"'Quoted_fun_name'",0},
+ {"'Quoted_fun_too'",0},
+ {"a_fun_name",1},
+ {"a_less_fun_name",1},
+ {"b_comes_after_a",1},
+ {"module_info",0},
+ {"module_info",1}]} = edlin_expand:expand(
+ lists:reverse("'ExpandTestCaps1':")),
+ ?line {yes,"_",[]} = edlin_expand:expand(
+ lists:reverse("'ExpandTestCaps1':a")),
+ ?line {yes,[],[{"a_fun_name",1},
+ {"a_less_fun_name",1}]} = edlin_expand:expand(
+ lists:reverse("'ExpandTestCaps1':a_")),
+ ?line {yes,[],
+ [{"'#weird-fun-name'",0},
+ {"'Quoted_fun_name'",0},
+ {"'Quoted_fun_too'",0}]} = edlin_expand:expand(
+ lists:reverse("'ExpandTestCaps1':'")),
+ ?line {yes,"uoted_fun_",[]} = edlin_expand:expand(
+ lists:reverse("'ExpandTestCaps1':'Q")),
+ ?line {yes,[],
+ [{"'Quoted_fun_name'",0},
+ {"'Quoted_fun_too'",0}]} = edlin_expand:expand(
+ lists:reverse("'ExpandTestCaps1':'Quoted_fun_")),
+ ?line {yes,"weird-fun-name'(",[]} = edlin_expand:expand(
+ lists:reverse("'ExpandTestCaps1':'#")),
+ ok.
diff --git a/lib/stdlib/test/expand_test.erl b/lib/stdlib/test/expand_test.erl
new file mode 100644
index 0000000000..63e4bc3aa0
--- /dev/null
+++ b/lib/stdlib/test/expand_test.erl
@@ -0,0 +1,32 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(expand_test).
+
+-export([a_fun_name/1,
+ a_less_fun_name/1,
+ b_comes_after_a/1]).
+
+a_fun_name(X) ->
+ X.
+
+a_less_fun_name(X) ->
+ X.
+
+b_comes_after_a(X) ->
+ X.
diff --git a/lib/stdlib/test/expand_test1.erl b/lib/stdlib/test/expand_test1.erl
new file mode 100644
index 0000000000..11b6fec0f3
--- /dev/null
+++ b/lib/stdlib/test/expand_test1.erl
@@ -0,0 +1,44 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(expand_test1).
+
+-export([a_fun_name/1,
+ a_less_fun_name/1,
+ b_comes_after_a/1,
+ 'Quoted_fun_name'/0,
+ 'Quoted_fun_too'/0,
+ '#weird-fun-name'/0]).
+
+a_fun_name(X) ->
+ X.
+
+a_less_fun_name(X) ->
+ X.
+
+b_comes_after_a(X) ->
+ X.
+
+'Quoted_fun_name'() ->
+ whoopee.
+
+'Quoted_fun_too'() ->
+ too.
+
+'#weird-fun-name'() ->
+ weird.
diff --git a/lib/wx/test/wx_class_SUITE.erl b/lib/wx/test/wx_class_SUITE.erl
index cedbd1ef19..ddb491be6c 100644
--- a/lib/wx/test/wx_class_SUITE.erl
+++ b/lib/wx/test/wx_class_SUITE.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%%-------------------------------------------------------------------
%%% File : wx_class_SUITE.erl
@@ -113,12 +113,14 @@ treeCtrl(Config) ->
Frame = wxFrame:new(Wx, ?wxID_ANY, "Frame"),
Panel = wxPanel:new(Frame, []),
Tree = ?mt(wxTreeCtrl,wxTreeCtrl:new(Panel, [{style , ?wxTR_HAS_BUTTONS}])),
- Root = ?mt(wxTreeItemId, wxTreeCtrl:addRoot(Tree, "Root", [])),
- Item1 = ?mt(wxTreeItemId, wxTreeCtrl:appendItem(Tree, Root, "Item1", [])),
- ?m(ok, wxTreeCtrl:setItemData(Tree, Item1, {data, item1})),
- Item2 = ?mt(wxTreeItemId, wxTreeCtrl:appendItem(Tree, Root, "Item2", [])),
- ?m(ok, wxTreeCtrl:setItemData(Tree, Item2, {data, item2})),
- Item3 = ?mt(wxTreeItemId, wxTreeCtrl:appendItem(Tree, Root, "Item3", [])),
+ Root = wxTreeCtrl:addRoot(Tree, "Root", []),
+ ?m(true, is_integer(Root)),
+ Item1 = wxTreeCtrl:appendItem(Tree, Root, "Item1", []),
+ ?m(true, is_integer(Item1)),
+ ?m(ok, wxTreeCtrl:setItemData(Tree, Item1, {data, item1})),
+ Item2 = wxTreeCtrl:appendItem(Tree, Root, "Item2", []),
+ ?m(ok, wxTreeCtrl:setItemData(Tree, Item2, {data, item2})),
+ Item3 = wxTreeCtrl:appendItem(Tree, Root, "Item3", []),
?m(ok, wxTreeCtrl:setItemData(Tree, Item3, {data, item3})),
Sizer = wxBoxSizer:new(?wxVERTICAL),
@@ -373,7 +375,7 @@ radioBox(Config) ->
io:format("TrSortRadioBox ~p ~n", [TrSortRadioBox]),
%% If I uncomment any of these lines, it will crash
- ?m(_, catch wxControlWithItems:setClientData(TrSortRadioBox, 0, timestamp)),
+ io:format("~p~n", [catch wxControlWithItems:setClientData(TrSortRadioBox, 0, timestamp)]),
%?m(_, wxListBox:append(TrSortRadioBox, "Session Id", session_id)),
%?m(_, wxListBox:insert(TrSortRadioBox, "Session Id", 0, session_id)),
diff --git a/lib/wx/test/wx_xtra_SUITE.erl b/lib/wx/test/wx_xtra_SUITE.erl
index 6f21c60d14..d5888bbf94 100644
--- a/lib/wx/test/wx_xtra_SUITE.erl
+++ b/lib/wx/test/wx_xtra_SUITE.erl
@@ -69,10 +69,11 @@ destroy_app_test(N) when N > 0 ->
Wx = ?mr(wx_ref, wx:new()),
Frame = wxFrame:new(Wx, 1, "Destroy"),
?m(ok, wxFrame:destroy(Frame)),
- wx:destroy(),
receive
Msg -> Msg
- after 150 -> destroy_app_test(N-1)
+ after 150 ->
+ wx:destroy(),
+ destroy_app_test(N-1)
end;
destroy_app_test(_) ->
receive
@@ -184,7 +185,7 @@ menu_item_debug(Config) ->
Frame = wxFrame:new(Wx, -1, "Button Fix"),
wxFrame:connect(Frame, close_window),
- FramePanel = wxPanel:new(Frame),
+ wxPanel:new(Frame),
create_menus(Frame),
wxWindow:show(Frame),
wx_test_lib:wx_destroy(Frame,Config).
diff --git a/lib/wx/test/wxt.erl b/lib/wx/test/wxt.erl
index a346a6bdb8..1f5b1cc3b1 100644
--- a/lib/wx/test/wxt.erl
+++ b/lib/wx/test/wxt.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%%-------------------------------------------------------------------
%%% File : wxt.erl
@@ -58,16 +58,16 @@ user(Mod,Tc) when is_atom(Tc) ->
%% Resolves the name of test suites and test cases
%% according to the alias definitions. Single atoms
%% are assumed to be the name of a test suite.
-resolve(Suite0) when atom(Suite0) ->
+resolve(Suite0) when is_atom(Suite0) ->
case alias(Suite0) of
- Suite when atom(Suite) ->
+ Suite when is_atom(Suite) ->
{Suite, all};
{Suite, Case} ->
{Suite, Case}
end;
-resolve({Suite0, Case}) when atom(Suite0), atom(Case) ->
+resolve({Suite0, Case}) when is_atom(Suite0), is_atom(Case) ->
case alias(Suite0) of
- Suite when atom(Suite) ->
+ Suite when is_atom(Suite) ->
{Suite, Case};
{Suite, Case2} ->
{Suite, Case2}
diff --git a/lib/xmerl/doc/src/Makefile b/lib/xmerl/doc/src/Makefile
index e26e77eb96..100a2feb0a 100644
--- a/lib/xmerl/doc/src/Makefile
+++ b/lib/xmerl/doc/src/Makefile
@@ -1,19 +1,19 @@
#
# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2004-2009. All Rights Reserved.
-#
+#
+# Copyright Ericsson AB 2004-2010. All Rights Reserved.
+#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
# compliance with the License. You should have received a copy of the
# Erlang Public License along with this software. If not, it can be
# retrieved online at http://www.erlang.org/.
-#
+#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
# the License for the specific language governing rights and limitations
# under the License.
-#
+#
# %CopyrightEnd%
#
include $(ERL_TOP)/make/target.mk
@@ -126,7 +126,7 @@ pdf: $(TOP_PDF_FILE)
html: gifs $(HTML_REF_MAN_FILE)
$(XMERL_XML_FILES):
- docb_gen $(XMERL_DIR)/$(@:%.xml=%.erl)
+ escript $(DOCGEN)/priv/bin/xml_from_edoc.escript $(XMERL_DIR)/$(@:%.xml=%.erl)
man: $(MAN3_FILES) $(MAN6_FILES)